@@ -14,12 +14,52 @@ use Throwable;
|
||||
|
||||
class ImportDocumentBatch extends Command
|
||||
{
|
||||
protected $signature = 'documents:import-batch {manifest : JSON manifest inside storage/app/private/document-import-staging} {--apply : Register private drafts and queue malware scans} {--actor= : Existing user ID responsible for an applied import}';
|
||||
protected $signature = 'documents:import-batch {manifest : JSON manifest inside storage/app/private/document-import-staging} {--apply : Register private drafts and queue malware scans} {--actor= : Existing user ID responsible for an applied import} {--pilot-agronegocio : Restrict to the approved two-original pilot} {--sectors-lot20 : Restrict to the named 20-resource sector batch} {--sectors-trio : Restrict to the three named sector articles and reuse the existing image} {--backup-proof= : Fresh verified destination backup receipt for active pilot apply}';
|
||||
|
||||
protected $description = 'Preview or idempotently import a document batch into the existing private library';
|
||||
|
||||
private const MAX_BYTES = 10485760;
|
||||
|
||||
private const PILOT_MANIFEST_SHA256 = '0b720b0a6f7539de1d3eca9e32f89a6b9038848dc0b97ad21ace605154d9ddd8';
|
||||
|
||||
private const PILOT_HASHES = [
|
||||
'legacy-tempo-post-171985-20260420' => '0929184a6d4645b9046512675394ad4f60575273f6dab0955f71cc7474a6a4e2',
|
||||
'legacy-tempo-agronegocio-image-5e3840705cf98226' => '5e3840705cf98226d1f189cf665aaa98cb05da96c645159a1332a1d429d642eb',
|
||||
];
|
||||
|
||||
private const SECTORS_MANIFEST_SHA256 = 'ade9a00c031534f4341e8f6bd5e425b502ee03efc9fcfaec4f463a10fb28201b';
|
||||
|
||||
private const SECTORS_HASHES = [
|
||||
'legacy-tempo-post-171981-20260430' => '26a70f16cd511c579f08633655ff312db05122f81e44852dd4b163fa6eef85f1',
|
||||
'legacy-tempo-post-172679-20260430' => '2003755b7dac53b43f4608e707321db6d2f29878926a0e74f4cf27627b70a9cb',
|
||||
'legacy-tempo-post-172674-20260430' => '3ae780f082a8fa7c767635cce98563f5bc027c9656c9f41f8788843a17fa1f54',
|
||||
'legacy-tempo-post-171990-20260616' => '8cab862be245382dd4c1fd5fcb423c47aed7be3a22e0a7f8d5521510cc36bc72',
|
||||
'legacy-tempo-post-172263-20260414' => '538495cd5b31047ac1c5993fdaf298ec1303330368248b251c87d201d31ff211',
|
||||
'legacy-tempo-post-172256-20260414' => 'dcc29cbd36cf57e0a5c88dd312c84ee03c32a3d18ae9216d3715dc7b5a6960bf',
|
||||
'legacy-tempo-post-172261-20260414' => '88177fccd78d8516dba670c6f71272af062cc981d52d97adefe5bf77c613b16a',
|
||||
'legacy-tempo-post-172258-20260417' => '48314a576dea2f2dadf47d8f1eadd7ab58030606b02eebe17aa9bd6badffb7e9',
|
||||
'legacy-tempo-post-172253-20260414' => 'e90e39e49ba65bbbcbbc303c6eca456e445238daf9acc935ab03690819281678',
|
||||
'legacy-tempo-post-172240-20260414' => '8c5e91c937032680883793a12844f1128f7ac99e97c63b68c23d1396e009ba9d',
|
||||
'legacy-tempo-post-172237-20260417' => 'a62a43e31da32795a7286f4c152a93d5dc829233e72023b00ea61fd8e2fcb58c',
|
||||
'legacy-tempo-post-172233-20260417' => '345dfd72d8ebf459eae8eb025d699afddbae751df55ffa8d053568cd08096c97',
|
||||
'legacy-tempo-post-172230-20260414' => '4f4570f7bbd5599cb925ed996c1734a23582362fe485736931a53b9266565d4e',
|
||||
'legacy-tempo-post-172223-20260414' => '514a9d88c097d234038fa6341f5a5b01e8938cb6a9535a807145c84c37010a4d',
|
||||
'legacy-tempo-post-172219-20260414' => '0d468ae0de9a76d2b140bc8cb5c555f29626fb6422287c917762bec3e615a70c',
|
||||
'legacy-tempo-post-171992-20260430' => '05eb492dd6cfca6a7f305b633658a16723c315168f4b2c75103f22d1fac84032',
|
||||
'legacy-tempo-image-0a2c50d91dad3a60' => '0a2c50d91dad3a6007544634540e0f61b11d3506682a5a19066bae03cdcba490',
|
||||
'legacy-tempo-image-28f41f12e10ab345' => '28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa',
|
||||
'legacy-tempo-image-fe9a2e382e385b35' => 'fe9a2e382e385b35f6e61ae320e199a979678677fd327fb7d4b07d8ce0111c11',
|
||||
'legacy-tempo-image-8e58544e49e719f9' => '8e58544e49e719f9c865c91e07ef1030155a9e3d59260e6dc93e9c9e25674e39',
|
||||
];
|
||||
|
||||
private const TRIO_MANIFEST_SHA256 = '9210ad7e1bea557349c440fd8295b321a10c2ddd34cc170f3dad18b5517751f8';
|
||||
private const TRIO_REUSED_IMAGE_SHA256 = '28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa';
|
||||
private const TRIO_HASHES = [
|
||||
'legacy-tempo-post-173209-20260623' => '926f5e4096737c936c9d5002ebdc64be9e63b0c0822023d17ce618111a65c941',
|
||||
'legacy-tempo-post-173218-20260616' => '43612c358c7573475cea24ef4825c5b7c7925306fa5861051220eed3f4e333b5',
|
||||
'legacy-tempo-post-173213-20260616' => '0ba605ae43dec7f685610f828df884bc82cb4da67131fc9783b5cdbe4cc6d9f0',
|
||||
];
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$staging = storage_path('app/private/document-import-staging');
|
||||
@@ -43,7 +83,8 @@ class ImportDocumentBatch extends Command
|
||||
}
|
||||
|
||||
try {
|
||||
$manifest = json_decode((string) file_get_contents($manifestPath), true, 512, JSON_THROW_ON_ERROR);
|
||||
$manifestBytes = (string) file_get_contents($manifestPath);
|
||||
$manifest = json_decode($manifestBytes, true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (Throwable) {
|
||||
$this->error('Manifest is not valid JSON.');
|
||||
|
||||
@@ -57,7 +98,24 @@ class ImportDocumentBatch extends Command
|
||||
|
||||
$apply = (bool) $this->option('apply');
|
||||
$actorId = $this->option('actor');
|
||||
if ($apply) {
|
||||
$pilot = (bool) $this->option('pilot-agronegocio');
|
||||
$sectors = (bool) $this->option('sectors-lot20');
|
||||
$trio = (bool) $this->option('sectors-trio');
|
||||
if ((int) $pilot + (int) $sectors + (int) $trio > 1) {
|
||||
$this->error('Select exactly one named batch; agribusiness scope is unchanged.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
if ($pilot || $sectors || $trio) {
|
||||
try {
|
||||
$this->validatePilot($manifestPath, $manifestBytes, $manifest, $stagingReal, $apply, $actorId, $sectors, $trio);
|
||||
} catch (Throwable $exception) {
|
||||
$this->error('Pilot refused before import: '.$exception->getMessage());
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
if ($apply && ! $pilot && ! $sectors && ! $trio) {
|
||||
// CLI attribution is not an authenticated active installation. Rehearsals stay isolated.
|
||||
$target = DB::selectOne('SELECT current_database() AS database,inet_server_port() AS port');
|
||||
if (! app()->environment('testing') || ! str_ends_with($target->database, '_test') || (int) $target->port !== 55441
|
||||
@@ -87,6 +145,9 @@ class ImportDocumentBatch extends Command
|
||||
$label = is_array($record) ? (string) ($record['external_id'] ?? '#'.($index + 1)) : '#'.($index + 1);
|
||||
try {
|
||||
$validated = $this->validateRecord($record, $stagingReal);
|
||||
if (($pilot || $sectors || $trio) && ! hash_equals(($trio ? self::TRIO_HASHES : ($sectors ? self::SECTORS_HASHES : self::PILOT_HASHES))[$validated['external_id']] ?? '', $validated['sha256'])) {
|
||||
throw new RuntimeException('Approved pilot bytes changed after preview validation.');
|
||||
}
|
||||
$hash = $validated['sha256'];
|
||||
if (isset($seenHashes[$hash])) {
|
||||
$this->line($label.' | duplicate bytes within batch; references item '.$seenHashes[$hash]);
|
||||
@@ -215,6 +276,80 @@ class ImportDocumentBatch extends Command
|
||||
return $failures > 0 ? self::FAILURE : self::SUCCESS;
|
||||
}
|
||||
|
||||
/** The extra CLI path is a named, byte-bound pilot; it is not a general active import gate. */
|
||||
private function validatePilot(string $manifestPath, string $manifestBytes, array $manifest, string $staging, bool $apply, mixed $actorId, bool $sectors = false, bool $trio = false): void
|
||||
{
|
||||
$allowed = $trio ? self::TRIO_HASHES : ($sectors ? self::SECTORS_HASHES : self::PILOT_HASHES);
|
||||
$manifestName = $trio ? 'legacy-trio-20261015/manifest.json' : ($sectors ? 'legacy-setores-lote20-20261015/manifest.json' : 'legacy-agronegocio/manifest.json');
|
||||
$manifestHash = $trio ? self::TRIO_MANIFEST_SHA256 : ($sectors ? self::SECTORS_MANIFEST_SHA256 : self::PILOT_MANIFEST_SHA256);
|
||||
if ($manifestPath !== realpath($staging.'/'.$manifestName)
|
||||
|| ! hash_equals($manifestHash, hash('sha256', $manifestBytes))
|
||||
|| count($manifest['documents']) !== count($allowed)) {
|
||||
throw new RuntimeException('Only the exact selected manifest and its fixed resource list are allowed.');
|
||||
}
|
||||
$target = DB::selectOne('SELECT current_database() AS database,inet_server_port() AS port');
|
||||
$host = config('database.connections.pgsql.host');
|
||||
$qa = app()->environment('testing') && str_ends_with($target->database, '_test') && (int) $target->port === 55441;
|
||||
$active = ! app()->environment('testing') && $target->database === 'investemoz' && (int) $target->port === 5432;
|
||||
if ((! $qa && ! $active) || ! in_array($host, ['127.0.0.1', 'localhost'], true) || config('database.connections.pgsql.url')) {
|
||||
throw new RuntimeException('Pilot target identity is not permitted.');
|
||||
}
|
||||
if ($apply || $actorId !== null) {
|
||||
$actor = is_string($actorId) && preg_match('/^[1-9][0-9]*$/D', $actorId) ? User::find((int) $actorId) : null;
|
||||
if (! $actor || ! $actor->can('manage-portal')) {
|
||||
throw new RuntimeException('A real existing account with effective manage-portal authorization is required.');
|
||||
}
|
||||
}
|
||||
if ($active && $apply) {
|
||||
$this->validatePilotBackup($this->option('backup-proof'));
|
||||
}
|
||||
if ($trio) {
|
||||
$images = DB::table('documents as d')->join('portal_resources as r', 'r.document_id', '=', 'd.id')
|
||||
->where('d.external_id', 'legacy-tempo-image-28f41f12e10ab345')->where('d.sha256', self::TRIO_REUSED_IMAGE_SHA256)
|
||||
->whereNull('d.deleted_at')->where('d.status', 'active')->where('d.data_classification', 'public')
|
||||
->where('d.rights_status', 'authorized')->where('r.rights_status', 'authorized')->where('r.published', true)
|
||||
->where('d.malware_scan_status', 'clean')->whereColumn('d.sha256', 'd.malware_scanned_sha256')->get(['d.storage_key']);
|
||||
if ($images->count() !== 1 || ! Storage::disk('local')->exists($images[0]->storage_key)
|
||||
|| ! hash_equals(self::TRIO_REUSED_IMAGE_SHA256, hash_file('sha256', Storage::disk('local')->path($images[0]->storage_key)))) {
|
||||
throw new RuntimeException('The shared image must already exist once, published, authorized and clean with the exact original bytes; no image is imported.');
|
||||
}
|
||||
}
|
||||
foreach ($manifest['documents'] as $record) {
|
||||
$entry = $this->validateRecord($record, $staging);
|
||||
if (! hash_equals($allowed[$entry['external_id']] ?? '', $entry['sha256'])) {
|
||||
throw new RuntimeException('Article or image differs from the approved SHA-256.');
|
||||
}
|
||||
$existing = DB::table('documents')->where('sha256', $entry['sha256'])->whereNull('deleted_at')->first();
|
||||
if ($existing && ($existing->external_id !== $entry['external_id']
|
||||
|| ! DB::table('portal_resources')->where('document_id', $existing->id)->exists())) {
|
||||
throw new RuntimeException('Matching bytes have another identity or no library resource; reconcile explicitly.');
|
||||
}
|
||||
if (DB::table('documents')->where('external_id', $entry['external_id'])->whereNull('deleted_at')
|
||||
->where('sha256', '!=', $entry['sha256'])->exists()
|
||||
|| (! $existing && DB::table('portal_resources')->where('document_identity_key', $this->identity($entry))->exists())) {
|
||||
throw new RuntimeException('Existing identity/version conflicts with this pilot; no overwrite or partial preflight import.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function validatePilotBackup(mixed $path): void
|
||||
{
|
||||
if (! is_string($path) || ! is_file($path)) {
|
||||
throw new RuntimeException('Active pilot apply requires a fresh verified backup/restoration receipt.');
|
||||
}
|
||||
$proof = json_decode((string) file_get_contents($path), true, 512, JSON_THROW_ON_ERROR);
|
||||
$verified = strtotime($proof['verified_at'] ?? '');
|
||||
if (! ($proof['restore_verified'] ?? false) || ! ($proof['files_verified'] ?? false)
|
||||
|| ($proof['target']['database'] ?? '') !== 'investemoz' || (int) ($proof['target']['port'] ?? 0) !== 5432
|
||||
|| ! str_ends_with($proof['restore_target']['database'] ?? '', '_test') || (int) ($proof['restore_target']['port'] ?? 0) !== 55441
|
||||
|| $verified === false || $verified > time() || $verified < time() - 86400
|
||||
|| ! is_file($proof['dump_path'] ?? '') || ! is_file($proof['files_path'] ?? '')
|
||||
|| ! hash_equals($proof['sha256'] ?? '', hash_file('sha256', $proof['dump_path']))
|
||||
|| ! hash_equals($proof['files_sha256'] ?? '', hash_file('sha256', $proof['files_path']))) {
|
||||
throw new RuntimeException('Backup/restoration identity, freshness or integrity does not match the active pilot.');
|
||||
}
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
private function validateRecord(mixed $record, string $stagingRoot): array
|
||||
{
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\ExistingBusinessClassification;
|
||||
use App\Services\Mne\BusinessRepository;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
class ExistingBusinessClassificationController extends Controller
|
||||
{
|
||||
public function show(Request $request, string $id, ExistingBusinessClassification $service): Response|JsonResponse
|
||||
{
|
||||
$props = ['supplement' => $service->privateView($request->user(), app(BusinessRepository::class)->find($id))];
|
||||
|
||||
return $request->expectsJson() ? response()->json($props) : Inertia::render('investment/business-classification', $props);
|
||||
}
|
||||
|
||||
public function act(Request $request, string $id, ExistingBusinessClassification $service): JsonResponse
|
||||
{
|
||||
$business = $service->act($request->user(), $id, $request->all());
|
||||
|
||||
return response()->json(['supplement' => $service->privateView($request->user(), $business)]);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ class InvestmentDiscoveryController extends Controller
|
||||
if (! empty($filters['geo_location_id'])) {
|
||||
app(InvestmentGeography::class)->constrainDossiersToTerritories($query, app(InvestmentGeography::class)->descendants($filters['geo_location_id']));
|
||||
}
|
||||
foreach (['zee_id', 'zfi_id', 'park_id', 'education', 'facets', 'sector', 'province', 'district', 'min_amount', 'max_amount', 'currency', 'before', 'maturity_level'] as $field) {
|
||||
foreach (['association_type', 'association_target', 'association_state', 'association_purpose', 'authority_id', 'chain_id', 'subsector_id', 'category', 'publication_state', 'zee_id', 'zfi_id', 'park_id', 'education', 'facets', 'sector', 'province', 'district', 'min_amount', 'max_amount', 'currency', 'before', 'maturity_level'] as $field) {
|
||||
if (isset($filters[$field]) && $filters[$field] !== '' && $filters[$field] !== false && $filters[$field] !== []) {
|
||||
return $query->whereRaw('false')->get();
|
||||
}
|
||||
@@ -131,7 +131,7 @@ class InvestmentDiscoveryController extends Controller
|
||||
{
|
||||
$filters = $catalogue->filters($request);
|
||||
$context = $this->territorial($filters)->map(fn ($d) => ['id' => 'dossier:'.$d->id, 'title' => $d->title, 'kind' => $d->cluster_id ? 'Cluster' : ($d->corridor_id ? 'Corredor' : 'Projeto âncora'), 'url' => '/carteira/'.$d->id]);
|
||||
$opportunityOnlyFilters = array_filter(Arr::only($filters, ['education', 'sector', 'facets', 'project_id', 'cluster_id', 'corridor_id', 'min_amount', 'max_amount', 'currency', 'before', 'maturity_level']), fn ($value) => $value !== null && $value !== '' && $value !== false && $value !== []);
|
||||
$opportunityOnlyFilters = array_filter(Arr::only($filters, ['association_type', 'association_target', 'association_state', 'association_purpose', 'authority_id', 'chain_id', 'subsector_id', 'category', 'publication_state', 'education', 'sector', 'facets', 'project_id', 'cluster_id', 'corridor_id', 'min_amount', 'max_amount', 'currency', 'before', 'maturity_level']), fn ($value) => $value !== null && $value !== '' && $value !== false && $value !== []);
|
||||
if ($opportunityOnlyFilters === [] && ! in_array($filters['dimension'] ?? null, ['cluster', 'corridor'], true)) {
|
||||
$zoneFilters = $filters;
|
||||
if (in_array($filters['dimension'] ?? null, ['zee', 'zfi'], true)) {
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\FintechInvestment;
|
||||
use App\Services\InvestorPath;
|
||||
use App\Services\LegacyContent;
|
||||
use App\Services\SectorInvestment;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -21,21 +23,45 @@ class InvestorPathController extends Controller
|
||||
return $request->expectsJson() ? response()->json($data) : Inertia::render('investor-path/index', $data);
|
||||
}
|
||||
|
||||
public function sectorStart(Request $request, string $sectorSlug, InvestorPath $path): JsonResponse|Response
|
||||
{
|
||||
abort_unless($path->available(), 404);
|
||||
$data = ['contexts' => $path->contexts($request->user()), 'sectorSource' => app(SectorInvestment::class)->context($sectorSlug)];
|
||||
|
||||
return $request->expectsJson() ? response()->json($data) : Inertia::render('investor-path/index', $data);
|
||||
}
|
||||
|
||||
public function sectorAttach(Request $request, string $id): JsonResponse|RedirectResponse
|
||||
{
|
||||
app(SectorInvestment::class)->attach($request->user(), $id, $request->all());
|
||||
|
||||
return $request->expectsJson() ? response()->json(['ok' => true]) : redirect('/investimentos/'.$id)->with('success', 'Setor associado ao mesmo dossier.');
|
||||
}
|
||||
|
||||
public function create(Request $request, InvestorPath $path): JsonResponse|RedirectResponse
|
||||
{
|
||||
$sector = $request->validate(['sector_slug' => 'nullable|string|max:150'])['sector_slug'] ?? null;
|
||||
if ($sector !== null) {
|
||||
app(SectorInvestment::class)->context($sector);
|
||||
}
|
||||
$source = $request->input('content_resource_id');
|
||||
if ($source !== null) {
|
||||
$resourceId = filter_var($source, FILTER_VALIDATE_INT);
|
||||
abort_unless(is_int($resourceId) && $resourceId !== 0, 422);
|
||||
app(LegacyContent::class)->articleForResource($resourceId);
|
||||
}
|
||||
$id = DB::transaction(function () use ($path, $request, $source): string {
|
||||
$id = DB::transaction(function () use ($path, $request, $source, $sector): string {
|
||||
$id = $path->create($request->user(), $request->all());
|
||||
if ($source !== null) {
|
||||
$case = $path->view($request->user(), $id)['case'];
|
||||
app(LegacyContent::class)->attach($request->user(), $id, ['version' => $case['version'], 'resource_id' => (int) $source]);
|
||||
}
|
||||
|
||||
if ($sector !== null) {
|
||||
$case = $path->view($request->user(), $id)['case'];
|
||||
app(SectorInvestment::class)->attach($request->user(), $id, ['version' => $case['version'], 'sector_slug' => $sector]);
|
||||
}
|
||||
|
||||
return $id;
|
||||
});
|
||||
|
||||
@@ -80,6 +106,14 @@ class InvestorPathController extends Controller
|
||||
return $request->expectsJson() ? response()->json(['id' => $task], 201) : back()->with('success', 'Tarefa assumida no acompanhamento interno.');
|
||||
}
|
||||
|
||||
public function fintech(Request $request, string $id, InvestorPath $path): JsonResponse|RedirectResponse
|
||||
{
|
||||
abort_unless($path->available(), 404);
|
||||
app(FintechInvestment::class)->save($request->user(), $id, $request->all());
|
||||
|
||||
return $this->saved($request, 'Caracterização Fintech guardada no mesmo dossier; pendências e histórico preservados.');
|
||||
}
|
||||
|
||||
private function saved(Request $request, string $message): JsonResponse|RedirectResponse
|
||||
{
|
||||
return $request->expectsJson() ? response()->json(['message' => $message]) : back()->with('success', $message);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Opportunity;
|
||||
use App\Services\OpportunityClassification;
|
||||
use App\Services\OpportunityManagement;
|
||||
use App\Services\PortalProfileAccess;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class OpportunityClassificationController extends Controller
|
||||
{
|
||||
public function index(Request $request, int $id, OpportunityClassification $service): JsonResponse
|
||||
{
|
||||
$record = Opportunity::findOrFail($id);
|
||||
app(PortalProfileAccess::class)->authorize($request->user(), 'view', $record);
|
||||
|
||||
return response()->json(['version' => $service::VERSION, 'etag' => app(OpportunityManagement::class)->etag($record), 'rows' => $service->listing($request->user(), $record), 'duplicates' => $service->duplicates($request->user(), $record)])->header('Cache-Control', 'private, no-store');
|
||||
}
|
||||
|
||||
public function review(Request $request, int $id, OpportunityClassification $service): JsonResponse
|
||||
{
|
||||
$record = $service->review($request->user(), Opportunity::findOrFail($id), $request->all());
|
||||
|
||||
return response()->json(['etag' => app(OpportunityManagement::class)->etag($record), 'rows' => $service->listing($request->user(), $record)])->header('Cache-Control', 'private, no-store');
|
||||
}
|
||||
}
|
||||
@@ -136,6 +136,11 @@ class OpportunityManagementController extends Controller
|
||||
'profileMode' => $record ? $record->owner_user_id !== null : str_starts_with($request->path(), 'minhas-oportunidades'),
|
||||
'profileActions' => $record && $record->owner_user_id !== null ? app(OpportunityProfileWorkflow::class)->actions($request->user(), $record) : [], 'profileContext' => $record?->workflow_context, 'profileOrganization' => $record?->organization_id]);
|
||||
$values = $record ? $service->values($record) : [];
|
||||
if (! $record && $request->filled('sector_id')) {
|
||||
$selection = $request->validate(['sector_id' => ['required', 'integer', Rule::exists('sectors', 'id')->where('is_active', true)->whereNull('deleted_at')]]);
|
||||
$values['sector_id'] = (int) $selection['sector_id'];
|
||||
$values['canonical']['sector_id'] = (int) $selection['sector_id'];
|
||||
}
|
||||
Inertia::share('publicationPreview', app(OpportunityCanonicalContract::class)->publicProjection($values['canonical'] ?? []));
|
||||
$classification = $id ? DB::table('audit_events')->where('source_system', 'opportunity-origin-review')->where('after_data->opportunity_id', $id)->orderByDesc('occurred_at')->orderByDesc('id')->value('after_data') : null;
|
||||
|
||||
|
||||
@@ -123,12 +123,21 @@ class PortalProfileController extends Controller
|
||||
return app(OpportunityManagementController::class)->index($request, app(OpportunityManagement::class));
|
||||
}
|
||||
|
||||
public function edit(Request $request, PortalProfileAccess $access, ?int $id = null): Response
|
||||
public function edit(Request $request, PortalProfileAccess $access, ?int $id = null): Response|\Symfony\Component\HttpFoundation\Response
|
||||
{
|
||||
if ($id) {
|
||||
$access->authorize($request->user(), str_ends_with($request->path(), '/view') ? 'view' : 'edit', Opportunity::withTrashed()->findOrFail($id));
|
||||
} else {
|
||||
abort_unless($access->navigation($request->user())['contexts'] ?? [], 403);
|
||||
if (! ($access->navigation($request->user())['contexts'] ?? [])) {
|
||||
$reason = $access->has($request->user(), 'auditor')
|
||||
? 'O papel de Auditor permite consulta e impede a criação de oportunidades.'
|
||||
: 'Esta conta não dispõe de um contexto ativo de Promotor para uma organização e modalidade autorizadas. Confirme a vigência, o âmbito e os tipos atribuídos na gestão de perfis. A elevação excecional de Superutilizador não substitui a autorização de Promotor.';
|
||||
if ($request->expectsJson()) {
|
||||
abort(403, $reason);
|
||||
}
|
||||
|
||||
return response()->view('profiles.creation-unavailable', ['reason' => $reason], 403);
|
||||
}
|
||||
}
|
||||
|
||||
return app(OpportunityManagementController::class)->edit($request, app(OpportunityManagement::class), $id);
|
||||
|
||||
@@ -6,6 +6,8 @@ use App\Http\Resources\PublicBusinessOpportunityResource;
|
||||
use App\Models\ExistingBusiness;
|
||||
use App\Services\CountryCatalogue;
|
||||
use App\Services\ExistingBusinessDrafts;
|
||||
use App\Services\ExistingBusinessClassification;
|
||||
use App\Services\OpportunityClassification;
|
||||
use App\Services\InvestmentGeography;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -19,16 +21,10 @@ class PublicBusinessOpportunityController extends Controller
|
||||
{
|
||||
public function index(Request $request): Response|JsonResponse
|
||||
{
|
||||
$filters = $request->validate([
|
||||
'q' => ['nullable', 'string', 'max:120'],
|
||||
'modality' => ['nullable', Rule::in(ExistingBusinessDrafts::MODALITIES)],
|
||||
'sector' => ['nullable', 'integer', 'min:1'],
|
||||
'per_page' => ['nullable', 'integer', 'min:1', 'max:50'],
|
||||
'province_id' => ['nullable', 'uuid'], 'district_id' => ['nullable', 'uuid'],
|
||||
'admin_post_id' => ['nullable', 'uuid'], 'locality_id' => ['nullable', 'uuid'],
|
||||
]);
|
||||
$filters = $this->filters($request);
|
||||
|
||||
$query = $this->publishedQuery();
|
||||
app(ExistingBusinessClassification::class)->constrain($query, $filters);
|
||||
$path = app(InvestmentGeography::class)->selection($filters);
|
||||
if ($path !== []) {
|
||||
$territoryIds = app(InvestmentGeography::class)->descendants($path[array_key_last($path)]->id);
|
||||
@@ -53,12 +49,27 @@ class PublicBusinessOpportunityController extends Controller
|
||||
$query->where('existing_businesses.modality', $filters['modality']);
|
||||
}
|
||||
|
||||
$results = PublicBusinessOpportunityResource::collection($query->paginate($filters['per_page'] ?? 12)->withQueryString());
|
||||
$results = PublicBusinessOpportunityResource::collection($query->paginate($filters['per_page'] ?? 12)->appends($filters));
|
||||
if ($request->expectsJson()) {
|
||||
return $results->response();
|
||||
}
|
||||
|
||||
return Inertia::render('investment/business-marketplace', ['results' => $results, 'filters' => $filters, 'territorySelection' => $path]);
|
||||
return Inertia::render('investment/business-marketplace', ['results' => $results, 'filters' => $filters, 'territorySelection' => $path,
|
||||
'classificationOptions' => app(OpportunityClassification::class)->options(),
|
||||
'authorities' => DB::table('authorities')->where('status', 'published')->orderBy('label_pt_mz')->get(['id', 'label_pt_mz'])]);
|
||||
}
|
||||
|
||||
private function filters(Request $request): array
|
||||
{
|
||||
return $request->validate([
|
||||
'q' => ['nullable', 'string', 'max:120'],
|
||||
'modality' => ['nullable', Rule::in(ExistingBusinessDrafts::MODALITIES)],
|
||||
'sector' => ['nullable', 'integer', 'min:1'],
|
||||
'per_page' => ['nullable', 'integer', 'min:1', 'max:50'],
|
||||
'province_id' => ['nullable', 'uuid'], 'district_id' => ['nullable', 'uuid'],
|
||||
'admin_post_id' => ['nullable', 'uuid'], 'locality_id' => ['nullable', 'uuid'],
|
||||
...app(ExistingBusinessClassification::class)->filterRules(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Request $request, string $slug): Response|JsonResponse
|
||||
@@ -69,7 +80,7 @@ class PublicBusinessOpportunityController extends Controller
|
||||
return $resource->response();
|
||||
}
|
||||
|
||||
$returnFilters = $request->query();
|
||||
$returnFilters = $this->filters($request);
|
||||
|
||||
return Inertia::render('investment/business-opportunity', ['record' => $resource->resolve($request),
|
||||
'returnUrl' => $returnFilters === [] ? '/negocios' : '/negocios?'.http_build_query($returnFilters),
|
||||
@@ -80,7 +91,7 @@ class PublicBusinessOpportunityController extends Controller
|
||||
{
|
||||
$record = $this->publishedQuery()->where('existing_businesses.public_slug', $slug)->firstOrFail();
|
||||
|
||||
$returnFilters = $request->query();
|
||||
$returnFilters = $this->filters($request);
|
||||
|
||||
return Inertia::render('investment/business-interest', [
|
||||
'record' => (new PublicBusinessOpportunityResource($record))->resolve($request),
|
||||
@@ -109,6 +120,7 @@ class PublicBusinessOpportunityController extends Controller
|
||||
'existing_businesses.activity_code', 'existing_businesses.stage', 'existing_businesses.objective',
|
||||
'existing_businesses.currency', 'existing_businesses.amount_min', 'existing_businesses.amount_max',
|
||||
'existing_businesses.available_percentage', 'existing_businesses.published_at', 'existing_businesses.sector_id',
|
||||
'existing_businesses.owner_user_id', 'existing_businesses.organization_id', 'existing_businesses.version_no', 'existing_businesses.expires_at', 'existing_businesses.status', 'existing_businesses.modality',
|
||||
'public_location.province', 'public_location.district', 'public_location.locality']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
||||
use App\Models\Opportunity;
|
||||
use App\Models\Sector;
|
||||
use App\Services\CountryCatalogue;
|
||||
use App\Services\SectorInvestment;
|
||||
use Illuminate\Http\Request;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
@@ -23,6 +24,7 @@ class PublicPortalController extends Controller
|
||||
$sector = Sector::where('slug', $slug)->where('is_active', true)->firstOrFail();
|
||||
|
||||
return Inertia::render('portal/services', ['section' => 'sector', 'sector' => $sector->only(['name', 'slug', 'description', 'short_description']),
|
||||
'sectorEntry' => array_key_exists($sector->slug, SectorInvestment::CONTENT) ? app(SectorInvestment::class)->publicView($sector) : null,
|
||||
'opportunities' => $sector->opportunities()->published()->latest('published_at')->limit(12)->get(['title', 'slug', 'province', 'summary'])]);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class ProtectProfileOpportunity
|
||||
if ($record && ($record->owner_user_id !== null || str_starts_with($request->path(), 'minhas-oportunidades'))) {
|
||||
abort_if($record->owner_user_id === null && str_starts_with($request->path(), 'minhas-oportunidades'), 403, 'Registo legado não convertido para a política v1.');
|
||||
$access = app(PortalProfileAccess::class);
|
||||
$access->authorize($request->user(), $request->isMethod('GET') || str_ends_with($request->path(), '/workflow') || str_ends_with($request->path(), '/preview') ? 'view' : 'edit', $record);
|
||||
$access->authorize($request->user(), $request->isMethod('GET') || str_ends_with($request->path(), '/workflow') || str_ends_with($request->path(), '/preview') || $request->is('minhas-oportunidades/*/classification/review') ? 'view' : 'edit', $record);
|
||||
abort_if($request->is('management/opportunity-origin/apply'), 403, 'O cadastro privado v1 não usa a classificação editorial dos exemplos legados.');
|
||||
abort_if($request->isMethod('POST') && str_ends_with($request->path(), '/lifecycle') && ! str_contains($request->path(), '/resources/'), 403, 'Use o workflow com decisões segregadas; o perfil não concede exclusão.');
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ class PublicBusinessOpportunityResource extends JsonResource
|
||||
'province' => $this->resource->getAttribute('province'),
|
||||
'district' => $this->resource->getAttribute('district'),
|
||||
'locality' => $this->resource->getAttribute('locality'),
|
||||
'multidimensional' => app(\App\Services\ExistingBusinessClassification::class)->publicRows($this->resource),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use App\Models\ExistingBusiness;
|
||||
use App\Models\User;
|
||||
use App\Services\PortalProfileAccess;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ExistingBusinessPolicy
|
||||
{
|
||||
@@ -96,6 +97,50 @@ class ExistingBusinessPolicy
|
||||
}
|
||||
}
|
||||
|
||||
/** Supplement-only authority never changes the normal content/workflow abilities. */
|
||||
public function prepareClassification(User $user, ExistingBusiness $business): bool
|
||||
{
|
||||
return $this->owns($user, $business) && ! app(PortalProfileAccess::class)->has($user, 'auditor')
|
||||
&& in_array($business->status, ['draft', 'needs_information', 'published'], true);
|
||||
}
|
||||
|
||||
public function reviewClassification(User $user, ExistingBusiness $business): bool
|
||||
{
|
||||
return ! $business->trashed() && $business->owner_user_id !== $user->id
|
||||
&& ! app(PortalProfileAccess::class)->has($user, 'auditor')
|
||||
&& in_array($business->status, ['triage', 'in_review', 'needs_information', 'published'], true)
|
||||
&& $this->designated($user, 'reviewers', $business);
|
||||
}
|
||||
|
||||
/** Current responsibility check without requiring a reviewer's live browser session on public reads. */
|
||||
public function classificationReviewerScope(User $user, ExistingBusiness $business, string $dimension): bool
|
||||
{
|
||||
if ($business->trashed() || ! $user->hasVerifiedEmail() || (int) $business->owner_user_id === (int) $user->id) {
|
||||
return false;
|
||||
}
|
||||
$access = app(PortalProfileAccess::class);
|
||||
if ($access->has($user, 'auditor')) { return false; }
|
||||
if (! $access->available()) {
|
||||
return $access->legacyWriteAllowed($user) && (bool) $user->two_factor_confirmed_at && (bool) $user->two_factor_secret
|
||||
&& in_array(strtolower($user->email), config('existing-business.reviewers', []), true);
|
||||
}
|
||||
if ($business->modality !== 'company_sale') { return false; }
|
||||
$responsibility = $dimension === 'regulation' ? 'legal_reviewer' : 'technical_reviewer';
|
||||
return collect($access->grants($user, 'validator'))->contains(fn ($g) => $g->organization_id === null
|
||||
&& in_array('business_sale', json_decode($g->opportunity_types, true), true)
|
||||
&& in_array($responsibility, json_decode($g->responsibilities, true), true));
|
||||
}
|
||||
|
||||
public function discloseClassification(User $user, ExistingBusiness $business): bool
|
||||
{
|
||||
if ($business->trashed() || $business->status !== 'published' || (int) $business->owner_user_id === (int) $user->id
|
||||
|| app(PortalProfileAccess::class)->has($user, 'auditor') || ! $this->designated($user, 'publishers', $business)) {
|
||||
return false;
|
||||
}
|
||||
return ! DB::table('business_workflow_transitions')->where('existing_business_id', $business->id)
|
||||
->whereIn('to_status', ['approval_l2', 'approved'])->where('actor_id', $user->id)->exists();
|
||||
}
|
||||
|
||||
private function designatedAny(User $user, ?ExistingBusiness $business = null): bool
|
||||
{
|
||||
foreach (['reviewers', 'triagers', 'approvers_l1', 'approvers_l2', 'publishers'] as $designation) {
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\ExistingBusiness;
|
||||
use App\Models\User;
|
||||
use App\Policies\ExistingBusinessPolicy;
|
||||
use App\Services\Mne\BusinessRepository;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
/** Supplement of the same UUID. All state remains in the existing immutable encrypted journal. */
|
||||
class ExistingBusinessClassification
|
||||
{
|
||||
public const VERSION = 'business-classification-20261016-v1';
|
||||
private const ACTIONS = ['classification_prepared', 'classification_reviewed', 'classification_disclosed', 'classification_withdrawn'];
|
||||
|
||||
public function context(ExistingBusiness $business): array
|
||||
{
|
||||
$revision = DB::table('existing_business_revisions')->where('business_id', $business->id)->whereIn('action', self::ACTIONS)->orderByDesc('version_no')->first(['snapshot']);
|
||||
if (! $revision) {
|
||||
return ['schema_version' => self::VERSION, 'relations' => [], 'authors' => [], 'decisions' => [], 'publication' => []];
|
||||
}
|
||||
$state = json_decode(Crypt::decryptString($revision->snapshot), true, 512, JSON_THROW_ON_ERROR)['context']['multidimensional'] ?? null;
|
||||
abort_unless(is_array($state) && ($state['schema_version'] ?? '') === self::VERSION, 409, 'Versão do suplemento não reconhecida; preserve o histórico.');
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
private function hash(array $row): string
|
||||
{
|
||||
return OpportunityCanonicalValue::hash($row);
|
||||
}
|
||||
|
||||
private function evidence(array $row, ExistingBusiness $business): ?array
|
||||
{
|
||||
$id = $row['classification']['document_id'] ?? null;
|
||||
if (! $id) {
|
||||
return null;
|
||||
}
|
||||
$document = DB::table('existing_business_document_links as l')->join('documents as d', 'd.id', '=', 'l.document_id')
|
||||
->where('l.existing_business_id', $business->id)->where('d.id', $id)
|
||||
->first(['l.id as link_id', 'd.id', 'd.sha256', 'd.version_no', 'd.status', 'd.deleted_at', 'd.valid_until', 'd.malware_scan_status', 'd.malware_scanned_sha256']);
|
||||
|
||||
return $document ? (array) $document : ['unavailable' => $id];
|
||||
}
|
||||
|
||||
private function evidenceHash(array $row, ExistingBusiness $business): ?string
|
||||
{
|
||||
$evidence = $this->evidence($row, $business);
|
||||
|
||||
return $evidence === null ? null : OpportunityCanonicalValue::hash($evidence);
|
||||
}
|
||||
|
||||
private function validateRows(array $rows, ExistingBusiness $business, bool $confirming = false): void
|
||||
{
|
||||
$seen = [];
|
||||
foreach ($rows as $i => $row) {
|
||||
$fail = fn ($key, $message) => throw ValidationException::withMessages(['canonical.relations.'.$i.'.'.$key => $message]);
|
||||
Validator::make($row, [
|
||||
'related_id' => ['required', 'string', 'max:80'], 'relation_type' => ['required', 'string', 'max:80'],
|
||||
'classification' => ['required', 'array:target_type,purpose,criteria,justification,source_reference,citation,document_id,authority_id,requested_state,disclosure,valid_from,valid_until,external_status,external_act_reference,production_stage'],
|
||||
'classification.target_type' => ['required', Rule::in(array_keys(OpportunityClassification::TARGETS))],
|
||||
'classification.purpose' => ['required', Rule::in(array_keys(OpportunityClassification::PURPOSES))],
|
||||
'classification.requested_state' => ['required', Rule::in(['draft', 'preliminary', 'in_validation'])],
|
||||
'classification.disclosure' => ['required', Rule::in(['restricted', 'public'])],
|
||||
'classification.criteria' => ['nullable', 'string', 'max:2000'], 'classification.justification' => ['nullable', 'string', 'max:4000'],
|
||||
'classification.source_reference' => ['nullable', 'string', 'max:2000'], 'classification.citation' => ['nullable', 'string', 'max:1000'],
|
||||
'classification.document_id' => ['nullable', 'uuid'], 'classification.authority_id' => ['nullable', 'uuid'],
|
||||
'classification.valid_from' => ['nullable', 'date_format:Y-m-d'], 'classification.valid_until' => ['nullable', 'date_format:Y-m-d'],
|
||||
'classification.external_status' => ['required', Rule::in(OpportunityClassification::EXTERNAL)],
|
||||
'classification.external_act_reference' => ['nullable', 'string', 'max:2000'], 'classification.production_stage' => ['nullable', 'string', 'max:250'],
|
||||
])->validate();
|
||||
if (array_diff(array_keys($row), ['related_id', 'relation_type', 'classification'])) {
|
||||
$fail('classification', 'Metadados de decisão ou campos desconhecidos não podem ser enviados pelo autor.');
|
||||
}
|
||||
$c = $row['classification']; $kind = $c['target_type'];
|
||||
if (($kind === 'sector' && ! ctype_digit($row['related_id'])) || ($kind !== 'sector' && ! Str::isUuid($row['related_id']))) {
|
||||
$fail('related_id', 'Identificador de referência inválido.');
|
||||
}
|
||||
if (! app(OpportunityClassification::class)->targets($kind)->where('id', $row['related_id'])->exists()) {
|
||||
$fail('related_id', 'Selecione uma referência existente e consultável.');
|
||||
}
|
||||
if (in_array($c['purpose'], ['regime_recognition', 'enterprise_admission', 'specific_benefit'], true) && $kind !== 'zone') {
|
||||
$fail('classification.purpose', 'Regime, admissão e benefício usam a relação regulatória com a zona.');
|
||||
}
|
||||
$identity = OpportunityClassification::TARGETS[$kind][0].':'.$row['related_id'].':'.$c['purpose'];
|
||||
if (isset($seen[$identity])) { $fail('related_id', 'Referência e finalidade já associadas; recupere a relação existente.'); }
|
||||
$seen[$identity] = true;
|
||||
if (! empty($c['valid_from']) && ! empty($c['valid_until']) && $c['valid_until'] < $c['valid_from']) {
|
||||
$fail('classification.valid_until', 'O fim da vigência precede o início.');
|
||||
}
|
||||
if (! empty($c['authority_id']) && ! DB::table('authorities')->where('id', $c['authority_id'])->where('status', 'published')->exists()) {
|
||||
$fail('classification.authority_id', 'Entidade competente não consta do catálogo publicado.');
|
||||
}
|
||||
$evidence = $this->evidence($row, $business);
|
||||
if ($evidence && isset($evidence['unavailable'])) { $fail('classification.document_id', 'Documento não está associado a este anúncio.'); }
|
||||
if (($c['external_status'] ?? '') === 'documented_granted' && (empty($c['document_id']) || empty(trim($c['external_act_reference'] ?? '')))) {
|
||||
$fail('classification.external_act_reference', 'Um ato declarado como concedido exige documento e referência próprios.');
|
||||
}
|
||||
if ($confirming) {
|
||||
foreach (['criteria', 'justification', 'source_reference', 'citation'] as $key) {
|
||||
if (empty(trim($c[$key] ?? ''))) { $fail('classification.'.$key, 'Confirmação exige fundamento e fonte/citação por relação; a preparação pode continuar preliminar.'); }
|
||||
}
|
||||
if ($evidence && ($evidence['status'] !== 'active' || $evidence['deleted_at'] !== null || $evidence['malware_scan_status'] !== 'clean'
|
||||
|| ! hash_equals(trim($evidence['sha256']), trim((string) $evidence['malware_scanned_sha256']))
|
||||
|| (! empty($evidence['valid_until']) && $evidence['valid_until'] < today()->toDateString()))) {
|
||||
$fail('classification.document_id', 'O suporte associado não está disponível, íntegro e analisado para esta confirmação.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function effective(ExistingBusiness $business, array $row, array $state): string
|
||||
{
|
||||
$decision = $state['decisions'][$this->hash($row)] ?? null;
|
||||
if (! $decision) { return $row['classification']['requested_state'] ?? 'preliminary'; }
|
||||
if ($decision['state'] !== 'confirmed') { return $decision['state']; }
|
||||
$dimension = OpportunityClassification::TARGETS[$row['classification']['target_type']][2];
|
||||
$reviewer = User::find($decision['actor_id']);
|
||||
if (! $reviewer || ! app(ExistingBusinessPolicy::class)->classificationReviewerScope($reviewer, $business, $dimension)
|
||||
|| (int) ($state['authors'][$this->hash($row)] ?? 0) === (int) $reviewer->id
|
||||
|| ($decision['evidence_hash'] ?? null) !== $this->evidenceHash($row, $business)) {
|
||||
return 'in_validation';
|
||||
}
|
||||
|
||||
return 'confirmed';
|
||||
}
|
||||
|
||||
public function privateView(User $actor, ExistingBusiness $business): array
|
||||
{
|
||||
Gate::forUser($actor)->authorize('view', $business);
|
||||
$state = $this->context($business);
|
||||
$rows = [];
|
||||
foreach ($state['relations'] as $row) {
|
||||
$hash = $this->hash($row); $dimension = OpportunityClassification::TARGETS[$row['classification']['target_type']][2];
|
||||
$rows[] = ['hash' => $hash, 'relation' => $row, 'dimension' => $dimension, 'state' => $this->effective($business, $row, $state),
|
||||
'can_review' => Gate::forUser($actor)->allows('reviewClassification', $business) && app(ExistingBusinessPolicy::class)->classificationReviewerScope($actor, $business, $dimension)
|
||||
&& (int) ($state['authors'][$hash] ?? 0) !== (int) $actor->id,
|
||||
'history' => $state['decisions'][$hash]['history'] ?? []];
|
||||
}
|
||||
$documents = DB::table('existing_business_document_links as l')->join('documents as d', 'd.id', '=', 'l.document_id')
|
||||
->where('l.existing_business_id', $business->id)->whereNull('d.deleted_at')->get(['d.id', 'd.file_name', 'd.sha256']);
|
||||
|
||||
return ['id' => $business->id, 'title' => $business->public_title, 'status' => $business->status, 'version_no' => $business->version_no,
|
||||
'rows' => $rows, 'publication' => $this->publicRows($business), 'publication_version' => $state['publication_version'] ?? null,
|
||||
'preview' => $this->publicRows($business, [...$state, 'publication' => array_values(array_filter($state['relations'], fn ($r) => $r['classification']['disclosure'] === 'public'))]),
|
||||
'can_prepare' => Gate::forUser($actor)->allows('prepareClassification', $business),
|
||||
'can_disclose' => Gate::forUser($actor)->allows('discloseClassification', $business),
|
||||
'options' => app(OpportunityClassification::class)->options(),
|
||||
'authorities' => DB::table('authorities')->where('status', 'published')->orderBy('label_pt_mz')->get(['id', 'label_pt_mz']),
|
||||
'documents' => $documents->map(fn ($d) => ['id' => $d->id, 'payload' => ['title' => $d->file_name], 'file' => ['file_name' => $d->file_name]])];
|
||||
}
|
||||
|
||||
public function act(User $actor, string $id, array $input): ExistingBusiness
|
||||
{
|
||||
$data = Validator::make($input, [
|
||||
'action' => ['required', Rule::in(['prepare', 'review', 'disclose', 'withdraw'])], 'version_no' => ['required', 'integer', 'min:1'],
|
||||
'reason' => ['required', 'string', 'min:20', 'max:1000'],
|
||||
'rows' => ['required_if:action,prepare', 'array', 'max:100'],
|
||||
'hash' => ['required_if:action,review', 'string', 'size:64'],
|
||||
'state' => ['required_if:action,review', Rule::in(['in_validation', 'confirmed', 'rejected', 'archived', 'revoked'])],
|
||||
], ['reason.required' => 'Indique o fundamento da ação.', 'reason.min' => 'O fundamento deve ter pelo menos 20 caracteres.'])->validate();
|
||||
abort_if(array_diff(array_keys($input), ['action', 'version_no', 'reason', 'rows', 'hash', 'state']), 422, 'Esta ação aceita apenas campos da classificação.');
|
||||
|
||||
return DB::transaction(function () use ($actor, $id, $data) {
|
||||
$business = app(BusinessRepository::class)->find($id, true);
|
||||
$action = $data['action'];
|
||||
Gate::forUser($actor)->authorize(match ($action) { 'prepare' => 'prepareClassification', 'review' => 'reviewClassification', default => 'discloseClassification' }, $business);
|
||||
abort_unless($business->version_no === (int) $data['version_no'], 409, 'A versão mudou. Atualize antes de decidir; preserve os valores preparados.');
|
||||
$state = $this->context($business);
|
||||
if ($action === 'prepare') {
|
||||
$this->validateRows($data['rows'], $business);
|
||||
$state['relations'] = $data['rows'];
|
||||
foreach ($data['rows'] as $row) { $state['authors'][$this->hash($row)] ??= $actor->id; }
|
||||
} elseif ($action === 'review') {
|
||||
$search = in_array($data['state'], ['revoked', 'archived'], true) ? [...$state['relations'], ...$state['publication']] : $state['relations'];
|
||||
$row = collect($search)->first(fn ($r) => hash_equals($this->hash($r), $data['hash']));
|
||||
abort_unless($row, 409, 'Associação inexistente nesta versão.');
|
||||
$dimension = OpportunityClassification::TARGETS[$row['classification']['target_type']][2];
|
||||
abort_unless(app(ExistingBusinessPolicy::class)->classificationReviewerScope($actor, $business, $dimension)
|
||||
&& (int) ($state['authors'][$data['hash']] ?? 0) !== (int) $actor->id, 403, 'Revisão exige responsabilidade e independência aplicáveis.');
|
||||
if ($data['state'] === 'confirmed') { $this->validateRows([$row], $business, true); }
|
||||
$prior = $state['decisions'][$data['hash']] ?? [];
|
||||
$decision = ['state' => $data['state'], 'actor_id' => $actor->id, 'at' => now()->toIso8601String(), 'reason' => $data['reason'],
|
||||
'evidence_hash' => $this->evidenceHash($row, $business), 'version' => ($prior['version'] ?? 0) + 1];
|
||||
$state['decisions'][$data['hash']] = [...$decision, 'history' => [...($prior['history'] ?? []), $decision]];
|
||||
if (in_array($data['state'], ['revoked', 'archived'], true)) {
|
||||
// Explicit withdrawal is retained: a later confirmation must not silently republish it.
|
||||
$state['publication'] = array_values(array_filter($state['publication'], fn ($r) => $this->hash($r) !== $data['hash']));
|
||||
}
|
||||
} else {
|
||||
$publication = $action === 'withdraw' ? [] : array_values(array_filter($state['relations'], fn ($r) => $r['classification']['disclosure'] === 'public'));
|
||||
$this->validateRows($publication, $business);
|
||||
// Existing publication independence also applies to the actors deciding this supplement.
|
||||
foreach ($publication as $row) {
|
||||
abort_if((int) ($state['decisions'][$this->hash($row)]['actor_id'] ?? 0) === (int) $actor->id, 403, 'A divulgação deve ser feita por pessoa diferente de quem decidiu a associação.');
|
||||
}
|
||||
$state['publication'] = $publication;
|
||||
$state['publication_version'] = $business->version_no + 1;
|
||||
$state['publication_actor'] = $actor->id;
|
||||
$state['publication_at'] = now()->toIso8601String();
|
||||
}
|
||||
$business->version_no++;
|
||||
$business->save();
|
||||
$event = ['prepare' => 'classification_prepared', 'review' => 'classification_reviewed', 'disclose' => 'classification_disclosed', 'withdraw' => 'classification_withdrawn'][$action];
|
||||
app(ExistingBusinessDrafts::class)->snapshot($business, $actor, $event, $data['reason'], ['multidimensional' => $state]);
|
||||
|
||||
return $business;
|
||||
});
|
||||
}
|
||||
|
||||
public function publicRows(ExistingBusiness $business, ?array $preparedState = null): array
|
||||
{
|
||||
if ($business->trashed() || $business->status !== 'published' || ! $business->published_at || $business->published_at->isFuture()
|
||||
|| ($business->expires_at && $business->expires_at->isBefore(today()))) { return []; }
|
||||
$state = $preparedState ?? $this->context($business); $rows = [];
|
||||
foreach ($state['publication'] as $row) {
|
||||
$c = $row['classification']; $kind = $c['target_type'];
|
||||
if (($c['disclosure'] ?? '') !== 'public' || ! isset(OpportunityClassification::TARGETS[$kind])) { continue; }
|
||||
$target = app(OpportunityClassification::class)->targets($kind)->where('id', $row['related_id'])->first();
|
||||
if (! $target || (! empty($c['valid_from']) && $c['valid_from'] > today()->toDateString()) || (! empty($c['valid_until']) && $c['valid_until'] < today()->toDateString())) { continue; }
|
||||
$effective = $this->effective($business, $row, $state);
|
||||
if (in_array($effective, ['archived', 'revoked'], true)) { continue; }
|
||||
$rows[] = ['dimension' => OpportunityClassification::TARGETS[$kind][2], 'target_type' => $kind, 'target_id' => (string) $row['related_id'],
|
||||
'label' => $target->{OpportunityClassification::TARGETS[$kind][1]}, 'purpose' => $c['purpose'], 'purpose_label' => OpportunityClassification::PURPOSES[$c['purpose']],
|
||||
'state' => $effective, 'source_reference' => $c['source_reference'] ?? null, 'citation' => $c['citation'] ?? null,
|
||||
'authority_id' => $c['authority_id'] ?? null, 'production_stage' => $c['production_stage'] ?? null,
|
||||
'external_status' => $c['external_status'], 'valid_from' => $c['valid_from'] ?? null, 'valid_until' => $c['valid_until'] ?? null];
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public function filterRules(): array
|
||||
{
|
||||
return ['association_type' => ['nullable', Rule::in(array_keys(OpportunityClassification::TARGETS))],
|
||||
'association_target' => ['nullable', 'string', 'max:80'], 'association_purpose' => ['nullable', Rule::in(array_keys(OpportunityClassification::PURPOSES))],
|
||||
'association_state' => ['nullable', Rule::in(OpportunityClassification::STATES)],
|
||||
'chain_id' => ['nullable', 'uuid'], 'authority_id' => ['nullable', 'uuid'], 'subsector_id' => ['nullable', 'uuid']];
|
||||
}
|
||||
|
||||
public function constrain(Builder $query, array $filters): void
|
||||
{
|
||||
$filters = array_filter(array_intersect_key($filters, $this->filterRules()), fn ($v) => $v !== null && $v !== '');
|
||||
if ($filters === []) { return; }
|
||||
$ids = [];
|
||||
(clone $query)->reorder()->select('existing_businesses.*')->chunkById(200, function ($records) use ($filters, &$ids) {
|
||||
foreach ($records as $business) {
|
||||
$rows = $this->publicRows($business); $same = array_intersect_key($filters, array_flip(['association_type', 'association_target', 'association_purpose', 'association_state']));
|
||||
$matches = ! $same || collect($rows)->contains(function ($row) use ($same) {
|
||||
foreach (['association_type' => 'target_type', 'association_target' => 'target_id', 'association_purpose' => 'purpose', 'association_state' => 'state'] as $key => $field) {
|
||||
if (isset($same[$key]) && $same[$key] !== $row[$field]) { return false; }
|
||||
}
|
||||
return true;
|
||||
});
|
||||
foreach (['chain_id' => 'chain', 'subsector_id' => 'activity'] as $key => $type) {
|
||||
if (! empty($filters[$key])) { $matches = $matches && collect($rows)->contains(fn ($r) => $r['target_type'] === $type && $r['target_id'] === $filters[$key]); }
|
||||
}
|
||||
if (! empty($filters['authority_id'])) { $matches = $matches && collect($rows)->contains(fn ($r) => ($r['authority_id'] ?? null) === $filters['authority_id']); }
|
||||
if ($matches) { $ids[] = $business->id; }
|
||||
}
|
||||
}, 'existing_businesses.id', 'id');
|
||||
$query->whereIn('existing_businesses.id', $ids);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\Ai\InvestorGuidanceRules;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
/** Private characterization in the existing dossier; no legal classification or new workflow. */
|
||||
final class FintechInvestment
|
||||
{
|
||||
public const VERSION = 'fintech-preparation-v1';
|
||||
|
||||
public const FIELDS = [
|
||||
'problem' => 'Problema a resolver', 'clients' => 'Público-alvo e clientes nacionais/estrangeiros',
|
||||
'value' => 'Proposta de valor', 'revenues' => 'Modelo de receitas', 'services' => 'Serviços pretendidos',
|
||||
'channels' => 'Canais de prestação', 'currencies' => 'Moedas de operação declaradas',
|
||||
'location' => 'Localização efetiva e instalações', 'coverage' => 'Abrangência de operação',
|
||||
'technology' => 'Tecnologia e arquitetura', 'infrastructure' => 'Infraestrutura',
|
||||
'suppliers' => 'Fornecedores críticos', 'security' => 'Segurança e resposta a incidentes',
|
||||
'continuity' => 'Continuidade e recuperação', 'partners' => 'Instituições financeiras e parceiros',
|
||||
'team' => 'Equipa e capacidade operacional', 'maturity' => 'Maturidade declarada',
|
||||
'dependencies' => 'Dependências concretas', 'schedule' => 'Calendário de implementação',
|
||||
];
|
||||
|
||||
public const ACTIVITIES = ['moves_funds' => 'Movimentar fundos', 'deposits' => 'Receber depósitos',
|
||||
'custody' => 'Custodiar fundos', 'credit' => 'Conceder crédito', 'payments' => 'Serviços de pagamento',
|
||||
'investment_intermediation' => 'Intermediar investimentos', 'other' => 'Outra atividade potencialmente regulada'];
|
||||
|
||||
public const DOCUMENTS = ['business_plan' => ['S04', 'Modelo de negócio, mercado e plano de investimento'],
|
||||
'entity' => ['S05', 'Entidade, representação e participação'], 'architecture' => ['S06', 'Arquitetura tecnológica e fluxos de dados'],
|
||||
'security' => ['S16', 'Segurança, continuidade e fornecedores'], 'fund_flows' => ['S08', 'Fluxos de fundos e enquadramento da atividade'],
|
||||
'customers' => ['S17', 'Atendimento, reclamações e proteção do utilizador'],
|
||||
'external' => ['S08', 'Pedido ou decisão externa e respetivo âmbito'], 'tests' => ['S17', 'Testes e preparação operacional']];
|
||||
|
||||
public function __construct(private readonly VirtualDesk $desk) {}
|
||||
|
||||
public function save(User $actor, string $id, array $input): void
|
||||
{
|
||||
$keys = implode(',', array_keys(self::FIELDS));
|
||||
$activities = implode(',', array_keys(self::ACTIVITIES));
|
||||
$rules = ['version' => 'required|integer|min:1', 'profile' => ['required', 'array:model,fields,operation_countries,activities,activity_basis,documents'],
|
||||
'profile.model' => ['nullable', Rule::in(['technology_provider', 'financial_operator', 'undetermined'])],
|
||||
'profile.fields' => ['nullable', 'array:'.$keys], 'profile.operation_countries' => 'nullable|array|max:249',
|
||||
'profile.operation_countries.*' => ['required', 'distinct', app(CountryCatalogue::class)->rule()],
|
||||
'profile.activities' => ['nullable', 'array:'.$activities], 'profile.activity_basis' => 'nullable|string|max:3000',
|
||||
'profile.documents' => 'nullable|array|max:8', 'profile.documents.*' => 'nullable|uuid'];
|
||||
foreach (self::FIELDS as $key => $label) {
|
||||
$rules['profile.fields.'.$key] = 'nullable|string|max:4000';
|
||||
}
|
||||
foreach (self::ACTIVITIES as $key => $label) {
|
||||
$rules['profile.activities.'.$key] = ['nullable', Rule::in(['yes', 'no', 'unknown'])];
|
||||
}
|
||||
$rules['profile.documents'] = ['nullable', 'array:'.implode(',', array_keys(self::DOCUMENTS))];
|
||||
$data = Validator::make($input, $rules)->validate();
|
||||
DB::transaction(function () use ($actor, $id, $data) {
|
||||
$case = $this->desk->case($actor, $id, true, true);
|
||||
abort_if($case->closed_at, 409, 'O dossier está encerrado.');
|
||||
abort_unless($this->desk->owns($actor, $case), 403, 'Sem autorização para preparar este dossier.');
|
||||
$payload = $this->desk->decode($case->payload);
|
||||
$profile = $data['profile'];
|
||||
$profile['model'] = $profile['model'] ?? 'undetermined';
|
||||
$profile['fields'] = array_map(fn ($v) => trim((string) $v), $profile['fields'] ?? []);
|
||||
$profile['activities'] = array_replace(array_fill_keys(array_keys(self::ACTIVITIES), 'unknown'), $profile['activities'] ?? []);
|
||||
$profile['operation_countries'] = $profile['operation_countries'] ?? [];
|
||||
sort($profile['operation_countries']);
|
||||
$profile['documents'] = array_filter($profile['documents'] ?? []);
|
||||
$profile['activity_basis'] = trim($profile['activity_basis'] ?? '');
|
||||
foreach ($profile['documents'] as $key => $document) {
|
||||
if (! DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')->where('l.case_id', $id)->where('l.document_id', $document)->whereNull('d.deleted_at')->exists()) {
|
||||
throw ValidationException::withMessages(['profile.documents.'.$key => 'O documento deixou de estar disponível neste dossier. Selecione um anexo associado e disponível; os campos preenchidos foram preservados.']);
|
||||
}
|
||||
}
|
||||
$hash = $this->fingerprint($profile);
|
||||
$old = $payload['investor_path']['fintech'] ?? null;
|
||||
if (($old['sha256'] ?? null) === $hash) {
|
||||
return;
|
||||
}
|
||||
abort_unless((int) $case->version === $data['version'], 409, 'O dossier foi alterado; recupere a versão atual antes de guardar.');
|
||||
if ($old) {
|
||||
$payload['investor_path']['fintech_history'][] = $old;
|
||||
}
|
||||
$payload['investor_path']['fintech'] = ['schema' => self::VERSION, 'sha256' => $hash, 'profile' => $profile, 'actor_id' => $actor->id, 'saved_at' => now()->toIso8601String()];
|
||||
DB::table('desk_cases')->where('id', $id)->update(['payload' => $this->desk->encode($payload), 'version' => $case->version + 1, 'updated_at' => now()]);
|
||||
$this->desk->event($this->desk->case($actor, $id), $actor, 'fintech_characterization_saved', ['schema' => self::VERSION, 'sha256' => $hash, 'previous_sha256' => $old['sha256'] ?? null]);
|
||||
});
|
||||
}
|
||||
|
||||
private function fingerprint(array $value): string
|
||||
{
|
||||
$canonical = function ($v) use (&$canonical) {
|
||||
if (! is_array($v)) {
|
||||
return $v;
|
||||
}
|
||||
if (! array_is_list($v)) {
|
||||
ksort($v);
|
||||
}
|
||||
|
||||
return array_map($canonical, $v);
|
||||
};
|
||||
|
||||
return hash('sha256', json_encode($canonical($value), JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR));
|
||||
}
|
||||
|
||||
public function reviewFingerprints(array $record): array
|
||||
{
|
||||
$profile = $record['profile'] ?? [];
|
||||
$fields = $profile['fields'] ?? [];
|
||||
$project = static fn (array $keys) => array_replace(array_fill_keys($keys, ''), array_intersect_key($fields, array_flip($keys)));
|
||||
$countries = $profile['operation_countries'] ?? [];
|
||||
sort($countries);
|
||||
|
||||
// Country order and an omitted versus empty optional field are not material changes.
|
||||
return [
|
||||
'S02' => $this->fingerprint($project(['problem', 'clients', 'value', 'revenues'])),
|
||||
'S08' => $this->fingerprint([$profile['model'] ?? 'undetermined', $profile['activities'] ?? [], $countries, $fields['services'] ?? '', $profile['activity_basis'] ?? '']),
|
||||
'S17' => $this->fingerprint($project(['technology', 'infrastructure', 'suppliers', 'security', 'continuity', 'channels', 'location'])),
|
||||
];
|
||||
}
|
||||
|
||||
public function adjustSteps(array $payload, array $steps): array
|
||||
{
|
||||
$record = $payload['investor_path']['fintech'] ?? null;
|
||||
if (! $record) {
|
||||
return $steps;
|
||||
}
|
||||
$fingerprints = $this->reviewFingerprints($record);
|
||||
foreach ($steps as &$step) {
|
||||
$hash = $fingerprints[$step['code']] ?? null;
|
||||
if (! $hash) {
|
||||
continue;
|
||||
}
|
||||
$reviewed = in_array($step['saved_state'], ['approved', 'reviewing', 'completed', 'ready_to_submit', 'submitted'], true);
|
||||
if ($reviewed && ($step['detail']['fintech_fingerprint'] ?? null) !== $hash) {
|
||||
$step['fintech_review_required'] = true;
|
||||
$step['state'] = 'correction_required';
|
||||
$step['reason'] = 'Pressupostos Fintech alterados ou ainda não abrangidos por esta revisão. O parecer anterior está preservado; é necessária conferência deste âmbito.';
|
||||
}
|
||||
}
|
||||
unset($step);
|
||||
|
||||
return $steps;
|
||||
}
|
||||
|
||||
public function view(array $payload, array $steps): array
|
||||
{
|
||||
$record = $payload['investor_path']['fintech'] ?? null;
|
||||
$p = $record['profile'] ?? [];
|
||||
$declared = $p['activities'] ?? [];
|
||||
$basis = $p['activity_basis'] ?? '';
|
||||
$requirements = [];
|
||||
foreach (self::ACTIVITIES as $key => $label) {
|
||||
$value = $declared[$key] ?? 'unknown';
|
||||
$requirements[] = ['code' => $key, 'activity' => $label,
|
||||
'declared' => $value, 'state' => $value === 'yes' ? 'applicable' : ($value === 'no' && mb_strlen($basis) >= 3 ? 'dispensed' : 'undetermined'),
|
||||
'action' => 'Preparar o enquadramento documental desta atividade', 'preparation_allowed' => true,
|
||||
'basis' => $value === 'no' && mb_strlen($basis) >= 3 ? $basis : 'Declaração do promotor; a atividade e o enquadramento jurídico concreto ainda precisam de correspondência documental.',
|
||||
'source' => ['nature' => 'investor_declaration', 'reference' => $record['sha256'] ?? null, 'provision' => null, 'version' => null, 'valid_period' => null],
|
||||
'legal_license_state' => 'undetermined', 'limit' => 'Dispensa apenas desta preparação declarada; não é dispensa de licença ou confirmação externa.'];
|
||||
}
|
||||
$docs = [];
|
||||
foreach (self::DOCUMENTS as $key => [$stage,$label]) {
|
||||
$conditional = in_array($key, ['fund_flows', 'external'], true);
|
||||
$needed = $conditional ? (in_array('yes', $declared, true) ? 'applicable' : 'undetermined') : 'support';
|
||||
$docs[] = ['code' => $key, 'stage' => $stage, 'label' => $label, 'applicability' => $needed, 'document_id' => $p['documents'][$key] ?? null, 'required_at_creation' => false, 'action' => $key === 'external' ? 'Documentar o ato quando existir; usar a etapa e a conferência independente existentes.' : 'Preparar e associar ao dossier sem duplicar originais.'];
|
||||
}
|
||||
$facts = ['project_summary' => $p['fields']['problem'] ?? '', 'activity' => $p['fields']['services'] ?? '', 'target_customers' => $p['fields']['clients'] ?? '', 'location' => $p['fields']['location'] ?? '', 'resource_plan' => $p['fields']['technology'] ?? '', 'schedule' => $p['fields']['schedule'] ?? ''];
|
||||
$guidance = app(InvestorGuidanceRules::class)->evaluate($facts);
|
||||
$map = ['idea' => 'S01', 'market' => 'S02', 'location' => 'S09', 'resources' => 'S06', 'finance' => 'S12', 'execution' => 'S16', 'support' => 'S19'];
|
||||
$guidance = array_map(fn ($item) => ['stage' => $map[$item['id']], 'recommendations' => $item['recommendations']], $guidance);
|
||||
|
||||
return ['guidance' => $guidance, 'guidance_version' => InvestorGuidanceRules::VERSION, 'schema' => self::VERSION, 'record' => $record, 'fields' => self::FIELDS, 'activities' => self::ACTIVITIES, 'countries' => app(CountryCatalogue::class)->all(),
|
||||
'requirements' => $requirements, 'documents' => $docs, 'review_fingerprints' => $record ? $this->reviewFingerprints($record) : [],
|
||||
'affected_reviews' => array_values(array_column(array_filter($steps,fn ($s) => $s['fintech_review_required'] ?? false), 'code')),
|
||||
'limits' => ['Fintech é caracterização do investimento, não nova categoria jurídica ou autorização.', 'Preparação de orçamento, tecnologia, documentos e parceiros pode avançar em paralelo.', 'Países de operação não alteram país mestre, origem, nacionalidade ou residências.', 'Capitais mínimos, taxas, prazos e licenças específicos permanecem por determinar sem disposição e período aplicáveis.']];
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,13 @@ class InvestmentCatalogue
|
||||
'max_amount' => ['nullable', 'numeric', 'min:0', 'max:999999999999', ...($request->filled('min_amount') ? ['gte:min_amount'] : [])],
|
||||
'currency' => ['nullable', 'required_with:min_amount,max_amount', 'in:MZN,USD,EUR,ZAR'],
|
||||
'before' => ['nullable', 'date_format:Y-m-d'], 'sort' => ['nullable', 'in:recent,title,amount_asc,amount_desc'],
|
||||
'association_type' => ['nullable', 'in:'.implode(',', array_keys(OpportunityClassification::TARGETS))],
|
||||
'association_target' => ['nullable', 'string', 'max:80'],
|
||||
'association_state' => ['nullable', 'in:'.implode(',', OpportunityClassification::STATES)],
|
||||
'association_purpose' => ['nullable', 'in:'.implode(',', array_keys(OpportunityClassification::PURPOSES))],
|
||||
'authority_id' => ['nullable', 'uuid'], 'chain_id' => ['nullable', 'uuid'], 'subsector_id' => ['nullable', 'uuid'],
|
||||
'category' => ['nullable', 'in:'.implode(',', OpportunityManagement::CATEGORIES)],
|
||||
'publication_state' => ['nullable', 'in:published'],
|
||||
'per_page' => ['nullable', 'integer', 'between:1,50'], 'page' => ['nullable', 'integer', 'min:1']]);
|
||||
app(InvestmentGeography::class)->selection($filters);
|
||||
|
||||
@@ -164,6 +171,8 @@ class InvestmentCatalogue
|
||||
if (! empty($filters['before'])) {
|
||||
$query->whereExists(fn ($sub) => $sub->selectRaw('1')->from('opportunity_profiles')->whereColumn('opportunity_id', 'opportunities.id')->where('target_date', '<=', $filters['before']));
|
||||
}
|
||||
if (! empty($filters['category'])) $query->where('opportunity_category', $filters['category']);
|
||||
app(OpportunityClassification::class)->constrain($query, $filters);
|
||||
$sort = $filters['sort'] ?? 'recent';
|
||||
|
||||
// Monetary sorting stays grouped by currency; no undocumented FX conversion.
|
||||
@@ -178,7 +187,10 @@ class InvestmentCatalogue
|
||||
* @return array<string,mixed> */
|
||||
public function references(bool $management = false, array $territoryFilters = []): array
|
||||
{
|
||||
$result = ['options' => DB::table('investment_reference_options')->when(! $management, fn ($q) => $q->where('active', true))->orderBy('sort_order')->orderBy('label')->get(),
|
||||
$result = ['classification' => app(OpportunityClassification::class)->options(),
|
||||
'authorities' => DB::table('authorities')->where('status', 'published')->get(['id', 'label_pt_mz']),
|
||||
'categories' => OpportunityManagement::CATEGORIES,
|
||||
'options' => DB::table('investment_reference_options')->when(! $management, fn ($q) => $q->where('active', true))->orderBy('sort_order')->orderBy('label')->get(),
|
||||
'sectors' => DB::table('sectors')->where('is_active', true)->whereNull('deleted_at')->orderBy('name')->get(['id', 'name', 'slug']),
|
||||
'maturityCatalogue' => ['version'=>OpportunityMaturity::VERSION, 'stages'=>OpportunityMaturity::STAGES,
|
||||
'legacyVersion'=>OpportunityMaturity::LEGACY, 'legacyLabels'=>OpportunityMaturity::LEGACY_LABELS]];
|
||||
@@ -245,6 +257,8 @@ class InvestmentCatalogue
|
||||
$result['zones'] = app(InvestmentZones::class)->links()->join('investment_item_opportunities as m', 'm.item_id', '=', 'zl.item_id')
|
||||
->join('investment_zones as z', 'z.id', '=', 'zl.zone_id')->where('m.opportunity_id', $id)
|
||||
->get(['z.id', 'z.name', 'z.category', 'zl.association_type', 'zl.source_reference', 'zl.valid_from', 'zl.valid_until']);
|
||||
$opportunity = Opportunity::findOrFail($id);
|
||||
$result['classification'] = $management ? [] : app(OpportunityClassification::class)->publicRows($opportunity);
|
||||
$result['primary_territory_path'] = app(InvestmentGeography::class)->path(DB::table('opportunities')->where('id', $id)->value('primary_territory_id'));
|
||||
$result['opportunity_locations'] = app(InvestmentRelations::class)->opportunityLocations($id, $management);
|
||||
$result['source_evidence'] = app(InvestmentTerritorialTraceability::class)->sources('opportunities', $id);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\CrmTask;
|
||||
use App\Models\LandAssistanceCase;
|
||||
use App\Models\SimulationFormDraft;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -92,6 +93,7 @@ final class InvestorPath
|
||||
'detail' => $detail, 'preparation_allowed' => $value !== 'no',
|
||||
'action_gaps' => []];
|
||||
}
|
||||
$steps = app(FintechInvestment::class)->adjustSteps($payload, $steps);
|
||||
$byCode = collect($steps)->keyBy('code');
|
||||
foreach ($steps as &$step) {
|
||||
foreach ($step['dependencies'] as $action => $dependencies) {
|
||||
@@ -126,15 +128,17 @@ final class InvestorPath
|
||||
$next = collect($steps)->first(fn ($step) => $step['preparation_allowed'] && ! in_array($step['state'], ['completed', 'approved', 'waiting_external', 'submitted', 'reviewing'], true));
|
||||
|
||||
$landCase = (int) $case->user_id === $actor->id
|
||||
? \App\Models\LandAssistanceCase::where('user_id', $actor->id)->latest('updated_at')->get()
|
||||
? LandAssistanceCase::where('user_id', $actor->id)->latest('updated_at')->get()
|
||||
->first(fn ($land) => ($land->payload['investor_path_case_id'] ?? null) === $id) : null;
|
||||
|
||||
return ['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'] ?? [],
|
||||
'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['code']] : null,
|
||||
'results' => $results, 'requests' => $requests, 'documents' => $documents,
|
||||
'sector_contexts' => ($owner || $manager) ? ($path['sector_contexts'] ?? []) : [],
|
||||
'content_sources' => ($owner || $manager) ? ($path['content_sources'] ?? []) : [],
|
||||
'tasks' => DB::table('tasks')->where('desk_case_id', $id)
|
||||
->whereNull('deleted_at')
|
||||
@@ -182,6 +186,7 @@ final class InvestorPath
|
||||
$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'];
|
||||
abort_if($state === 'completed' && ($step['fintech_review_required'] ?? false), 422, 'Os pressupostos Fintech desta revisão mudaram; preserve a preparação e atualize a conferência antes da conclusão.');
|
||||
$internal = in_array($state, ['reviewing', 'correction_required'], true);
|
||||
$external = in_array($state, ['approved', 'rejected', 'expired'], true);
|
||||
$scope = 'investor_preparation';
|
||||
@@ -210,7 +215,7 @@ final class InvestorPath
|
||||
if ($state === 'completed' && in_array($code, ['S07', 'S08', 'S10', 'S11', 'S14', 'S15', 'S17', 'S18'], true)) {
|
||||
abort_unless(($step['saved_state'] ?? '') === 'approved' && in_array($data['action'], ['execute', 'operate'], true), 422, 'Conclusão operacional exige acto externo documentado; use preparação enquanto aguarda.');
|
||||
}
|
||||
$detail = [...$data, 'scope' => $scope, 'actor_id' => $actor->id, 'recorded_at' => now()->toIso8601String()];
|
||||
$detail = [...$data, '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),
|
||||
'status' => in_array($state, ['completed', 'approved'], true) ? 'completed' : ($state === 'not_started' ? 'pending' : 'active'),
|
||||
'version_no' => $step['version'] + 1, 'updated_at' => now()]);
|
||||
|
||||
@@ -18,6 +18,11 @@ final class LegacyContent
|
||||
{
|
||||
public function available(): bool
|
||||
{
|
||||
// Explicit delivery gate; document publication and access checks remain independent.
|
||||
if (config('portal.legacy_content_enabled', false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! config('portal.legacy_content_qa_enabled') || ! app()->environment('testing')
|
||||
|| config('database.connections.pgsql.host') !== '127.0.0.1'
|
||||
|| config('database.connections.pgsql.url') || (int) config('database.connections.pgsql.port') !== 55441) {
|
||||
@@ -164,6 +169,10 @@ final class LegacyContent
|
||||
$payload = $desk->decode($case->payload);
|
||||
foreach ($payload['investor_path']['content_sources'] ?? [] as $existing) {
|
||||
if ($existing['resource_id'] === $article['id'] && $existing['sha256'] === $article['sha256']) {
|
||||
if ($article['sector']) {
|
||||
app(SectorInvestment::class)->attach($actor, $caseId, ['version' => $data['version'], 'sector_slug' => $article['sector']['slug']]);
|
||||
}
|
||||
|
||||
return; // Same source/version replay: neither another reference nor another event.
|
||||
}
|
||||
}
|
||||
@@ -174,6 +183,9 @@ final class LegacyContent
|
||||
'saved_at' => now()->toIso8601String()];
|
||||
DB::table('desk_cases')->where('id', $caseId)->update(['payload' => $desk->encode($payload), 'version' => $case->version + 1, 'updated_at' => now()]);
|
||||
$desk->event($desk->case($actor, $caseId), $actor, 'legacy_content_referenced', ['resource_id' => $article['id'], 'sha256' => $article['sha256']]);
|
||||
if ($article['sector']) {
|
||||
app(SectorInvestment::class)->attach($actor, $caseId, ['version' => $case->version + 1, 'sector_slug' => $article['sector']['slug']]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ class OpportunityCanonicalContract
|
||||
}
|
||||
$schema = app(OpportunityCategoryFields::class)->enrich($schema);
|
||||
$schema = app(OpportunityModularProfiles::class)->extend($schema);
|
||||
$schema = app(OpportunityClassification::class)->extend($schema);
|
||||
$schema = $this->writeSchema($schema, $draft);
|
||||
$properties = &$schema['$defs']['opportunityCreate']['properties'];
|
||||
unset($properties['mutation_context']); // Actor, audit reason and revision are server-owned.
|
||||
@@ -213,6 +214,9 @@ class OpportunityCanonicalContract
|
||||
*/
|
||||
private function schemaData(mixed $value, array $node, array $defs): mixed
|
||||
{
|
||||
if (($node['x-investmoz-classification'] ?? false) && is_array($value)) {
|
||||
$node = isset($value['classification']) ? $defs['relationCreate'] : ['type' => 'object'];
|
||||
}
|
||||
if (isset($node['$ref'])) {
|
||||
$name = basename($node['$ref']);
|
||||
$node = $defs[$name] ?? $node;
|
||||
@@ -543,6 +547,7 @@ class OpportunityCanonicalContract
|
||||
|
||||
return ['version' => self::VERSION, 'modularProfiles' => app(OpportunityModularProfiles::class)->enabled() ? OpportunityModularProfiles::PROFILES : [],
|
||||
'historyVersion' => app(OpportunityModularProfiles::class)->enabled() ? OpportunityModularProfiles::HISTORY_VERSION : null,
|
||||
'classification' => app(OpportunityClassification::class)->options(),
|
||||
'schema' => $this->schema(true)['$defs']['opportunityCreate'],
|
||||
'definitions' => $this->schema(true)['$defs'],
|
||||
'submissionTextLimits' => ['demand_statement' => array_intersect_key($submissionProperties['demand_statement'], array_flip(['minLength', 'maxLength']))],
|
||||
|
||||
@@ -39,6 +39,7 @@ class OpportunityCanonicalResponse
|
||||
} catch (HttpExceptionInterface $failure) {
|
||||
$errors = ['canonical.resources' => ['Recurso indisponível para validação; estado HTTP '.$failure->getStatusCode().'. Preserve o original e resolva a operação afetada.']];
|
||||
}
|
||||
$data['classification'] = app(OpportunityClassification::class)->listing($actor, $record);
|
||||
$data['validation_result'] = ['errors' => $errors, 'warnings' => [], 'rule' => OpportunityCanonicalContract::VERSION,
|
||||
'evaluated_at' => now()->toIso8601String(), 'persisted_submission_hash' => $context['submission']['hash'] ?? null,
|
||||
'external_decision' => 'not_inferred'];
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Http\Controllers\InvestmentPortfolioController;
|
||||
use App\Models\Opportunity;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
/** Additive adapter over canonical relations. Never creates master data or inferred pivots. */
|
||||
class OpportunityClassification
|
||||
{
|
||||
public const VERSION = 'classification-relations-20261015-v1';
|
||||
|
||||
public const DIMENSIONS = ['territory' => 'Enquadramento territorial', 'production' => 'Organização produtiva', 'regulation' => 'Regime regulatório', 'activity' => 'Atividade económica'];
|
||||
|
||||
public const TARGETS = [
|
||||
'corridor' => ['development_corridors', 'name', 'territory'],
|
||||
'location' => ['geo_locations', 'name', 'territory'],
|
||||
'cluster' => ['economic_clusters', 'name', 'production'],
|
||||
'project' => ['projects', 'name', 'production'],
|
||||
'chain' => ['value_chains', 'name', 'production'],
|
||||
'park' => ['investment_zones', 'name', 'production'],
|
||||
'zone' => ['investment_zones', 'name', 'regulation'],
|
||||
'sector' => ['sectors', 'name', 'activity'],
|
||||
'activity' => ['economic_activities', 'label_pt_mz', 'activity'],
|
||||
];
|
||||
|
||||
public const PURPOSES = ['location' => 'Localização', 'coverage' => 'Abrangência documentada', 'proximity' => 'Proximidade, sem pertença', 'administrative_boundary' => 'Limite administrativo', 'parcel' => 'Parcela referenciada',
|
||||
'connectivity' => 'Conectividade e fluxos', 'productive_complementarity' => 'Complementaridade produtiva', 'specialization' => 'Especialização do cluster', 'anchor' => 'Projeto âncora documentado',
|
||||
'zone_location' => 'Localização na zona', 'regime_recognition' => 'Reconhecimento do regime', 'enterprise_admission' => 'Admissão do empreendimento', 'specific_benefit' => 'Benefício específico', 'park_operation' => 'Operação do parque',
|
||||
'financing_need' => 'Necessidade de financiamento', 'payments' => 'Pagamentos', 'risk_management' => 'Gestão de riscos', 'financial_instrument' => 'Instrumento financeiro',
|
||||
'logistics_service' => 'Serviço logístico', 'physical_asset' => 'Ativo físico/capacidade', 'economic_activity' => 'Atividade económica', 'production_stage' => 'Etapa da cadeia produtiva'];
|
||||
|
||||
public const STATES = ['draft', 'preliminary', 'in_validation', 'confirmed', 'rejected', 'archived', 'revoked'];
|
||||
|
||||
public const EXTERNAL = ['not_assessed', 'pending', 'documented_granted', 'documented_denied', 'expired'];
|
||||
|
||||
public function extend(array $schema): array
|
||||
{
|
||||
$fields = ['target_type' => ['type' => 'string', 'enum' => array_keys(self::TARGETS)],
|
||||
'purpose' => ['type' => 'string', 'enum' => array_keys(self::PURPOSES)],
|
||||
'criteria' => ['type' => 'string', 'maxLength' => 2000], 'justification' => ['type' => 'string', 'maxLength' => 4000],
|
||||
'source_reference' => ['type' => 'string', 'maxLength' => 2000], 'citation' => ['type' => 'string', 'maxLength' => 1000],
|
||||
'document_id' => ['type' => ['string', 'null'], 'format' => 'uuid'],
|
||||
'authority_id' => ['type' => ['string', 'null'], 'format' => 'uuid'],
|
||||
'requested_state' => ['type' => 'string', 'enum' => ['draft', 'preliminary', 'in_validation']],
|
||||
'disclosure' => ['type' => 'string', 'enum' => ['restricted', 'public']],
|
||||
'valid_from' => ['type' => ['string', 'null'], 'format' => 'date'], 'valid_until' => ['type' => ['string', 'null'], 'format' => 'date'],
|
||||
'external_status' => ['type' => 'string', 'enum' => self::EXTERNAL],
|
||||
'external_act_reference' => ['type' => 'string', 'maxLength' => 2000],
|
||||
'production_stage' => ['type' => 'string', 'maxLength' => 250],
|
||||
];
|
||||
// Same collection for every approved modality; old untyped relations remain valid.
|
||||
$schema['$defs']['relationCreate']['properties']['classification'] = ['type' => 'object', 'additionalProperties' => false, 'properties' => $fields];
|
||||
$schema['$defs']['relation']['properties']['classification'] = ['type' => 'object', 'additionalProperties' => false, 'properties' => $fields];
|
||||
foreach (['opportunity', 'opportunityCreate'] as $name) {
|
||||
$schema['$defs'][$name]['properties']['relations'] ??= ['type' => 'array', 'items' => ['$ref' => '#/$defs/relation']];
|
||||
$schema['$defs'][$name]['properties']['enterprise_size'] = ['type' => ['string', 'null'], 'maxLength' => 120];
|
||||
}
|
||||
// The extracted Create had generic objects here. Type only the new adapter;
|
||||
// pre-existing relation shapes remain accepted without recertification.
|
||||
$schema['$defs']['opportunityCreate']['properties']['relations']['items'] = ['x-investmoz-classification' => true, 'anyOf' => [
|
||||
['type' => 'object', 'not' => ['required' => ['classification']]],
|
||||
['$ref' => '#/$defs/relationCreate'],
|
||||
]];
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/** Only consultable targets: a promoter's draft permission is not access to private master data. */
|
||||
public function targets(string $kind): \Illuminate\Database\Query\Builder
|
||||
{
|
||||
abort_unless(isset(self::TARGETS[$kind]), 422);
|
||||
[$table] = self::TARGETS[$kind];
|
||||
$query = DB::table($table);
|
||||
if (in_array($kind, ['sector', 'activity'], true)) {
|
||||
return $kind === 'sector' ? $query->whereNull('deleted_at')->where('is_active', true) : $query->where('status', 'published');
|
||||
}
|
||||
$query->whereNull('deleted_at');
|
||||
if ($kind === 'chain') {
|
||||
$query->whereIn('cluster_id', $this->targets('cluster')->select('id'));
|
||||
}
|
||||
if ($kind === 'location') {
|
||||
$query->whereIn('id', app(InvestmentGeography::class)->publicReferences()->select('id'));
|
||||
}
|
||||
if (in_array($kind, ['zone', 'park'], true)) {
|
||||
return $query->whereIn('id', app(InvestmentZones::class)->visible()->select('id'))->when($kind === 'park', fn ($q) => $q->where('category', 'industrial_park'));
|
||||
}
|
||||
if (in_array($kind, ['project', 'cluster', 'corridor'], true)) {
|
||||
$foreign = ['project' => 'project_id', 'cluster' => 'cluster_id', 'corridor' => 'corridor_id'][$kind];
|
||||
|
||||
return $query->where(fn ($q) => $q->where('data_classification', 'public')->orWhereIn('id', InvestmentPortfolioController::visible()->whereNotNull($foreign)->select($foreign)));
|
||||
}
|
||||
|
||||
return $query->where('data_classification', 'public');
|
||||
}
|
||||
|
||||
public function options(): array
|
||||
{
|
||||
$targets = [];
|
||||
foreach (self::TARGETS as $kind => [$table, $label, $dimension]) {
|
||||
$targets[$kind] = $this->targets($kind)->orderBy($label)->get(['id', $label.' as label']);
|
||||
}
|
||||
|
||||
return ['version' => self::VERSION, 'dimensions' => self::DIMENSIONS, 'types' => array_map(fn ($v) => $v[2], self::TARGETS), 'purposes' => self::PURPOSES, 'states' => self::STATES, 'externalStates' => self::EXTERNAL, 'targets' => $targets];
|
||||
}
|
||||
|
||||
public function validate(array $payload, Opportunity $record): void
|
||||
{
|
||||
$seen = [];
|
||||
foreach ($payload['relations'] ?? [] as $i => $row) {
|
||||
if (! isset($row['classification'])) {
|
||||
continue;
|
||||
}
|
||||
$c = $row['classification'];
|
||||
$prefix = 'canonical.relations.'.$i;
|
||||
$fail = fn ($key, $message) => throw ValidationException::withMessages([$prefix.'.'.$key => $message]);
|
||||
$allowed = ['target_type', 'purpose', 'criteria', 'justification', 'source_reference', 'citation', 'document_id', 'authority_id', 'requested_state', 'disclosure', 'valid_from', 'valid_until', 'external_status', 'external_act_reference', 'production_stage'];
|
||||
if (array_diff(array_keys($c), $allowed)) {
|
||||
$fail('classification', 'Campo de certificação ou metadado não permitido. A decisão é registada pelo revisor autorizado.');
|
||||
}
|
||||
$validator = Validator::make($c, [
|
||||
'target_type' => 'required|in:'.implode(',', array_keys(self::TARGETS)), 'purpose' => 'required|in:'.implode(',', array_keys(self::PURPOSES)),
|
||||
'requested_state' => 'sometimes|in:draft,preliminary,in_validation', 'disclosure' => 'sometimes|in:restricted,public',
|
||||
'external_status' => 'sometimes|in:'.implode(',', self::EXTERNAL),
|
||||
'criteria' => 'sometimes|nullable|string|max:2000', 'justification' => 'sometimes|nullable|string|max:4000',
|
||||
'source_reference' => 'sometimes|nullable|string|max:2000', 'citation' => 'sometimes|nullable|string|max:1000',
|
||||
'document_id' => 'sometimes|nullable|uuid', 'authority_id' => 'sometimes|nullable|uuid',
|
||||
'valid_from' => 'sometimes|nullable|date_format:Y-m-d', 'valid_until' => 'sometimes|nullable|date_format:Y-m-d',
|
||||
'external_act_reference' => 'sometimes|nullable|string|max:2000', 'production_stage' => 'sometimes|nullable|string|max:250',
|
||||
]);
|
||||
if ($validator->fails()) {
|
||||
throw ValidationException::withMessages(collect($validator->errors()->messages())->mapWithKeys(fn ($v, $k) => [$prefix.'.classification.'.$k => $v])->all());
|
||||
}
|
||||
$kind = $c['target_type'] ?? '';
|
||||
$id = (string) ($row['related_id'] ?? '');
|
||||
if (($kind === 'sector' && ! ctype_digit($id)) || ($kind !== 'sector' && ! Str::isUuid($id))) {
|
||||
$fail('related_id', 'Identificador de referência inválido.');
|
||||
}
|
||||
if (! isset(self::TARGETS[$kind]) || ! $this->targets($kind)->where('id', (string) ($row['related_id'] ?? ''))->exists()) {
|
||||
$fail('related_id', 'Selecione uma referência existente e consultável; nenhum cadastro é criado por esta relação.');
|
||||
}
|
||||
$purpose = $c['purpose'] ?? '';
|
||||
if (! isset(self::PURPOSES[$purpose])) {
|
||||
$fail('classification.purpose', 'Indique a finalidade da relação.');
|
||||
}
|
||||
if (in_array($purpose, ['regime_recognition', 'enterprise_admission', 'specific_benefit'], true) && $kind !== 'zone') {
|
||||
$fail('classification.purpose', 'Regime, admissão e benefício usam a relação regulatória com a zona, separada da ficha física do parque.');
|
||||
}
|
||||
$identity = self::TARGETS[$kind][0].':'.$row['related_id'].':'.$purpose;
|
||||
if (isset($seen[$identity])) {
|
||||
$fail('related_id', 'Esta referência e finalidade já estão associadas. Recupere a relação existente.');
|
||||
}
|
||||
$seen[$identity] = true;
|
||||
if (! empty($c['valid_from']) && ! empty($c['valid_until']) && $c['valid_until'] < $c['valid_from']) {
|
||||
$fail('classification.valid_until', 'O fim da vigência precede o início.');
|
||||
}
|
||||
if (! empty($c['document_id']) && ! DB::table('opportunity_documents')->where('id', $c['document_id'])->where('opportunity_id', $record->id)->whereNull('deleted_at')->exists()) {
|
||||
$fail('classification.document_id', 'Documento deve pertencer aos anexos desta oportunidade.');
|
||||
}
|
||||
if (! empty($c['authority_id']) && ! DB::table('authorities')->where('id', $c['authority_id'])->where('status', 'published')->exists()) {
|
||||
$fail('classification.authority_id', 'Entidade competente não consta do catálogo publicado.');
|
||||
}
|
||||
if (($c['external_status'] ?? '') === 'documented_granted' && (empty($c['document_id']) || empty(trim($c['external_act_reference'] ?? '')))) {
|
||||
$fail('classification.external_act_reference', 'Um ato declarado como concedido exige documento e referência próprios; a associação não concede o direito.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function hash(array $row): string
|
||||
{
|
||||
// Client identity/status cannot certify a relation. Object-order normalization is reused.
|
||||
return OpportunityCanonicalValue::hash($row);
|
||||
}
|
||||
|
||||
public function canReview(User $actor, Opportunity $record, string $dimension): bool
|
||||
{
|
||||
$access = app(PortalProfileAccess::class);
|
||||
$responsibility = $dimension === 'regulation' ? 'legal_reviewer' : 'technical_reviewer';
|
||||
|
||||
return $access->canView($actor, $record) && $access->scoped($actor, 'validator', $record->organization_id, $record->opportunity_category)
|
||||
&& ! $access->conflict($actor, $record) && $access->operational($actor, 'validate', $record->id) && $access->mfa($actor)
|
||||
&& collect($access->grants($actor, 'validator'))->contains(fn ($g) => in_array($record->opportunity_category, json_decode($g->opportunity_types, true), true)
|
||||
&& ($g->organization_id === null || $g->organization_id === $record->organization_id) && in_array($responsibility, json_decode($g->responsibilities, true), true));
|
||||
}
|
||||
|
||||
public function state(Opportunity $record, array $row): string
|
||||
{
|
||||
$decision = $record->workflow_context['classification_decisions'][$this->hash($row)] ?? null;
|
||||
if ($decision && $decision['state'] !== 'confirmed') {
|
||||
return $decision['state'];
|
||||
}
|
||||
if ($decision) {
|
||||
$reviewer = User::find($decision['actor_id']);
|
||||
$c = $row['classification'];
|
||||
if (! empty($c['document_id']) && ($decision['evidence_hash'] ?? '') !== $this->evidenceHash($row)) {
|
||||
return 'in_validation';
|
||||
}
|
||||
// Current grants/conflicts still apply; reading a public page never requires the reviewer's browser session.
|
||||
$access = app(PortalProfileAccess::class);
|
||||
$responsibility = self::TARGETS[$c['target_type']][2] === 'regulation' ? 'legal_reviewer' : 'technical_reviewer';
|
||||
$responsible = $reviewer && collect($access->grants($reviewer, 'validator'))->contains(fn ($g) => ($g->organization_id === null || $g->organization_id === $record->organization_id)
|
||||
&& in_array($record->opportunity_category, json_decode($g->opportunity_types, true), true) && in_array($responsibility, json_decode($g->responsibilities, true), true));
|
||||
if ($responsible && ! $access->conflict($reviewer, $record)) {
|
||||
return 'confirmed';
|
||||
}
|
||||
|
||||
return 'in_validation';
|
||||
}
|
||||
|
||||
return $row['classification']['requested_state'] ?? 'preliminary';
|
||||
}
|
||||
|
||||
private function evidenceHash(array $row): ?string
|
||||
{
|
||||
$id = $row['classification']['document_id'] ?? null;
|
||||
if (! $id) {
|
||||
return null;
|
||||
}
|
||||
$resource = DB::table('opportunity_documents as r')->join('documents as d', 'd.id', '=', 'r.document_id')->where('r.id', $id)
|
||||
->first(['r.id', 'r.version', 'r.deleted_at', 'd.sha256']);
|
||||
|
||||
return OpportunityCanonicalValue::hash($resource ? (array) $resource : ['unavailable' => $id]);
|
||||
}
|
||||
|
||||
public function listing(User $actor, Opportunity $record): array
|
||||
{
|
||||
app(PortalProfileAccess::class)->authorize($actor, 'view', $record);
|
||||
$rows = app(OpportunityManagement::class)->values($record)['canonical']['relations'] ?? [];
|
||||
$rows = array_values(array_filter($rows, fn ($row) => isset($row['classification'])));
|
||||
|
||||
return array_map(function ($row) use ($record, $actor) {
|
||||
$kind = $row['classification']['target_type'];
|
||||
$dimension = self::TARGETS[$kind][2];
|
||||
$metadata = $record->workflow_context['canonical_items'] ?? [];
|
||||
$prior = [];
|
||||
foreach ($metadata['deleted'] ?? [] as $item) {
|
||||
$old = $item['last_value'] ?? [];
|
||||
if (isset($old['classification']) && ($old['related_id'] ?? null) === $row['related_id'] && ($old['classification']['target_type'] ?? null) === $kind
|
||||
&& ($old['classification']['purpose'] ?? null) === $row['classification']['purpose'] && $this->hash($old) !== $this->hash($row)) {
|
||||
$prior[] = ['metadata' => array_diff_key($item, ['last_value' => true]), 'history' => $record->workflow_context['classification_decisions'][$this->hash($old)]['history'] ?? [], 'relation' => $old];
|
||||
}
|
||||
}
|
||||
|
||||
return ['hash' => $this->hash($row), 'dimension' => $dimension, 'relation' => $row, 'state' => $this->state($record, $row),
|
||||
'metadata' => collect($metadata['active'] ?? [])->first(fn ($m) => ($m['fingerprint'] ?? '') === $this->hash($row)), 'previous_versions' => $prior,
|
||||
'can_review' => $this->canReview($actor, $record, $dimension), 'history' => $record->workflow_context['classification_decisions'][$this->hash($row)]['history'] ?? []];
|
||||
}, $rows);
|
||||
}
|
||||
|
||||
public function review(User $actor, Opportunity $record, array $input): Opportunity
|
||||
{
|
||||
$data = Validator::make($input, ['etag' => 'required|string|size:64', 'hash' => 'required|string|size:64', 'state' => 'required|in:in_validation,confirmed,rejected,archived,revoked', 'reason' => 'required|string|min:20|max:1000'])->validate();
|
||||
|
||||
return DB::transaction(function () use ($actor, $record, $data) {
|
||||
$record = Opportunity::whereKey($record->id)->lockForUpdate()->firstOrFail();
|
||||
abort_if($record->status === 'archived', 409, 'Oportunidade arquivada; preserve o histórico e use o workflow aprovado.');
|
||||
$access = app(PortalProfileAccess::class);
|
||||
$access->authorize($actor, 'view', $record);
|
||||
abort_unless(hash_equals(app(OpportunityManagement::class)->etag($record), $data['etag']), 409, 'A oportunidade mudou. Atualize antes de decidir; o rascunho permanece guardado.');
|
||||
$rows = app(OpportunityManagement::class)->values($record)['canonical']['relations'] ?? [];
|
||||
// A revocation also reaches a previously published version after a draft correction.
|
||||
if (in_array($data['state'], ['revoked', 'archived'], true)) {
|
||||
$rows = [...$rows, ...($record->workflow_context['publication']['classification'] ?? [])];
|
||||
}
|
||||
$row = collect($rows)->first(fn ($r) => isset($r['classification']) && $this->hash($r) === $data['hash']);
|
||||
abort_unless($row, 409, 'Associação inexistente nesta versão.');
|
||||
$c = $row['classification'];
|
||||
abort_unless($this->canReview($actor, $record, self::TARGETS[$c['target_type']][2]), 403, 'Revisão exige âmbito, responsabilidade, MFA e independência aprovados.');
|
||||
if ($data['state'] === 'confirmed') {
|
||||
foreach (['criteria', 'justification', 'source_reference', 'citation'] as $key) {
|
||||
abort_if(empty(trim($c[$key] ?? '')), 422, 'Confirmação exige critérios, justificação, fonte e citação por associação. A preparação pode continuar como preliminar.');
|
||||
}
|
||||
$this->validate(['relations' => [$row]], $record);
|
||||
}
|
||||
$context = $record->workflow_context ?? [];
|
||||
$before = $context['classification_decisions'][$data['hash']] ?? null;
|
||||
$decision = ['state' => $data['state'], 'actor_id' => $actor->id, 'at' => now()->toIso8601String(), 'reason' => $data['reason'], 'evidence_hash' => $this->evidenceHash($row), 'version' => ($before['version'] ?? 0) + 1];
|
||||
$context['classification_decisions'][$data['hash']] = [...$decision, 'history' => [...($before['history'] ?? []), $decision]];
|
||||
$record->workflow_context = $context;
|
||||
$record->management_version++;
|
||||
$record->save();
|
||||
$access->audit($actor, 'classification_'.$data['state'], ['record_id' => $record->id, 'relation_hash' => $data['hash'], 'before' => $before, 'after' => $decision]);
|
||||
|
||||
return $record;
|
||||
});
|
||||
}
|
||||
|
||||
/** Frozen at the existing editorial publication, not on draft save or association confirmation. */
|
||||
public function publication(array $payload): array
|
||||
{
|
||||
return array_values(array_filter($payload['relations'] ?? [], fn ($r) => isset($r['classification']) && ($r['classification']['disclosure'] ?? 'restricted') === 'public'));
|
||||
}
|
||||
|
||||
public function publicRows(Opportunity $record): array
|
||||
{
|
||||
if ($record->trashed() || $record->status !== 'published' || ! $record->published_at || $record->published_at->isFuture() || ($record->workflow_context['publication']['visibility'] ?? '') !== 'public') {
|
||||
return [];
|
||||
}
|
||||
$rows = [];
|
||||
foreach ($record->workflow_context['publication']['classification'] ?? [] as $row) {
|
||||
$c = $row['classification'];
|
||||
$kind = $c['target_type'];
|
||||
if (! isset(self::TARGETS[$kind]) || ($c['disclosure'] ?? '') !== 'public') {
|
||||
continue;
|
||||
}
|
||||
$target = $this->targets($kind)->where('id', $row['related_id'])->first();
|
||||
if (! $target || (! empty($c['valid_from']) && $c['valid_from'] > today()->toDateString()) || (! empty($c['valid_until']) && $c['valid_until'] < today()->toDateString())) {
|
||||
continue;
|
||||
}
|
||||
$state = $this->state($record, $row);
|
||||
if (in_array($state, ['archived', 'revoked'], true)) {
|
||||
continue;
|
||||
}
|
||||
// Original documents, internal rationale, actor IDs and decision history stay private.
|
||||
$rows[] = ['dimension' => self::TARGETS[$kind][2], 'target_type' => $kind, 'target_id' => (string) $row['related_id'], 'label' => $target->{self::TARGETS[$kind][1]},
|
||||
'purpose' => $c['purpose'], 'purpose_label' => self::PURPOSES[$c['purpose']], 'target_code' => $target->code ?? null, 'catalog_version' => $target->catalog_version_id ?? null,
|
||||
'physical_category' => $target->physical_category ?? null, 'legal_regime' => $target->legal_regime ?? null,
|
||||
'state' => $state, 'source_reference' => $c['source_reference'] ?? null, 'citation' => $c['citation'] ?? null,
|
||||
'authority_id' => $c['authority_id'] ?? null, 'external_status' => $c['external_status'] ?? 'not_assessed', 'availability_confirmed' => false,
|
||||
'production_stage' => $c['production_stage'] ?? null, 'valid_from' => $c['valid_from'] ?? null, 'valid_until' => $c['valid_until'] ?? null];
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/** Same public projection for count/list/map; AND across filters, OR across selected associations. */
|
||||
public function constrain(Builder $query, array $filters): void
|
||||
{
|
||||
$keys = ['association_type', 'association_target', 'association_state', 'association_purpose', 'authority_id', 'chain_id', 'subsector_id'];
|
||||
if (! array_filter(array_intersect_key($filters, array_flip($keys)), fn ($v) => $v !== null && $v !== '')) {
|
||||
return;
|
||||
}
|
||||
// Query candidates in bounded chunks to apply the exact visibility/decision rules used by detail.
|
||||
// IDs only, no private payload leaves this service. A future indexed projection is an optimization, not another catalogue.
|
||||
$ids = [];
|
||||
(clone $query)->reorder()->select('opportunities.*')->chunkById(200, function ($records) use (&$ids, $filters) {
|
||||
foreach ($records as $record) {
|
||||
$rows = $this->publicRows($record);
|
||||
$main = array_filter(array_intersect_key($filters, array_flip(['association_type', 'association_target', 'association_state', 'association_purpose'])), fn ($v) => $v !== null && $v !== '');
|
||||
$matches = $main === [] || collect($rows)->contains(function ($r) use ($main) {
|
||||
foreach (['association_type' => 'target_type', 'association_target' => 'target_id', 'association_state' => 'state', 'association_purpose' => 'purpose'] as $filter => $field) {
|
||||
if (isset($main[$filter]) && ($r[$field] ?? null) !== $main[$filter]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
if (! empty($filters['chain_id'])) {
|
||||
$matches = $matches && collect($rows)->contains(fn ($r) => $r['target_type'] === 'chain' && $r['target_id'] === $filters['chain_id']);
|
||||
}
|
||||
if (! empty($filters['authority_id'])) {
|
||||
$matches = $matches && collect($rows)->contains(fn ($r) => $r['authority_id'] === $filters['authority_id']);
|
||||
}
|
||||
if (! empty($filters['subsector_id'])) {
|
||||
$matches = $matches && (($record->workflow_context['publication']['taxonomy']['subsector_id'] ?? '') === $filters['subsector_id'] || collect($rows)->contains(fn ($r) => $r['target_type'] === 'activity' && $r['target_id'] === $filters['subsector_id']));
|
||||
}
|
||||
if ($matches) {
|
||||
$ids[] = $record->id;
|
||||
}
|
||||
}
|
||||
}, 'opportunities.id', 'id');
|
||||
$query->whereIn('opportunities.id', $ids);
|
||||
}
|
||||
|
||||
public function duplicates(User $actor, Opportunity $record): array
|
||||
{
|
||||
app(PortalProfileAccess::class)->authorize($actor, 'view', $record);
|
||||
// Exact-title candidates only within the actor's existing visibility; never merge or reveal another dossier.
|
||||
return app(PortalProfileAccess::class)->scope(Opportunity::query(), $actor)->whereKeyNot($record->id)
|
||||
->whereRaw('lower(trim(title))=lower(trim(?))', [$record->title])->limit(10)->get(['id', 'reference', 'title'])
|
||||
->map(fn ($r) => ['id' => $r->id, 'reference' => $r->reference, 'reason' => 'Título exato normalizado; identidade do negócio por determinar. Nenhuma fusão executada.'])->all();
|
||||
}
|
||||
}
|
||||
@@ -130,6 +130,7 @@ class OpportunityManagement
|
||||
if (array_key_exists('canonical', $changes)) {
|
||||
$previous = $record->exists ? $this->values($record) : [];
|
||||
$changes['canonical'] = [...($previous['canonical'] ?? []), ...$changes['canonical']];
|
||||
app(OpportunityClassification::class)->validate($changes['canonical'], $record);
|
||||
if (($changes['canonical']['opportunity_category'] ?? ($changes['opportunity_category'] ?? $record->opportunity_category)) !== ($changes['opportunity_category'] ?? $record->opportunity_category)) {
|
||||
throw ValidationException::withMessages(['canonical.opportunity_category' => 'Contrato e registo devem usar a mesma categoria.']);
|
||||
}
|
||||
|
||||
@@ -332,7 +332,9 @@ class OpportunityProfileWorkflow
|
||||
'catalogue_version' => $context['publication']['maturity']['catalogue_version'] ?? null]];
|
||||
}
|
||||
$context['publication'] = [...$decision, 'hash' => $snapshot['hash'], 'visibility' => $p['visibility'],
|
||||
'public_fields' => ['title', 'summary', 'description', 'sector_id', 'province', 'district']];
|
||||
'public_fields' => ['title', 'summary', 'description', 'sector_id', 'province', 'district'],
|
||||
'classification' => app(OpportunityClassification::class)->publication($p),
|
||||
'taxonomy' => array_intersect_key($p, array_flip(['subsector_id', 'economic_activity_id']))];
|
||||
// Minimal public projection; contacts, valuations, evidence and originals remain private.
|
||||
$projection = $this->contract->publicProjection($p);
|
||||
$record->title = $projection['title'];
|
||||
|
||||
@@ -16,7 +16,7 @@ class PortalProfileAccess
|
||||
/** @return list<string> */
|
||||
public static function fingerprintFiles(): array
|
||||
{
|
||||
return [__FILE__, app_path('Services/OpportunityContacts.php'), resource_path('js/components/opportunity-contact-form.tsx'), app_path('Services/PortalInternalDesignation.php'), app_path('Models/User.php'), app_path('Models/Opportunity.php'), config_path('portal.php'), base_path('routes/web.php'),
|
||||
return [__FILE__, app_path('Services/OpportunityClassification.php'), app_path('Http/Controllers/OpportunityClassificationController.php'), resource_path('js/components/opportunity-classification.tsx'), app_path('Services/OpportunityContacts.php'), resource_path('js/components/opportunity-contact-form.tsx'), app_path('Services/PortalInternalDesignation.php'), app_path('Models/User.php'), app_path('Models/Opportunity.php'), config_path('portal.php'), base_path('routes/web.php'),
|
||||
app_path('Http/Middleware/HandleInertiaRequests.php'), app_path('Services/OpportunityManagement.php'),
|
||||
app_path('Services/OpportunityResources.php'), app_path('Services/OpportunityImageProcessor.php'), app_path('Services/VerifiedDocumentBinary.php'),
|
||||
app_path('Services/PortalProfileAdministration.php'), app_path('Services/PortalSuperusers.php'),
|
||||
@@ -39,7 +39,7 @@ class PortalProfileAccess
|
||||
resource_path('js/pages/dashboard.tsx'), resource_path('js/pages/PortalInvestidor.tsx'),
|
||||
resource_path('js/layouts/portal-navigation.tsx'), resource_path('js/components/interactive-investment-map.tsx'),
|
||||
resource_path('js/components/simulation-form.tsx'), resource_path('js/lib/simulation-form.ts'), app_path('Services/LegacyContent.php'),
|
||||
resource_path('js/components/ui/sidebar.tsx'), resource_path('js/components/simulation-financial-tools.tsx'), resource_path('js/components/simulation-cashflow-planner.tsx'), resource_path('js/pages/investor-path/show.tsx'), resource_path('views/app.blade.php'),
|
||||
resource_path('js/components/ui/sidebar.tsx'), resource_path('js/components/simulation-financial-tools.tsx'), resource_path('js/components/simulation-cashflow-planner.tsx'), resource_path('js/pages/investor-path/show.tsx'), resource_path('views/app.blade.php'), resource_path('views/profiles/creation-unavailable.blade.php'),
|
||||
resource_path('js/pages/management/opportunity-resources.tsx'),
|
||||
app_path('Services/PortalProfileInstallation.php'), app_path('Http/Controllers/PortalProfileInstallationController.php'), config_path('portal_profiles.php'), resource_path('js/pages/profiles/installation.tsx')];
|
||||
}
|
||||
@@ -162,6 +162,14 @@ class PortalProfileAccess
|
||||
return true;
|
||||
}
|
||||
|
||||
// Normal Promotor authority comes from its existing scope, not from the
|
||||
// Superutilizador membership. Other/extraneous actions retain elevation.
|
||||
if (in_array($action, ['view', 'edit'], true) && $recordId !== null) {
|
||||
$record = Opportunity::withTrashed()->find($recordId);
|
||||
if ($record && $record->owner_user_id !== null && $this->promoterRecordScope($actor, $record)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (! $this->mfa($actor)) {
|
||||
return false;
|
||||
}
|
||||
@@ -178,7 +186,8 @@ class PortalProfileAccess
|
||||
{
|
||||
$included = in_array($type, OpportunityCanonicalContract::BASE_CATEGORIES, true) || app(OpportunityModularProfiles::class)->enabled();
|
||||
|
||||
return $included && $this->available() && $this->scoped($actor, 'promoter', $organization, $type) && $this->operational($actor, 'create');
|
||||
// This is creation as an authorized Promotor, never an exceptional SU act.
|
||||
return $included && $this->available() && $this->scoped($actor, 'promoter', $organization, $type) && ! $this->has($actor, 'auditor');
|
||||
}
|
||||
|
||||
public function legacyWriteAllowed(User $actor): bool
|
||||
@@ -275,7 +284,30 @@ class PortalProfileAccess
|
||||
->where('scope->action', 'view')->whereNotNull('approved_by')->whereNull('consumed_at')->where('expires_at', '>', now())
|
||||
->get()->filter(fn ($row) => $this->operational($actor, 'view', json_decode($row->scope, true)['record_id'] ?? null))
|
||||
->map(fn ($row) => json_decode($row->scope, true)['record_id'])->all();
|
||||
$query->whereIn('id', $ids);
|
||||
$query->where(function ($eligible) use ($ids, $actor) {
|
||||
$eligible->whereIn('id', $ids);
|
||||
if ($this->has($actor, 'auditor')) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->grants($actor, 'promoter') as $grant) {
|
||||
$internal = $grant->source === 'internal-portal-designation';
|
||||
if (($internal && app(PortalInternalDesignation::class)->organization($grant->organization_id) === null)
|
||||
|| (! $internal && ! $this->represents($actor, $grant->organization_id))) {
|
||||
continue;
|
||||
}
|
||||
$eligible->orWhere(function ($normal) use ($actor, $grant, $internal) {
|
||||
$normal->whereNotNull('owner_user_id')->whereIn('opportunity_category', json_decode($grant->opportunity_types, true));
|
||||
if ($internal) {
|
||||
$normal->where(fn ($q) => $q->where('owner_user_id', $actor->id)->orWhereJsonContains('workflow_context->contributors', $actor->id))
|
||||
->where('workflow_context->operator_organization_id', $grant->organization_id);
|
||||
} elseif ($grant->organization_id !== null) {
|
||||
$normal->where('organization_id', $grant->organization_id);
|
||||
} else {
|
||||
$normal->whereNull('organization_id')->where('owner_user_id', $actor->id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return $query->where(function ($scope) use ($actor) {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Http\Controllers\InvestmentPortfolioController;
|
||||
use App\Models\Opportunity;
|
||||
use App\Models\Sector;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
/** Entry adapter over existing sector, opportunity, portfolio and private dossier records. */
|
||||
final class SectorInvestment
|
||||
{
|
||||
// Editorial bridges, not renamed masters or automatic opportunity classifications.
|
||||
public const CONTENT = [
|
||||
'mineracao' => ['mineracao', 'energia-mineracao'], 'energia-especifica' => ['energia', 'energia-mineracao'],
|
||||
'agronegocio' => ['agronegocio'], 'turismo' => ['turismo'], 'infraestruturas' => ['infraestruturas'],
|
||||
'tecnologias-de-informacao' => ['tech-fintech'], 'mercado-financeiro' => ['tech-fintech'],
|
||||
'fintech' => ['tech-fintech'], 'imobiliario' => ['imobiliario'],
|
||||
'bens-de-consumo-e-franquias' => ['bens-de-consumo-franquias'],
|
||||
];
|
||||
|
||||
public function sector(string $slug): Sector
|
||||
{
|
||||
return Sector::where('slug', $slug)->where('is_active', true)->firstOrFail();
|
||||
}
|
||||
|
||||
public function context(string $slug): array
|
||||
{
|
||||
$sector = $this->sector($slug);
|
||||
|
||||
return [...$sector->only(['id', 'name', 'slug']), 'href' => '/sectores/'.$sector->slug];
|
||||
}
|
||||
|
||||
public function publicView(Sector $sector): array
|
||||
{
|
||||
$query = Opportunity::published()->where('sector_id', $sector->id);
|
||||
$articles = [];
|
||||
if (app(LegacyContent::class)->available()) {
|
||||
foreach (self::CONTENT[$sector->slug] ?? [] as $slug) {
|
||||
try {
|
||||
$a = app(LegacyContent::class)->article($slug);
|
||||
$articles[] = ['title' => $a['title'], 'href' => $a['href'], 'image' => $a['image'], 'sha256' => $a['sha256'], 'scope' => $slug === 'tech-fintech' && $sector->slug !== 'fintech' ? 'Especialização Fintech; não representa todo o setor.' : 'Conteúdo educativo relacionado; não é uma oportunidade concreta.'];
|
||||
} catch (HttpException $e) {
|
||||
if ($e->getStatusCode() !== 404) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$relations = [];
|
||||
foreach (['projects' => 'project_id', 'clusters' => 'cluster_id', 'corridors' => 'corridor_id'] as $table => $foreign) {
|
||||
$ids = DB::table('opportunity_'.$table)->whereIn('opportunity_id', (clone $query)->select('id'))->pluck($foreign);
|
||||
foreach (InvestmentPortfolioController::visible()->whereIn($foreign, $ids)->orderBy('title')->get() as $dossier) {
|
||||
$relations[] = ['id' => $dossier->id, 'title' => $dossier->title, 'href' => '/carteira/'.$dossier->id, 'kind' => $table,
|
||||
'basis' => 'Associação cadastrada entre uma oportunidade pública deste setor e esta ficha publicada.', 'source' => $dossier->source];
|
||||
}
|
||||
}
|
||||
$locations = [];
|
||||
foreach ((clone $query)->orderBy('id')->get(['id', 'title', 'slug']) as $opportunity) {
|
||||
foreach (app(InvestmentRelations::class)->opportunityLocations($opportunity->id) as $location) {
|
||||
$locations[] = ['opportunity_title' => $opportunity->title, 'href' => '/oportunidades/'.$opportunity->slug, 'location' => $location];
|
||||
}
|
||||
}
|
||||
|
||||
return ['articles' => $articles, 'relations' => collect($relations)->unique('id')->values()->all(), 'locations' => $locations,
|
||||
'start_href' => app(InvestorPath::class)->available() ? '/investimentos/a-partir-do-setor/'.$sector->slug : null,
|
||||
'start_notice' => app(InvestorPath::class)->available() ? null : 'O percurso para guardar a ideia está temporariamente indisponível. A consulta e o apoio continuam disponíveis.',
|
||||
'register_href' => app(PortalProfileAccess::class)->available() ? '/minhas-oportunidades/create?sector_id='.$sector->id : null,
|
||||
'register_notice' => app(PortalProfileAccess::class)->available() ? null : 'O cadastro por perfis está temporariamente indisponível; pode preparar a ideia e contactar o apoio.',
|
||||
'specialization_href' => in_array($sector->slug, ['tecnologias-de-informacao', 'mercado-financeiro'], true) ? '/sectores/fintech' : null,
|
||||
'content_notice' => $sector->slug === 'mercado-financeiro' ? 'O artigo geral de Mercado Financeiro permanece vazio e não foi publicado. A preparação de negócios neste setor está disponível.' : null];
|
||||
}
|
||||
|
||||
public function attach(User $actor, string $id, array $input): void
|
||||
{
|
||||
$data = Validator::make($input, ['version' => 'required|integer|min:1', 'sector_slug' => 'required|string|max:150'])->validate();
|
||||
$context = $this->context($data['sector_slug']);
|
||||
abort_unless(app(InvestorPath::class)->available(), 404);
|
||||
DB::transaction(function () use ($actor, $id, $data, $context) {
|
||||
$desk = app(VirtualDesk::class);
|
||||
$case = $desk->case($actor, $id, true, true);
|
||||
abort_if($case->closed_at, 409, 'O dossier está encerrado.');
|
||||
abort_unless(DB::table('investor_journeys')->where('id', $case->journey_id)->whereNotNull('path_definition_id')->whereNull('deleted_at')->exists(), 409, 'Este dossier conserva outro roteiro.');
|
||||
$payload = $desk->decode($case->payload);
|
||||
foreach ($payload['investor_path']['sector_contexts'] ?? [] as $existing) {
|
||||
if ($existing['id'] === $context['id']) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
abort_unless((int) $case->version === $data['version'], 409, 'O dossier foi alterado; recupere a versão atual.');
|
||||
$payload['investor_path']['sector_contexts'][] = [...$context, 'actor_id' => $actor->id, 'saved_at' => now()->toIso8601String()];
|
||||
DB::table('desk_cases')->where('id', $id)->update(['payload' => $desk->encode($payload), 'version' => $case->version + 1, 'updated_at' => now()]);
|
||||
$desk->event($desk->case($actor, $id), $actor, 'sector_context_referenced', ['sector_id' => $context['id'], 'sector_slug' => $context['slug']]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,9 @@
|
||||
// Route/identity mapping over the existing library. Bodies and originals remain in documents.
|
||||
return [
|
||||
'groups' => [
|
||||
'fintech' => ['root' => 'tech-fintech', 'label' => 'Fintech', 'heading' => 'Explorar Fintech'],
|
||||
'imobiliario' => ['root' => 'imobiliario', 'label' => 'Imobiliário', 'heading' => 'Explorar Imobiliário'],
|
||||
'bens-de-consumo-e-franquias' => ['root' => 'bens-de-consumo-franquias', 'label' => 'Bens de Consumo e Franquias', 'heading' => 'Explorar Bens de Consumo e Franquias'],
|
||||
'agronegocio' => ['root' => 'agronegocio', 'label' => 'Agronegócio', 'heading' => 'Investir no agronegócio'],
|
||||
'energia-mineracao' => ['root' => 'energia-mineracao', 'label' => 'Energia e Mineração', 'heading' => 'Explorar Energia e Mineração'],
|
||||
'turismo' => ['root' => 'turismo', 'label' => 'Turismo', 'heading' => 'Explorar Turismo'],
|
||||
@@ -10,6 +13,9 @@ return [
|
||||
'mercado-financeiro' => ['root' => 'mercado-financeiro', 'label' => 'Mercado Financeiro', 'heading' => 'Explorar Mercado Financeiro'],
|
||||
],
|
||||
'articles' => [
|
||||
'tech-fintech' => ['external_id' => 'legacy-tempo-post-173209-20260623', 'source_url' => 'https://investemoz.tempo.co.mz/tech-fintech', 'group' => 'fintech', 'sector_slug' => 'fintech', 'publishable' => true],
|
||||
'imobiliario' => ['external_id' => 'legacy-tempo-post-173218-20260616', 'source_url' => 'https://investemoz.tempo.co.mz/imobiliario', 'group' => 'imobiliario', 'sector_slug' => 'imobiliario', 'publishable' => true],
|
||||
'bens-de-consumo-franquias' => ['external_id' => 'legacy-tempo-post-173213-20260616', 'source_url' => 'https://investemoz.tempo.co.mz/bens-de-consumo-franquias', 'group' => 'bens-de-consumo-e-franquias', 'sector_slug' => 'bens-de-consumo-e-franquias', 'publishable' => true],
|
||||
'agronegocio' => ['external_id' => 'legacy-tempo-post-171985-20260420', 'source_url' => 'https://investemoz.tempo.co.mz/agronegocio', 'group' => 'agronegocio', 'sector_slug' => 'agronegocio', 'publishable' => true],
|
||||
'energia-mineracao' => ['external_id' => 'legacy-tempo-post-171981-20260430', 'source_url' => 'https://investemoz.tempo.co.mz/energia-mineracao', 'group' => 'energia-mineracao', 'sector_slug' => 'energia', 'publishable' => true],
|
||||
'energia' => ['external_id' => 'legacy-tempo-post-172679-20260430', 'source_url' => 'https://investemoz.tempo.co.mz/energia/', 'group' => 'energia-mineracao', 'sector_slug' => 'energia-especifica', 'publishable' => true],
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
return [
|
||||
'organization_country_enabled' => env('PORTAL_ORGANIZATION_COUNTRY_ENABLED', false),
|
||||
'legacy_content_enabled' => env('PORTAL_LEGACY_CONTENT_ENABLED', false),
|
||||
'legacy_content_qa_enabled' => env('PORTAL_LEGACY_CONTENT_QA_ENABLED', false),
|
||||
'profile_access_enabled' => (bool) env('PORTAL_PROFILE_ACCESS_ENABLED', false),
|
||||
// Prepare and audit assignments without opening operational opportunity routes.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"openapi": "3.0.3",
|
||||
"info": {
|
||||
"title": "InvestMoz — descoberta e manifestações",
|
||||
"version": "1.0.0",
|
||||
"description": "Contrato local 27/09/2026. Sessão web Laravel, email verificado e CSRF; não usa bearer independente. Accept: application/json. Respostas privadas no-store. Estados de atendimento: received,in_review,contacted,closed. API pública usa throttle api da aplicação; limites específicos indicados por operação. O middleware Laravel 13 aceita origem same-origin comprovada ou token CSRF válido; clientes devem enviar o token. Pedidos cross-site sem token são recusados. Pesquisa, referências, sugestão, mapa, comparação, exportação e favoritos partilham 60 pedidos/minuto por IP."
|
||||
"version": "1.1.0-QA-classification",
|
||||
"description": "Contrato local 27/09/2026. Sessão web Laravel, email verificado e CSRF; não usa bearer independente. Accept: application/json. Respostas privadas no-store. Estados de atendimento: received,in_review,contacted,closed. API pública usa throttle api da aplicação; limites específicos indicados por operação. O middleware Laravel 13 aceita origem same-origin comprovada ou token CSRF válido; clientes devem enviar o token. Pedidos cross-site sem token são recusados. Pesquisa, referências, sugestão, mapa, comparação, exportação e favoritos partilham 60 pedidos/minuto por IP. Delta 15/10/2026: classificação multidimensional preparada apenas em QA; as novas operações e parâmetros abaixo identificados por x-qa-only NÃO estão ativos por esta documentação."
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
@@ -207,7 +207,12 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["MZN", "USD", "EUR", "ZAR"]
|
||||
"enum": [
|
||||
"MZN",
|
||||
"USD",
|
||||
"EUR",
|
||||
"ZAR"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -281,7 +286,12 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["cluster", "corridor", "zee", "zfi"]
|
||||
"enum": [
|
||||
"cluster",
|
||||
"corridor",
|
||||
"zee",
|
||||
"zfi"
|
||||
]
|
||||
},
|
||||
"description": "Require a visible association in the selected dimension, preserving other filters."
|
||||
},
|
||||
@@ -290,12 +300,137 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["grid", "list", "map", "combined"]
|
||||
"enum": [
|
||||
"grid",
|
||||
"list",
|
||||
"map",
|
||||
"combined"
|
||||
]
|
||||
},
|
||||
"description": "Presentation state retained in URL; does not alter permission checks."
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_type",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"corridor",
|
||||
"location",
|
||||
"cluster",
|
||||
"project",
|
||||
"chain",
|
||||
"park",
|
||||
"zone",
|
||||
"sector",
|
||||
"activity"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_target",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"maxLength": 80
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_state",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"preliminary",
|
||||
"in_validation",
|
||||
"confirmed",
|
||||
"rejected",
|
||||
"archived",
|
||||
"revoked"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_purpose",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "authority_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "chain_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "subsector_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "category",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"investment_project",
|
||||
"real_estate",
|
||||
"land_rights",
|
||||
"business_sale",
|
||||
"business_partnership",
|
||||
"franchise",
|
||||
"concession",
|
||||
"financing",
|
||||
"supply",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "publication_state",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"published"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
}
|
||||
],
|
||||
"description": "Min/max exigem currency; max >= min. Sem câmbio. Facetas: facets[]=1&facets[]=2. Ordenação monetária agrupada por moeda."
|
||||
"description": "Min/max exigem currency; max >= min. Sem câmbio. Facetas: facets[]=1&facets[]=2. Ordenação monetária agrupada por moeda. Novos filtros QA: AND entre critérios; tipo/alvo/estado/finalidade na mesma associação; cadeia, atividade e entidade podem constar de outras relações da mesma oportunidade. Somente projeção editorial pública e alvos consultáveis. Map matched_count usa a mesma consulta. Filtros antigos dos pivôs continuam a representar vínculos anteriores, sem conversão automática."
|
||||
}
|
||||
},
|
||||
"/references": {
|
||||
@@ -711,7 +846,12 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["MZN", "USD", "EUR", "ZAR"]
|
||||
"enum": [
|
||||
"MZN",
|
||||
"USD",
|
||||
"EUR",
|
||||
"ZAR"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -785,7 +925,12 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["cluster", "corridor", "zee", "zfi"]
|
||||
"enum": [
|
||||
"cluster",
|
||||
"corridor",
|
||||
"zee",
|
||||
"zfi"
|
||||
]
|
||||
},
|
||||
"description": "Require a visible association in the selected dimension, preserving other filters."
|
||||
},
|
||||
@@ -794,11 +939,137 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["grid", "list", "map", "combined"]
|
||||
"enum": [
|
||||
"grid",
|
||||
"list",
|
||||
"map",
|
||||
"combined"
|
||||
]
|
||||
},
|
||||
"description": "Presentation state retained in URL; does not alter permission checks."
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_type",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"corridor",
|
||||
"location",
|
||||
"cluster",
|
||||
"project",
|
||||
"chain",
|
||||
"park",
|
||||
"zone",
|
||||
"sector",
|
||||
"activity"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_target",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"maxLength": 80
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_state",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"preliminary",
|
||||
"in_validation",
|
||||
"confirmed",
|
||||
"rejected",
|
||||
"archived",
|
||||
"revoked"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_purpose",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "authority_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "chain_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "subsector_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "category",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"investment_project",
|
||||
"real_estate",
|
||||
"land_rights",
|
||||
"business_sale",
|
||||
"business_partnership",
|
||||
"franchise",
|
||||
"concession",
|
||||
"financing",
|
||||
"supply",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "publication_state",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"published"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": " Novos filtros QA: AND entre critérios; tipo/alvo/estado/finalidade na mesma associação; cadeia, atividade e entidade podem constar de outras relações da mesma oportunidade. Somente projeção editorial pública e alvos consultáveis. Map matched_count usa a mesma consulta. Filtros antigos dos pivôs continuam a representar vínculos anteriores, sem conversão automática."
|
||||
}
|
||||
},
|
||||
"/map": {
|
||||
@@ -996,7 +1267,12 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["MZN", "USD", "EUR", "ZAR"]
|
||||
"enum": [
|
||||
"MZN",
|
||||
"USD",
|
||||
"EUR",
|
||||
"ZAR"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1070,7 +1346,12 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["cluster", "corridor", "zee", "zfi"]
|
||||
"enum": [
|
||||
"cluster",
|
||||
"corridor",
|
||||
"zee",
|
||||
"zfi"
|
||||
]
|
||||
},
|
||||
"description": "Require a visible association in the selected dimension, preserving other filters."
|
||||
},
|
||||
@@ -1079,11 +1360,137 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["grid", "list", "map", "combined"]
|
||||
"enum": [
|
||||
"grid",
|
||||
"list",
|
||||
"map",
|
||||
"combined"
|
||||
]
|
||||
},
|
||||
"description": "Presentation state retained in URL; does not alter permission checks."
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_type",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"corridor",
|
||||
"location",
|
||||
"cluster",
|
||||
"project",
|
||||
"chain",
|
||||
"park",
|
||||
"zone",
|
||||
"sector",
|
||||
"activity"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_target",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"maxLength": 80
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_state",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"preliminary",
|
||||
"in_validation",
|
||||
"confirmed",
|
||||
"rejected",
|
||||
"archived",
|
||||
"revoked"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_purpose",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "authority_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "chain_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "subsector_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "category",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"investment_project",
|
||||
"real_estate",
|
||||
"land_rights",
|
||||
"business_sale",
|
||||
"business_partnership",
|
||||
"franchise",
|
||||
"concession",
|
||||
"financing",
|
||||
"supply",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "publication_state",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"published"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": " Novos filtros QA: AND entre critérios; tipo/alvo/estado/finalidade na mesma associação; cadeia, atividade e entidade podem constar de outras relações da mesma oportunidade. Somente projeção editorial pública e alvos consultáveis. Map matched_count usa a mesma consulta. Filtros antigos dos pivôs continuam a representar vínculos anteriores, sem conversão automática."
|
||||
}
|
||||
},
|
||||
"/compare": {
|
||||
@@ -1393,7 +1800,12 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["MZN", "USD", "EUR", "ZAR"]
|
||||
"enum": [
|
||||
"MZN",
|
||||
"USD",
|
||||
"EUR",
|
||||
"ZAR"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1467,7 +1879,12 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["cluster", "corridor", "zee", "zfi"]
|
||||
"enum": [
|
||||
"cluster",
|
||||
"corridor",
|
||||
"zee",
|
||||
"zfi"
|
||||
]
|
||||
},
|
||||
"description": "Require a visible association in the selected dimension, preserving other filters."
|
||||
},
|
||||
@@ -1476,11 +1893,137 @@
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": ["grid", "list", "map", "combined"]
|
||||
"enum": [
|
||||
"grid",
|
||||
"list",
|
||||
"map",
|
||||
"combined"
|
||||
]
|
||||
},
|
||||
"description": "Presentation state retained in URL; does not alter permission checks."
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_type",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"corridor",
|
||||
"location",
|
||||
"cluster",
|
||||
"project",
|
||||
"chain",
|
||||
"park",
|
||||
"zone",
|
||||
"sector",
|
||||
"activity"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_target",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"maxLength": 80
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_state",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"preliminary",
|
||||
"in_validation",
|
||||
"confirmed",
|
||||
"rejected",
|
||||
"archived",
|
||||
"revoked"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "association_purpose",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "authority_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "chain_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "subsector_id",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "category",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"investment_project",
|
||||
"real_estate",
|
||||
"land_rights",
|
||||
"business_sale",
|
||||
"business_partnership",
|
||||
"franchise",
|
||||
"concession",
|
||||
"financing",
|
||||
"supply",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "publication_state",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"published"
|
||||
]
|
||||
},
|
||||
"x-qa-only": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": " Novos filtros QA: AND entre critérios; tipo/alvo/estado/finalidade na mesma associação; cadeia, atividade e entidade podem constar de outras relações da mesma oportunidade. Somente projeção editorial pública e alvos consultáveis. Map matched_count usa a mesma consulta. Filtros antigos dos pivôs continuam a representar vínculos anteriores, sem conversão automática."
|
||||
}
|
||||
},
|
||||
"/favourites/{id}": {
|
||||
@@ -1600,7 +2143,9 @@
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["saved"]
|
||||
"required": [
|
||||
"saved"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2423,7 +2968,10 @@
|
||||
"description": "PDF/TXT até 10 MiB; máximo dez anexos."
|
||||
}
|
||||
},
|
||||
"required": ["version", "file"]
|
||||
"required": [
|
||||
"version",
|
||||
"file"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3584,7 +4132,10 @@
|
||||
"maxLength": 5000
|
||||
}
|
||||
},
|
||||
"required": ["client_key", "body"]
|
||||
"required": [
|
||||
"client_key",
|
||||
"body"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3847,7 +4398,9 @@
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": ["status"],
|
||||
"required": [
|
||||
"status"
|
||||
],
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
@@ -3955,6 +4508,135 @@
|
||||
},
|
||||
"description": "Exige manage-portal. Alteração transaccional com auditoria. Repetir o mesmo estado não cria outra notificação."
|
||||
}
|
||||
},
|
||||
"/minhas-oportunidades/{id}/classification": {
|
||||
"servers": [
|
||||
{
|
||||
"url": "/"
|
||||
}
|
||||
],
|
||||
"get": {
|
||||
"x-qa-only": true,
|
||||
"summary": "Recuperar associações, metadados e versões anteriores autorizadas",
|
||||
"description": "Sessão web Laravel verificada; autorização view do mesmo cadastro. Resposta Cache-Control private,no-store. Sem novo papel. Candidatos a duplicação limitados ao âmbito já autorizado e a título exato; nenhuma fusão.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Sucesso"
|
||||
},
|
||||
"401": {
|
||||
"description": "Sessão necessária"
|
||||
},
|
||||
"403": {
|
||||
"description": "Âmbito, responsabilidade, MFA ou independência insuficientes"
|
||||
},
|
||||
"404": {
|
||||
"description": "Registo inexistente"
|
||||
},
|
||||
"409": {
|
||||
"description": "Versão ou associação mudou"
|
||||
},
|
||||
"422": {
|
||||
"description": "Campos ou fundamento insuficientes"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/minhas-oportunidades/{id}/classification/review": {
|
||||
"servers": [
|
||||
{
|
||||
"url": "/"
|
||||
}
|
||||
],
|
||||
"post": {
|
||||
"x-qa-only": true,
|
||||
"summary": "Decidir confirmação de uma associação, sem transição editorial",
|
||||
"description": "Validador no âmbito da oportunidade; technical_reviewer ou legal_reviewer para dimensão regulatória, MFA efetiva e independência já aprovados. CSRF. Um 200 não publica a relação nem concede ato externo. Hash da relação e versão documental vinculam a decisão. Versão anterior publicada pode ser revogada após correção privada.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"etag",
|
||||
"hash",
|
||||
"state",
|
||||
"reason"
|
||||
],
|
||||
"properties": {
|
||||
"etag": {
|
||||
"type": "string",
|
||||
"minLength": 64,
|
||||
"maxLength": 64
|
||||
},
|
||||
"hash": {
|
||||
"type": "string",
|
||||
"minLength": 64,
|
||||
"maxLength": 64
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"in_validation",
|
||||
"confirmed",
|
||||
"rejected",
|
||||
"archived",
|
||||
"revoked"
|
||||
]
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"minLength": 20,
|
||||
"maxLength": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Sucesso"
|
||||
},
|
||||
"401": {
|
||||
"description": "Sessão necessária"
|
||||
},
|
||||
"403": {
|
||||
"description": "Âmbito, responsabilidade, MFA ou independência insuficientes"
|
||||
},
|
||||
"404": {
|
||||
"description": "Registo inexistente"
|
||||
},
|
||||
"409": {
|
||||
"description": "Versão ou associação mudou"
|
||||
},
|
||||
"422": {
|
||||
"description": "Campos ou fundamento insuficientes"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
@@ -4164,7 +4846,10 @@
|
||||
},
|
||||
"Draft": {
|
||||
"type": "object",
|
||||
"required": ["version", "payload"],
|
||||
"required": [
|
||||
"version",
|
||||
"payload"
|
||||
],
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "integer",
|
||||
@@ -4185,7 +4870,11 @@
|
||||
"Need": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["category_id", "option_id", "details"],
|
||||
"required": [
|
||||
"category_id",
|
||||
"option_id",
|
||||
"details"
|
||||
],
|
||||
"properties": {
|
||||
"category_id": {
|
||||
"type": "integer"
|
||||
@@ -4215,7 +4904,9 @@
|
||||
"details": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["description"],
|
||||
"required": [
|
||||
"description"
|
||||
],
|
||||
"properties": {
|
||||
"description": {
|
||||
"type": "string",
|
||||
@@ -4373,7 +5064,11 @@
|
||||
},
|
||||
"ContextInput": {
|
||||
"type": "object",
|
||||
"required": ["version", "is_education", "source_reference"],
|
||||
"required": [
|
||||
"version",
|
||||
"is_education",
|
||||
"source_reference"
|
||||
],
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "integer",
|
||||
@@ -4649,11 +5344,15 @@
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["FeatureCollection"]
|
||||
"enum": [
|
||||
"FeatureCollection"
|
||||
]
|
||||
},
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"enum": [1000]
|
||||
"enum": [
|
||||
1000
|
||||
]
|
||||
},
|
||||
"features": {
|
||||
"type": "array",
|
||||
@@ -4662,14 +5361,18 @@
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["Feature"]
|
||||
"enum": [
|
||||
"Feature"
|
||||
]
|
||||
},
|
||||
"geometry": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["Point"]
|
||||
"enum": [
|
||||
"Point"
|
||||
]
|
||||
},
|
||||
"coordinates": {
|
||||
"type": "array",
|
||||
@@ -4735,7 +5438,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["version", "payload"]
|
||||
"required": [
|
||||
"version",
|
||||
"payload"
|
||||
]
|
||||
},
|
||||
"CompanyDeclaration": {
|
||||
"type": "object",
|
||||
@@ -4765,11 +5471,18 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "country", "role"],
|
||||
"required": [
|
||||
"name",
|
||||
"country",
|
||||
"role"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["version", "payload"]
|
||||
"required": [
|
||||
"version",
|
||||
"payload"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2245,3 +2245,185 @@ A Tempo autorizou `B-final-fabf722bc8c6` com C137 e as limitações documentadas
|
||||
Backup/restauro fresco às 15:09:24 UTC: 295 tabelas, 31 sequências e 815 ficheiros. Comparação posterior por leitura confirma os dados de negócio anteriores preservados; acréscimos esperados: migration, definição e auditoria; variações técnicas de sessão/cache. COUNTRY02, demais configurações, serviços e DevTools preservados. Os 12 critérios aceites não foram repetidos. Mantêm-se as limitações aceites: linha 07 documental; C137 sem aceitação visual específica; estado intermédio sustentado por código/provas anteriores.
|
||||
|
||||
Resultado e recibo: `outputs/investmoz-audit-current-20261012/B-ativacao-concluida-20261015/`. ZIP das provas SHA-256 `bacefba6d72c3f36d8630ffc02e58f02fded3e71a44e71d4cddd6fc1a799cf83`. Candidata e suplemento imutáveis novamente verificados. Reversão conforme procedimento aprovado, preservando dados posteriores. Esta nota atualiza somente esta entrega; as restantes pendências da matriz mantêm-se.
|
||||
|
||||
|
||||
## 15/10/2026 — manifesto mínimo e mapa QA do legado agronegócio
|
||||
|
||||
Preparação autorizada nos mesmos AUD-LEG-01–07/AUD-LIB-01–02. Pacote em `outputs/investmoz-orientacao-legado-agronegocio-20261015/`: dois originais com hashes/versões/condições de divulgação; inventário integral referenciado; importação privada e publicação autenticada separadas; patch exato de dois ficheiros e flag editorial própria OFF por defeito; mapa de disponibilização/reversão sem migrations. Candidata ensaiada apenas em processo QA READ ONLY: 10 verificações dirigidas passaram; webroots QA/ativo não alterados.
|
||||
|
||||
Destino tem setor agronegócio ativo e serviço project-preparation v5; piloto tem v3, com definição semanticamente idêntica, conferida por leitura. Resolver versão local por código; não transportar UUID QA. Referências territoriais são menções editoriais/links de consulta, sem associação automática a projeto/geometria. Restam integração/HTTP do delta em QA, conferência operacional do lote e pacote final: 2–4 h estimadas por lacuna. Nenhuma importação, publicação, pedido ou alteração ativa executada. B e os 12 critérios mantêm-se encerrados; não se promove o estado global dos requisitos por esta preparação.
|
||||
|
||||
|
||||
Preparacao QA legado: ficha, pacote e recibo disponibilizados na pagina privada https://chatgpt.com/space/page_89da203a58148191bb44876b84a6751f. Candidata instalada somente na QA18445, com copia privada dos dois ficheiros e configuracao anteriores; artigo anonimo observado, autenticacao solicitada ao iniciar/continuar. Sem importacoes/publicacoes ou alteracoes ativas. Prova: outputs/investmoz-orientacao-legado-agronegocio-20261015/INSTALACAO-SOMENTE-QA.json. Observacao autenticada em curso; nao marcar percurso completo como aceite antes do resultado.
|
||||
|
||||
|
||||
## 15/10/2026 — candidata legado instalada e trecho observado em QA
|
||||
|
||||
Consulta pública anónima, login/MFA ao continuar e recuperação da referência no mesmo dossier agronegócio observados na QA18445. Preparação de apoio criou um único rascunho 2ead554a-bcf0-4865-8936-41311ce7d6a0, sem protocolo/submissão, ligado ao dossier b3e162da-0f9e-4ed4-8e66-c1febcb8504b. SQL READ ONLY confirmou vínculo, estado draft e serviço project-preparation v3 existente localmente. A v3/UUID QA não foi transportada ao destino; v5 ativa preservada, definição equivalente previamente conferida.
|
||||
|
||||
Dois ficheiros candidatos e gate instalados somente em QA; backups privados anteriores preservados. Zero importações/publicações de conteúdo, nenhum novo dossier e hashes ativos inalterados. Provas e suplemento em outputs/investmoz-orientacao-legado-agronegocio-20261015; anexos iniciais e suplemento na página privada dedicada. 2–4 h mantidas como estimativa de referência; B encerrada e ativação separada. Apenas o delta foi observado; não promover cobertura integral de AUD-LEG/LIB por este piloto.
|
||||
|
||||
|
||||
## 15/10/2026 — consolidação final do piloto legado para decisão
|
||||
|
||||
Suplemento incorporado em outputs/investmoz-orientacao-legado-consolidado-20261015. Instalação QA, login/continuidade/contexto/rascunho de apoio demonstrados; não continuam na estimativa. Restante exclusivamente operacional e dependente de autorização ativa: baseline/backup fresco 30–60 min; dois ficheiros/gate OFF 15–30 min; importação privada/scan/metadados 30–60 min; publicação autenticada/habilitação/recibo 15–30 min. Total 1h30–3h, mais espera variável; substitui 2–4h.
|
||||
|
||||
Mapa fechado para dois ficheiros, artigo e imagem; publicação na biblioteca expõe recursos mesmo com gate OFF, exigindo retirada própria na reversão. Proposta única à Tempo e recibo consolidados, histórico anterior preservado por hashes. Tempo leu textos, não inspecionou ZIPs; verificação local não é atribuída ao responsável. Sem repetição de ensaios, sem alteração ativa e sem reabertura B. IDs AUD-LEG-01–07/AUD-LIB-01–02 mantidos; sem novo backlog nem promoção global de cobertura.
|
||||
|
||||
|
||||
15/10/2026 — correção documental do mapa consolidado: rótulos Agronegócio e Pemba–Lichinga em UTF-8. Mapa, manifesto, recibo e pacote renovados; versões anteriores preservadas. Ficha/proposta/fontes inalteradas; zero novos testes ou alterações ativas. Decisão de disponibilização continua pendente da Tempo. Novo SHA-256 do mapa: `56abf71d9a7e26d431a2d42bb53698ae80c4e884486f8cf85cac72e8f8f4cfb8`; pacote: `c059d1f8eb6d3b5658b6692b46a1d7fc7bc13b265c66bc48ab61a12e3d9e26f3`.
|
||||
|
||||
|
||||
## 15/10/2026 — piloto autorizado; execução retida antes de alterar o ativo
|
||||
|
||||
A Tempo autorizou o piloto conforme recibo atualizado c059d1f8…; autorização preservada. Preflight READ ONLY e preview confirmaram ambos os originais ausentes, hashes exatos, ClamAV disponível, B ON/leitor OFF. Foi detetada uma omissão operacional: ImportDocumentBatch.php:58–68 recusa --apply fora de QA; não foi localizado o mecanismo autenticado ativo referido pelo erro. Upload autenticado não grava external_id exigido pelo leitor. Nenhum contorno executado.
|
||||
|
||||
Ajuste necessário excede os dois ficheiros autorizados: admitir no importador somente este manifesto/hashes com autorização específica, ator real e backup fresco, preservando bloqueio dos outros lotes e publicação separada. Proposta delimitada em outputs/investmoz-legado-ativacao-20261015/IMPEDIMENTO-IMPORTACAO.md. Nenhuma entrega/importação/publicação/flag ativa efetuada; B encerrada. Backup fresco adiado até execução efetiva, após solução do mecanismo.
|
||||
|
||||
|
||||
## 15/10/2026 — delta do importador corrigido e demonstrado em QA
|
||||
|
||||
Correção QA já cabia na resolução autorizada dos impedimentos; pedido anterior de autorização QA foi desnecessário. Candidata ImportDocumentBatch.php com opção nominal --pilot-agronegocio, manifesto exato, duas entradas/hashes, conta existente/permissão efetiva e recibo de backup/restauro fresco para apply ativo. Outros lotes ativos mantêm bloqueio. Dependência omitida registada: guarda QA do apply não fora conferida no procedimento.
|
||||
|
||||
39 verificações dirigidas passaram na base isolada legacy_import_delta_20261015_test:55441: preview sem escrita; recusas de manifesto/caminho/hashes/atores; duas importações privadas; replay sem duplicações ou alterações; scan real clean; recuperação de identidades pelo leitor apenas em projeção de elegibilidade revertida. Zero publicação persistente, zero alterações ativas; percurso funcional e B não repetidos.
|
||||
|
||||
Manifesto e reversão atualizados para três ficheiros; delta/provas/recibo em outputs/investmoz-legado-importador-delta-QA-20261015. Autorização anterior do piloto preservada; decisão pendente só para extensão ativa do terceiro ficheiro. Atribuição CLI não é descrita como login/MFA; publicação autenticada separada. Não alegar backup real com o fixture do teste de validação.
|
||||
|
||||
|
||||
## 15/10/2026 — piloto agronegócio disponibilizado, operação encerrada
|
||||
|
||||
A Tempo confirmou a extensão do importador; autorização inicial e âmbito exclusivo do piloto preservados. Backup/restauro fresco 18:49:57 UTC+02:00: 295 tabelas/31 sequências/996 ficheiros iguais. Três fontes entregues, build preservado e manutenção terminada. Importação nominal de dois originais ausentes como privados; scan real clean nos hashes autorizados. Metadados e publicação autenticada por Osmane Nala: imagem #6 e artigo #5, ambos v3; leitor habilitado só depois.
|
||||
|
||||
Artigo/entrada/imagem públicos responderam HTTP200 anónimo, sem contorno TLS; hash público da imagem igual ao original. Comparação READ ONLY confirmou todos os registos de negócio anteriores preservados; acréscimos limitados aos dois recursos, scans/revisões/auditoria e variação técnica da sessão. B/Country02/serviços e apoio v5 preservados; nenhum novo dossier/pedido, migration ou importação/publicação do restante legado. Percurso funcional e 12 critérios não repetidos. Evidências e reversão real em outputs/investmoz-legado-ativacao-20261015; pacote final e recibo anexados na página privada. Apenas esta entrega é encerrada; requisitos globais AUD-LEG-01–07/AUD-LIB-01–02 conservam as restantes pendências por consumidor/acervo.
|
||||
|
||||
|
||||
## 15/10/2026 — fecho do piloto na matriz e recorte dos restantes setores
|
||||
|
||||
AUD-LEG-03 encerrado como piloto ativo; nove linhas AUD-LEG-01–07/AUD-LIB-01–02 reconciliadas para distinguir piloto entregue de integração integral pendente. Mesmos 3401 IDs, restantes linhas byte a byte preservadas. Sem repetir aceitação nem alterar o ativo/B/COUNTRY02.
|
||||
|
||||
Levantamento READ ONLY: lote proposto de 16 conteúdos não financeiros e 4 imagens distintas (20 recursos): Energia/Mineração 3, Turismo12, Infraestruturas1. Ficheiros/hash/scan/publicação QA existentes e todos ausentes no ativo. Energia/Mineração é índice curto; imagem tempo-background é partilhada, sem duplicação. Mercado Financeiro: corpo0, artigo QA privado e imagem própria fora do recorte, apesar de já publicada em QA. Não inventar texto ou ativar calculador para preencher o vazio.
|
||||
|
||||
Dependência técnica principal: importador ativo nominal só aceita agronegócio; novo manifesto e extensão de escopo específicos devem ser preparados antes de nova disponibilização. Setores/rotas e apoio v5 já existem. Fonte, autorização de divulgação por recurso, scan no destino, importação privada/publicação separadas e backup fresco futuro mantêm-se. Nenhuma implementação nesta etapa. Detalhes em outputs/investmoz-legado-restantes-setores-preparacao-20261015/FECHO-E-PREPARACAO-LOTE.md; inventário completo22 e recorte20 associados aos IDs existentes.
|
||||
|
||||
Pagina privada do levantamento do proximo lote: https://chatgpt.com/space/page_d6f090dba9048191a92c9175b3605dee
|
||||
|
||||
|
||||
### 15/10/2026 — lote setorial preparado em QA
|
||||
|
||||
AUD-LEG-01/06/07 e AUD-LIB-01/02: manifesto fechado de 20 recursos (16 conteúdos + 4 imagens), importador nominal --sectors-lot20 preparado em cópia QA e 133 verificações dirigidas passadas. Plano e mapa: outputs/investmoz-legado-setores-lote20-QA-20261015/PLANO-UNICO.md. Agronegócio ativo/AUD-LEG-03 e B mantêm-se encerrados; Mercado Financeiro excluído. Sem alteração/publicação ativa. Saldo operacional futuro 2h30–5h, condicionado a decisão específica da Tempo e backup/restauro fresco; não inclui trabalho QA concluído. Reutilizar a aceitação anterior, sem novos ciclos.
|
||||
|
||||
|
||||
15/10/2026 — Proposta única de decisão do lote setorial consolidada em outputs/investmoz-legado-setores-lote20-QA-20261015/PROPOSTA-UNICA-TEMPO.md e vinculada pelo RECIBO-PROPOSTA.json. Sem nova preparação, testes ou alteração ativa; decisão da Tempo pendente. Configuração adicional dos percursos não prevista na revisão preparada. Saldo operacional 2h30–5h mantido.
|
||||
|
||||
|
||||
### 15/10/2026 — lote setorial disponibilizado no ativo
|
||||
|
||||
Tempo autorizou o procedimento. Entregue apenas ImportDocumentBatch.php na revisão f429fb2655a3956f4025d3a42db64d161643872045a134f63ab183f5dc011eb8. Importados 20 ausentes como privados; scan dos hashes verificado; publicação expressa pela sessão Osmane Nala, recursos 7–26/v3. Consulta anónima dos 16 conteúdos, três entradas setoriais e quatro imagens confirmada. Backup/restauro fresco: 295 tabelas, 31 sequências e ficheiros verificados. Sem alterações aos registos de negócio preexistentes, agronegócio, B, COUNTRY02, configuração ou build. Sem novos dossiers/pedidos e sem repetir aceitação funcional. Mercado Financeiro e integração integral do restante legado permanecem pendentes. Provas e reversão: outputs/investmoz-legado-setores-ativacao-20261015/.
|
||||
|
||||
|
||||
### 15/10/2026 — inventário restante do legado reconciliado por leitura
|
||||
|
||||
Mesma matriz e inventários atualizados: 50 artigos distintos, dos quais 17 publicados, 31 com corpo ainda por integrar (5 setoriais, 8 trabalho doméstico, 18 históricos/noticiosos), Mercado Financeiro vazio e post 74364 sem título. Onze URLs equivalentes não acrescentam artigos; 47 ficheiros adicionais inventariados não acrescentam identidades. Cinco imagens já públicas; próximos artigos setoriais reutilizam o fundo do recurso 24. Recorte sugerido para escolha da Tempo: Fintech, Imobiliário e Bens de Consumo/Franquias, cujos setores mestres existem. Não é autorização de nova implementação/publicação. Referências externas e 30.170 URLs do sitemap infopublica permanecem delimitados, sem bloquear os conteúdos disponíveis. Provas: outputs/investmoz-legado-inventario-reconciliado-20261015/SALDO-LEGADO.md e RECONCILIACAO-LEGADO.json. Sem nova aceitação dos já publicados ou alterações no ativo.
|
||||
|
||||
|
||||
## 15/10/2026 — portas setoriais e Fintech preparados em QA
|
||||
|
||||
Candidata setores-fintech-QA-d5b4dc354265: 16 fontes e compilação isoladas; três artigos Fintech/Imobiliário/Bens de Consumo e Franquias, imagem já publicada reutilizada por hash. Sete setores reúnem conteúdo, oportunidades e ações; ideia sem artigo/oportunidade e setor recuperado no mesmo dossier; modalidade existente no cadastro sem negócio automático. Energia/Mineração específicos e mestre combinado legado preservados. Artigo geral Mercado Financeiro vazio não bloqueia entrada comercial.
|
||||
|
||||
Fintech especializa o percurso de cinco fases/19 etapas: modelos tecnológico/financeiro/indeterminado; atividades/documentos condicionais; países de operação distintos dos mestres; payload cifrado, ferramentas/apoio/CRM/documentos/independência existentes. Enquadramento jurídico específico por determinar não bloqueia preparação independente; nenhum ato externo fictício. Revisões S02/S08/S17 apenas por âmbito afetado e pareceres preservados.
|
||||
|
||||
Provas: 67 serviços/controllers, 38 HTTP, 20 fecho delta e oito recuperação final; navegador A/B, novo login, países, gravação, erro com rótulo/foco/campos preservados e móvel. Trio com preview, importação privada, scan real, replay/recusas/leitor demonstrados. Reutilizar B/COUNTRY02/12 critérios e todas as aceitações anteriores.
|
||||
|
||||
Mesma matriz: dez linhas existentes atualizadas, apenas AUD-FINTECH-01 acrescentado; 3391 registos originais byte a byte preservados, incluindo AUD-LEG-03. Ativo não alterado nesta entrega; 993 ficheiros protegidos iguais. Comparação READ ONLY de 295 tabelas assinala um rascunho e três registos de histórico posteriores ao clone QA; preservados. Backup fresco será próximo da execução.
|
||||
|
||||
Resultado, mapa 5/19, manifesto, reversão, limites e proposta única: outputs/investmoz-fintech-investimento-QA-20261015. QA delimitada concluída; saldo operacional 1h30–3h só após decisão da Tempo. Não existe autorização ativa nesta preparação. Integração integral do legado e correspondências jurídicas específicas mantêm os seus estados próprios.
|
||||
|
||||
|
||||
### Revisão documental DOC01 da candidata setores-fintech-QA-d5b4dc354265
|
||||
|
||||
Preflight corrigido: 12 hashes anteriores e quatro ausências, sem alteração das 16 fontes, da compilação ou dos três recursos. Enquadramento regulatório Fintech completo (licenças, requisitos e documentos por atividade) mantém-se pendente em AUD-FINTECH-01 após eventual disponibilização. A conferência comunicada pela Tempo foi documental, sem inspeção do ZIP ou execução QA pela Tempo; não constitui autorização ativa. Provas aceites preservadas, sem novos testes funcionais. Pacote/recibo DOC01 substituem a documentação corrente; exemplares anteriores preservados.
|
||||
|
||||
|
||||
## 15/10/2026 — disponibilização setorial e Fintech concluída por autorização da Tempo
|
||||
|
||||
A mensagem «Autorizo a disponibilizar» autoriza a candidata setores-fintech-QA-d5b4dc354265 DOC01 no âmbito concreto preparado. Entregues 16 fontes (12 substituições e quatro novos ficheiros) e 173 ficheiros de compilação; sem migrations, categorias, alterações de flags ou outras funcionalidades. Três artigos ausentes importados privadamente, analisados com ClamAV 1.5.4 e publicados expressamente pela conta administrativa autenticada Osmane Nala (#2): Fintech #27, Imobiliário #28 e Bens de Consumo e Franquias #29, todos na versão de metadados 3. Imagem #24 reutilizada por identidade/hash, versão 3 preservada.
|
||||
|
||||
Backup fresco e restauro isolado verificados: 295 tabelas, 31 sequências, 1.027 ficheiros e 26 documentos. Comparação final: todos os registos anteriores de negócio preservados, 919 ficheiros protegidos fora do delta inalterados, B/COUNTRY02/flags e conteúdos anteriores preservados. Conferência operacional anónima das sete entradas e três artigos, duas fronteiras de login e assets; nenhuma nova criação de dossier/oportunidade ou repetição dos critérios aceites.
|
||||
|
||||
A entrega está encerrada; saldo operacional zero. A integração integral do legado continua pendente: 20 artigos publicados, 28 com corpo ainda por integrar (dois setoriais, oito de trabalho doméstico e 18 históricos/noticiosos), um vazio (Mercado Financeiro) e um sem título. O enquadramento regulatório específico Fintech (licenças, requisitos/documentos por atividade, disposição/versão/período) continua explicitamente pendente em AUD-FINTECH-01. Provas, recibo e reversão executável por ficheiro/publicação: outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json. Documentação e pacote DOC01 anteriores preservados como histórico; não são reescritos para simular autorização prévia.
|
||||
|
||||
|
||||
## 15/10/2026 — correspondência Fintech com o acervo aceite
|
||||
|
||||
Tabela de 14 linhas em fintech-correspondencia-acervo.md: atividade → requisito condicionado ao modelo → diploma/artigo/página → suporte existente/peça a preparar → etapa → lacuna. Fontes oficiais reutilizadas sem revalidar proveniência. Guias com diplomas revogados, minutas que misturam consultoria e ativos virtuais, capital recomendável sem força normativa e ordem autorização/constituição identificados concretamente. AUD-FINTECH-01 mantém enquadramento completo pendente; restantes 3401 registos preservados. Nenhuma alteração de aplicação/ativo, nova publicação, envio externo ou repetição da QA aceite. Preparação independente mantém-se permitida.
|
||||
|
||||
|
||||
## 15/10/2026 — classificação multidimensional preparada exclusivamente em QA
|
||||
|
||||
Reconciliado o repositório atual antes de codificar; plano finito e estimativa inicial 8–13 h preservados em outputs/investmoz-classificacao-multidimensional-QA-20261015/RECONCILIACAO-E-INCREMENTOS.md. Delta de 17 fontes (14 substituições/três novas) e compilação: associações tipadas na coleção canónica existente, quatro dimensões, decisão independente por relação/documento, projeção editorial pública e filtros combinados. Sem migrations, novos papéis/flags, importação, publicação ou classificações reais no ativo.
|
||||
|
||||
44 verificações HTTP, 22 de serviço e seis de reversão compatível; teclado/erros/móvel observados. Publicação usa fixture sintético explícito e não repete transições editoriais aceites. Reversão preserva o JSON usado e o histórico, com compatibilidade mínima no contrato anterior; nenhum down destrutivo. Ficheiros ativos protegidos conferidos por hash.
|
||||
|
||||
Oito requisitos existentes receberam evidência parcial e saldo concreto, sem criar outra matriz/backlog, fechar cláusulas integrais ou reabrir B/COUNTRY02/12 critérios/aceitações anteriores. Cobertura: Opportunity e /oportunidades; anúncios UUID /negocios não migrados. Ficha operacional integral de parques, dados económicos ausentes, similaridade/consolidação e enquadramento Fintech completo permanecem nas mesmas linhas próprias. A tabela Fintech de 14 linhas e fontes aceites permanece entregue.
|
||||
|
||||
Resultado, limites, manifesto/recibo e proposta única: outputs/investmoz-classificacao-multidimensional-QA-20261015/RELATORIO-QA.md, PROPOSTA-UNICA-TEMPO.md e PROCEDIMENTO-E-REVERSAO.md. Preparação não autoriza disponibilização. Saldo operacional proposto 1h30–3h somente após decisão da Tempo, com backup/restauro fresco próximo da execução.
|
||||
|
||||
|
||||
### Classificação multidimensional — revisão documental DOC01 (15/10/2026)
|
||||
|
||||
Corrigido o passo de cache no procedimento da candidata `classificacao-multidimensional-QA-64ab05e20b95`: comandos específicos de configuração, rotas e vistas, preservando a cache de dados na entrega e na reversão. Após utilização, mantém-se obrigatório o contrato compatível que preserva `enterprise_size`, relações, decisões e histórico. Pacote/manifesto/recibo DOC01 verificados localmente; DOC00 preservado. Fontes, compilação e provas QA mantidas, sem repetir ensaios ou alterar o ativo. Estimativa coerente e inalterada: 90–180 minutos (1h30–3h), após decisão expressa da Tempo. Permanecem abertos `/negocios`, ficha operacional integral dos parques, referências económicas em falta, consolidação de duplicados e regulação Fintech completa. Matriz e restantes confirmações inalteradas.
|
||||
|
||||
|
||||
## 15/10/2026 — classificação multidimensional DOC01 disponibilizada
|
||||
|
||||
A Tempo autorizou expressamente `classificacao-multidimensional-QA-64ab05e20b95`, pacote DOC01. Entregues 17 fontes (14 substituições e três novas) e 174 ficheiros de build, com hashes conferidos. Backup/restauro fresco: 295 tabelas, 31 sequências e 2.221 ficheiros; arranque do clone isolado conferido. Troca em manutenção, apenas config:clear/route:clear/view:clear; cache de dados idêntica durante a operação. HTTP/TLS/assets e seis oportunidades públicas preservados. Comparação de leitura sem alterações nas tabelas de negócio, configuração/flags/permissões, B, COUNTRY02, ficheiros privados, documentos e histórico. Sem migrations, dados QA, classificações reais ou repetição da auditoria aceite.
|
||||
|
||||
Editor no ativo: não demonstrado nesta conferência. O utilizador informou não ter acesso à conta de Promotora interna Aurora Chachuaio. A sessão efetiva Osmane Nala, conta 2, recebeu 403 em GET /minhas-oportunidades/create; não existe elevação operacional ativa. Os papéis Promotor/Validador dessa conta permanecem atribuídos; as funções de autorização v1 conferem exatamente com a versão anterior à entrega. Existem seis oportunidades legadas e nenhuma do workflow de promotor no ativo. A mensagem 403 genérica não expõe o motivo; o diagnóstico fica registado, sem alterar permissões, credenciais ou acrescentar uma correção fora do pacote autorizado. Mantêm-se as provas funcionais QA aceites do editor.
|
||||
|
||||
Reversão nominal preparada: 13 fontes anteriores mais contrato compatível após utilização, build fresco anterior e retirada por hash das três novas fontes após restauro das referências, sem restaurar base sobre dados posteriores. Provas e recibo: outputs/investmoz-classificacao-ativacao-20261015/. Mesmos oito requisitos recebem a prova operacional parcial; 3.394 outros registos brutos conservados. Continuam abertos /negocios, ficha integral de parques, referências económicas em falta, consolidação de duplicados e enquadramento Fintech completo. A estimativa anterior 1h30–3h era a previsão operacional da entrega, agora executada, não um saldo para repetir.
|
||||
|
||||
|
||||
## 15/10/2026 — acesso normal de Promotor com Superutilizador acumulado
|
||||
|
||||
A leitura direta da v1 §3.2/§5 distingue a atuação de Promotor da elevação excecional de Superutilizador. O diagnóstico anterior de falta de elevação explicava o 403 instalado, mas generalizava a exigência à acumulação sem disposição expressa. Corrigido apenas em QA no complemento `promotor-contexto-QA-e8858cb44dca`: canCreate, leitura/edição e fila próprias usam o grant de Promotor; funções excecionais, Auditor, organização/tipo, estados, MFA e independência conservam os controlos. Três fontes, duas substituições e uma vista nova de recusa explicada; sem build ou migrations. Não foram concedidos grants ou alteradas credenciais ativas.
|
||||
|
||||
Oito verificações HTTP antes e quinze depois, 23 verificações de âmbito e abertura visual com Fortify/MFA normais, sem preencher, guardar ou transitar o formulário. Ativo DOC01 preservado por hash; B/COUNTRY02 e aceitação anterior mantidos. Dois requisitos recebem complemento pontual, com 3.400 outros registos brutos preservados. Proposta, delta, provas e reversão: outputs/investmoz-promotor-contexto-QA-20261015/. Falta somente decisão específica para aplicar as três fontes no ativo e observar a abertura, sem reinstalar DOC01.
|
||||
|
||||
|
||||
## 15/10/2026 — contexto normal de Promotor disponibilizado
|
||||
|
||||
A Tempo autorizou `promotor-contexto-QA-e8858cb44dca`: entregues apenas três fontes, duas substituições e uma vista nova. Backup/restauro fresco conferido (295 tabelas, 31 sequências, 2.340 ficheiros, 29 documentos) e arranque do clone em leitura. Cache de dados preservada; somente view:clear. Editor aberto pela conta 2, Osmane Nala, em autenticação normal, sem guardar. Nenhum grant ou dado de negócio alterado, DOC01 não reinstalado, provas aceites não repetidas. Pendência operacional encerrada. Âmbitos, MFA, Auditor, independência e elevação excecional mantidos; B, COUNTRY02 e restantes lacunas preservados. Provas, reversão e recibo: outputs/investmoz-promotor-contexto-ativacao-20261015/. Os registos QA anteriores mantêm-se como histórico.
|
||||
|
||||
|
||||
## 16/10/2026 — mapa prévio de classificação de /negocios
|
||||
|
||||
Incremento limitado pela Tempo a QA, antes de codificar: campos e relações atuais, suplemento no contexto cifrado das revisões do mesmo UUID, decisão e divulgação distintas, sem reabrir o workflow do anúncio. Inspeção de leitura confirmou 172aa874-98fc-4bf6-b78f-d2e9a386d345 publicado/v12, 12 revisões/11 transições e zero documentos associados. A base QA de referência permanece intacta; ensaio previsto num clone novo. Dependências antecipadas: ações exclusivas do suplemento para publicado, adaptação da evidência documental e da pesquisa cifrada, responsabilidades/permissões atuais e reversão após uso.
|
||||
|
||||
Mapa completo, 11 fontes previstas (8 alterações/3 novas), critérios a demonstrar, reversão e estimativa restante 10–16 h: outputs/investmoz-negocios-classificacao-mapa-20261016/MAPA-ALTERACOES.md. Inspeção SQL não é aceitação funcional. Sem alterações de código de aplicação/ativo, nova atribuição, anúncio paralelo ou repetição de provas aceites. Mesmos sete requisitos referenciados, estados da matriz preservados; classificação canónica e acesso concluídos, restantes quatro lacunas abertas. Planeamento não autoriza disponibilização ativa.
|
||||
|
||||
|
||||
## 16/10/2026 — classificação multidimensional de /negocios demonstrada em QA
|
||||
|
||||
Candidata negocios-classificacao-QA-53311df2f59c: 11 fontes (oito substituições, três novas) e 161 ficheiros de build. Suplemento no contexto cifrado das revisões existentes, mantendo UUID, conteúdo e workflow. 36 verificações/50 pedidos HTTP, 10 de âmbito/política, recuperação visual após atualização e erro visível. Preparação e confirmação não divulgaram a nova classificação; nova projeção apenas por ação expressa. Referência QA publicada/v12 intacta; clone principal publicado/v26, com alteração apenas de versão/data e revisões do suplemento. Sem novos anúncios, migrations, grants, importações ou ativo alterado.
|
||||
|
||||
Reversão demonstrada com troca efetiva pelo código anterior, gravação posterior bem-sucedida de rascunho existente e recuperação exata da classificação. Limitação do fixture: o payload secundário foi inicializado sinteticamente só no clone por falta da chave pré-QA; ciphertext original preservado privadamente. O caso principal não foi reaberto. Não há cadeia de valor consultável na QA: caso positivo continua não demonstrado, sem criar mestres fictícios.
|
||||
|
||||
Mesmos sete requisitos recebem evidência parcial; 3.395 outros registos brutos e todos os estados preservados. As quatro lacunas excluídas e as duas entregas encerradas mantêm-se. Mapa prévio e provas anteriores conservados como histórico. Relatório, manifesto, procedimento e recibo: outputs/investmoz-negocios-classificacao-QA-20261016/. Preparação deste recorte concluída, saldo QA zero; estimativa operacional futura 90–180 min após decisão expressa da Tempo. Nenhuma autorização ativa presumida, nem repetição dos 12 critérios aceites.
|
||||
|
||||
|
||||
## 16/10/2026 — classificação de negócios disponibilizada com limite operacional explícito
|
||||
|
||||
Tempo autorizou prosseguir com negocios-classificacao-QA-53311df2f59c: entregues 11 fontes (oito substituições e três novas) e 161 ficheiros de build. Backup/restauro fresco conferido em 295 tabelas/31 sequências/2341 ficheiros/29 documentos, clone arrancou em leitura e troca concluída fora da manutenção. Apenas config:clear/route:clear/view:clear; cache de dados idêntica durante a troca. GET/TLS/assets passaram; catálogos preservados (zero anúncios públicos de negócios, seis oportunidades). Sem migrations, importações, grants, classificação real, divulgação ou repetição de provas aceites.
|
||||
|
||||
Após login/MFA normal de Osmane Nala (#2), a área privada e formulário inicial abriram sem guardar. Lista própria vazia; dois rascunhos pertencem a outro titular. Recuperação do editor UUID no ativo não observada; não se forçou acesso nem criou anúncio. Dados de negócio, papéis e histórico iguais à fotografia fresca. Sessões e cache técnica variaram com navegação/autenticação; a cache foi preservada durante a troca.
|
||||
|
||||
Compilação autorizada usa Laravel no sufixo do título por falta de VITE_APP_NAME no build QA. Suplemento negocios-compilacao-nome-QA-7ef0facd0e27 repõe InvesteMoz: zero fontes/configurações alteradas, mesmos 161 assets, CSS idêntico, apenas literal JavaScript e referências geradas diferentes. Preparado e observado apenas em QA; aplicação ativa depende de decisão específica dos novos hashes. Não reabrir a aceitação funcional.
|
||||
|
||||
Mesmos sete requisitos com complemento operacional parcial; 3395 outros registos brutos e todos os estados preservados. Cadeia sem caso positivo, ausência de ensaio volumétrico e limite da reversão sintética mantêm-se. As quatro outras lacunas permanecem abertas. Relatório, reversão e recibos em outputs/investmoz-negocios-classificacao-ativacao-20261016/. A estimativa de 1h30–3h da entrega base era previsão, agora executada; suplemento de nome tem previsão própria de 10–20 min se o backup fresco continuar válido.
|
||||
|
||||
|
||||
### 16/10/2026 — suplemento de nome autorizado e fecho operacional
|
||||
|
||||
Tempo autorizou expressamente negocios-compilacao-nome-QA-7ef0facd0e27. Renovado backup/restauro do estado base já entregue: 295 tabelas, 31 sequências, 1304 ficheiros e 29 documentos; clone arrancou em leitura. Trocados somente os 161 ficheiros de compilação, sem fontes/configurações adicionais nem comandos de limpeza de cache. Título ativo observado após carregamento: Oportunidades de negócio - InvesteMoz. GET/TLS/assets passaram, catálogos preservados; comparação final das 295 tabelas sem diferenças. Zero classificações reais ou relações divulgadas. Reversão do suplemento repõe apenas o build base; reversão integral mantém o contrato de preservação das novas revisões.
|
||||
|
||||
Saldo operacional zero. Limitação UUID no ativo permanece explícita por ausência de anúncio próprio da conta 2; não foi criado anúncio nem forçado acesso. Cadeia sem caso positivo, ausência de ensaio volumétrico e limitação do payload sintético da reversão conservadas. Outras quatro lacunas e aceitações anteriores mantêm-se. Mesmos sete requisitos recebem complemento, restantes 3395 registos brutos e todos os estados preservados. Relatório/recibo final: outputs/investmoz-negocios-classificacao-ativacao-20261016/RELATORIO-FINAL.md e RECIBO-CONSOLIDADO.json. Propostas e relatórios das fases anteriores conservados como histórico.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Correspondência Fintech com o acervo e o percurso
|
||||
|
||||
Tabela documental para preparar investimentos no modelo existente. Reutiliza as fontes oficiais aceites pela Tempo; não exige nova validação da sua proveniência. O requisito indicado aplica-se **quando o modelo de atividade corresponde ao âmbito citado**. Referências e documentos de apoio não constituem decisão externa ou licença. Todas as linhas permitem continuar a preparação independente.
|
||||
|
||||
Foram inventariados os 10.717 ficheiros acessíveis do acervo antes do recorte. Os inventários anteriores de 604 e 77 entradas foram reutilizados; respetivamente 599 e 67 caminhos continuam acessíveis. O recorte extraiu 23 exemplares, com 21 hashes distintos; duas cópias exatas foram relacionadas sem eliminação. Dois PDFs do Decreto 50/2024 têm bytes distintos e texto extraído igual; ambos os originais foram preservados. O inventário integral e extrações ficam locais/privados; nenhum original empresarial foi publicado ou anexado.
|
||||
|
||||
**Fonte/artigo** refere as edições identificadas abaixo. Não se afirma consolidação integral das alterações posteriores ou de todos os avisos. **Documento de suporte** distingue exemplares já disponíveis de peças a preparar no processo; não se dá por existente uma licença, contrato ou decisão do investidor. A ligação às etapas é uma proposta documental, sem nova dependência de software ou campo obrigatório.
|
||||
|
||||
| Atividade Fintech | Requisito aplicável | Fonte/artigo | Documento de suporte | Etapa do percurso | Lacuna concreta |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Fornecedor tecnológico sem atos financeiros próprios | Delimitar serviço e responsabilidades; se explorar plataforma abrangida, distinguir registo/licenciamento TIC de autorização financeira. | L20 arts. 5, 8, 227 (PDF p. 1, 2, 45); T59 arts. 2, 7, 8, 9, 10, 17, 18 (PDF p. 1, 2, 3) | Existentes: Fintech e TIC.docx. Preparar arquitetura, contrato com operador e fluxos; não é prova de dispensa. | S01–S04; S06; S08; S16–S17 | Definir se fornece software ou executa operações; classificar a plataforma concreta e normas TIC posteriores aplicáveis. Não impor licença BM a todo fornecedor por ser Fintech. |
|
||||
| Movimentar fundos / transferências | Enquadrar execução profissional em instituição habilitada e na categoria de transferência, com pedido conforme o modelo. | L20 arts. 6, 7, 8, 16, 17 (PDF p. 2, 3); R50 arts. 51, 52, 53, 54, 59 (PDF p. 8, 9) | Existente: guia de prestadores de pagamentos. Preparar fluxos, titularidade das contas, parceiros e dossier societário. | S04–S06; S08; S17–S18 | Separar operação própria, agência e tecnologia contratada; individualizar condições BM para agentes/atividade. Guia antigo cita diplomas revogados. |
|
||||
| Serviços de pagamento / agregação | Distinguir agregador, transferência e moeda eletrónica. Fundos de pagamentos não são automaticamente depósitos ou moeda eletrónica (art. 59(3)). | L20 arts. 6, 7, 16, 17 (PDF p. 2, 3); R50 arts. 51, 52, 54, 59 (PDF p. 8, 9) | Existentes: guia PDF e artigo de apoio pagamentos DOCX. Preparar contas, operações, contratos e arquitetura. | S04–S06; S08; S17–S19 | Identificar operações exatas do art. 59, categoria e normas complementares. Não transportar capitais do guia baseado no Decreto 99/2019. |
|
||||
| Emitir moeda eletrónica / carteira com saldo | Enquadrar entidade emitente, fundos recebidos, valor emitido e condições contratuais de reembolso. | L20 arts. 5, 6, 8 (PDF p. 1, 2); R50 arts. 51, 52, 55, 56, 57 (PDF p. 8) | Preparar modelo de saldo/reembolso, contrato do utilizador, fluxos e arquitetura; guia pagamentos é apoio histórico. | S04; S06; S08; S16–S19 | Confirmar que emite saldo monetário e não é mera interface; capital e demais avisos por categoria/período continuam por determinar. |
|
||||
| Receber depósitos ou poupanças | Distinguir captação pública para uso próprio, fundos de pagamentos e poupança exclusivamente de membros; escolher o regime correspondente. | L20 arts. 4, 5, 8 (PDF p. 1, 2); R50 arts. 59, 156, 157, 169 (PDF p. 9, 22, 24) | Existentes: guias microbancos/cooperativas. Preparar origem, titularidade, utilização dos fundos e estatutos. | S04–S06; S08; S12; S17–S19 | Definir público/membros, uso por conta própria e tipo de entidade. Não chamar depósito bancário a qualquer recebimento nem aplicar a exceção de membros ao público. |
|
||||
| Custodiar fundos ou valores | Precisar objeto: fundos de pagamentos, carteira de valores mobiliários ou outro ativo; o enquadramento depende do mandato e do tipo de entidade. | L20 arts. 5, 7, 8 (PDF p. 1, 2); R50 arts. 59, 61, 62, 78, 80 (PDF p. 9, 12) | Preparar contrato de custódia/mandato, poderes de movimentação, contas e reconciliação. Minutas de consultoria não demonstram custódia autorizada. | S04; S06; S08; S16–S19 | Falta identificar ativo, detentor, poderes e segregação exigível no regime concreto; não existe licença única deduzida da palavra custódia. |
|
||||
| Conceder crédito / microcrédito | Separar crédito profissional, exclusões da lei e microfinanças; microbancos/cooperativas seguem autorização, OPE/operadores de microcrédito seguem inscrição. | L20 arts. 8, 9, 225 (PDF p. 2, 45); R50 arts. 156, 157, 158, 167, 169, 170 (PDF p. 22, 23, 24, 25) | Existentes: guia microbancos e Anexo III do R50. Preparar projeto de atividade, NUIT, capital/origem de fundos e restantes peças do art. 158 conforme categoria. | S04–S06; S08; S12; S17–S19 | Classificar mutuante/operação; localizar aviso de capitais/limites aplicável e efeitos cadastrais. Não reutilizar automaticamente Decreto 57/2004 ou valores históricos. |
|
||||
| Intermediar investimentos / executar ordens | Caracterizar corretagem, gestão de fundos/património ou outra atividade; articular regime da entidade com o mercado de valores mobiliários. | L20 arts. 5, 6, 7, 8 (PDF p. 1, 2); R50 arts. 60, 61, 62, 64, 72, 73, 76, 78 (PDF p. 9, 10, 11, 12) | Existentes: guias ICSF e checklist de consultoria. Preparar serviços, instrumentos, mandato, ordens e conflitos; não presumir habilitação BVM. | S02; S04–S06; S08; S17–S19 | Faltam correspondências específicas do Código do Mercado de Valores Mobiliários, avisos/qualificação de investidores e regras BVM para os serviços definidos. |
|
||||
| Consultoria sem discricionariedade ou movimentação | Distinguir estudos/planeamento empresarial de consultoria de investimento em valores mobiliários; as referências a atividades de entidades reguladas não licenciam automaticamente uma consultora pura. | L20 arts. 5, 8 (PDF p. 1, 2); R50 arts. 62, 76 (PDF p. 9, 11) | Existentes: Consultoria e aconselhamento financeiro.docx; Para a actividade…docx; Minuta ao BM.docx; REQUERIMENTO.docx; checklist. São apoio privado, não decisões BM. | S02; S04–S06; S08; S19 | Minutas divergentes entre licença e parecer de enquadramento; uma inclui exemplos de ativos virtuais. Ajustar objeto/questão concreta; obter resposta externa quando necessária. Capital recomendável não é mínimo legal. |
|
||||
| Outra atividade / ativos virtuais, se declarados | Identificar ato e norma própria antes de classificar; minuta que cita um aviso não substitui o respetivo articulado. | Articulado específico ainda sem correspondência; minutas não são fonte normativa. | Existentes: Minuta ao BM.docx e REQUERIMENTO.docx, com referências a ativos virtuais que não correspondem automaticamente à consultoria declarada. | S01–S04; S06; S08 | Aviso 4/GBM/2023 referido nas minutas sem correspondência de artigo demonstrada neste recorte. Localizar o texto e âmbito aplicáveis; não inferir licença/dispensa nem impor esta categoria a todas as Fintechs. |
|
||||
| Operações cambiais e pagamentos transfronteiriços | Qualificar operação e sujeitos; pagamentos/recebimentos sobre o exterior passam por intermediário autorizado e registo aplicável. | C28 arts. 2, 15, 16, 29, 74 (PDF p. 2, 4, 6, 12) | Existente: Lei Cambial 28/2022. Preparar contrato, valor/moeda, sujeitos/residências cambiais e comprovativos da operação. | S04; S06; S08; S12–S15; S19 | Regulamentação/avisos e eventual liberalização por operação por reconciliar. A Lei 11/2009 foi revogada no art. 74; país declarado não determina residência cambial. |
|
||||
| Atendimento e operação de entidade obrigada a BC/FT | Preparar avaliação de risco, identificação/diligência, beneficiário efetivo, comunicação e conservação conforme âmbito da entidade. | BC53 arts. 2, 4, 5, 9, 10, 11, 12, 13, 14, 24, 29 (PDF p. 1, 2, 3, 4, 5, 6, 9, 10) | Preparar políticas e procedimentos BC/FT, cadastro de cliente/beneficiário, responsabilidades e arquivo seguro; modelos são peças a adaptar. | S06; S08; S16–S19 | Concretizar categoria obrigada, proporcionalidade e orientações setoriais; identificar a correspondência atual da Lei 14/2023 e alterações aplicáveis. Não generalizar uma checklist a qualquer software. |
|
||||
| Constituir entidade financeira e preparar autorização | Autorização de constituição é prévia à constituição da ICSF; preparar projeto de estatutos, programa, governação, arquitetura, sócios e origem de fundos. | L20 arts. 12, 13, 16, 17 (PDF p. 3); R50 arts. 4, 5, 6, 7, 8 (PDF p. 1, 2) | Existentes: guia ICSF e minutas. Preparar peças do art. 17; previsão de 5 anos para IC ou 3 para SF; comprovativo/garantia quando aplicável. | S04/S06 preparar; S08 autorização; S05 formalização conforme decisão; S12 financiamento | Reconciliar ordem jurídica com roteiro genérico S05/S08, sem exigir constituição consumada antes da autorização. Identificar aviso de capital mínimo e montantes/atualizações; não usar recomendações comerciais como lei. |
|
||||
| Testar e iniciar operação financeira | Distinguir aprovação interna do projeto, autorização de constituição e condições externas de início; vistoria inclui instalações, processamento de dados e sistema informático. | L20 arts. 21 (PDF p. 4); R50 arts. 14 (PDF p. 3) | Preparar arquitetura, segurança, continuidade, testes e evidência da decisão/vistoria externa. Art. 14 do R50 refere especificamente agências. | S16 implementar; S17 conferir; S18 iniciar quando habilitado; S19 acompanhar | Faltam requisitos técnicos complementares e atos reais do projeto. A decisão do portal não substitui vistoria/licença; nenhuma nova trava à preparação foi implementada. |
|
||||
|
||||
## Fontes identificadas
|
||||
|
||||
- **L20** — Lei 20/2020, de 31 de dezembro — LICSF; exemplar `lei_20-2020_31_de_dezembro_-_lei_das_instituições_de_crédito_e_sociedades_financeiras-licsf-1.pdf`; SHA-256 `e98fe5110375601bd4618aee6c3bc9e9abd560a3110722d026afadbe0c17469f`. Exemplar oficial identificado no acervo aceite.
|
||||
- **R50** — Regulamento anexo ao Decreto 50/2024, de 11 de julho; exemplar `decreto-50-2024-11-de-julho-regulamento-da-lei-das-instituições-de-crédito-e-sociedades-financeiras.pdf`; SHA-256 `74d3ce326c857e60c58a2b41eaf8969f07971cbf4934dc1b0504f507d075c07b`. [PDF oficial BM](https://www.bancomoc.mz/media/jcdnvi0r/decreto-50-2024-11-de-julho-regulamento-da-lei-das-institui%C3%A7%C3%B5es-de-cr%C3%A9dito-e-sociedades-financeiras.pdf).
|
||||
- **C28** — Lei 28/2022, de 29 de dezembro — Lei Cambial; exemplar `lei-nr-28-2022-de-29-de-dezembro-lei-cambial.pdf`; SHA-256 `0dba2775dbede3701b8c1f476e1497c0dc2a481d59e7898013aa992d0a3db896`. Exemplar oficial identificado no acervo aceite.
|
||||
- **BC53** — Regulamento anexo ao Decreto 53/2023, de 31 de agosto — BC/FT; exemplar `Regulamento da Lei que Estabelece o Re- gime Jurídico e as Medidas de Prevenção e Combate ao Branqueamento de Capitais e Financiamento do Terrorismo.pdf`; SHA-256 `eabe50780e8b0dc51396abf256f53b4d01f9eec15c8eea91f1359a71c7437e3f`. Exemplar oficial identificado no acervo aceite.
|
||||
- **T59** — Regulamento anexo ao Decreto 59/2023, de 27 de outubro — plataformas digitais; exemplar `BR_206_I_SERIE_2023 Registo e Licenciamento de Provedores Intermediários de Serviços Electrónicos e de Operadores de Plataformas Digitais.pdf`; SHA-256 `e2c28c35bb9c3ae630149387e7c701dfb0d0ec2830b829507c34d64c92264a7a`. Exemplar oficial identificado no acervo aceite.
|
||||
|
||||
O Decreto 50/2024, art. 2 do decreto aprovador, revoga expressamente os Decretos 56/2004, 57/2004, 31/2006, 30/2014 e 99/2019. A sua fonte oficial permanece aceite; a lacuna dos guias antigos é de âmbito/atualização, não de credibilidade. A Lei 28/2022, art. 74, revoga a Lei 11/2009. Não substituir estes textos por um checklist antigo.
|
||||
|
||||
Os guias PDF de bancos/sociedades financeiras, pagamentos e microbancos são fontes de apoio já disponíveis, com remissões históricas; os DOCX editoriais/minutas não são classificados como diplomas oficiais. `Capital social recomendável.docx` contém recomendação comercial, não mínimo legal identificado. `Minuta ao BM.docx`/`REQUERIMENTO.docx` contêm objeto de consultoria, exemplos de ativos virtuais e/ou alternativas de pedido: corrigir a peça do processo concreto antes de qualquer envio; nada foi enviado. O checklist cita Aviso 3/GBM/2026 sem articulado correspondente demonstrado neste recorte; essa referência não foi elevada a obrigação geral.
|
||||
|
||||
## Correspondência com o modelo instalado
|
||||
|
||||
As sete declarações existentes continuam `moves_funds`, `deposits`, `custody`, `credit`, `payments`, `investment_intermediation` e `other`; moeda eletrónica é detalhe de pagamentos e consultoria precisa de qualificação concreta, sem criar novas categorias. Reutilizam-se `business_plan` (S04), `entity` (S05), `architecture` (S06), `fund_flows`/`external` (S08), `security` (S16), `customers`/`tests` (S17), e o acompanhamento S19. Não foram acrescentados campos, checklists obrigatórios, regras, cálculos ou transições.
|
||||
|
||||
A ordem S05/S08 exige correspondência por modelo: preparar estatutos é diferente de constituir a instituição financeira antes da autorização do BM (Lei 20/2020, art. 16). A tabela identifica a questão para o processo regulado; não declara falha funcional demonstrada nem reabre as provas aceites. A vistoria/condições de operação são distintas da aprovação interna do portal.
|
||||
|
||||
Atualização apenas documental da mesma linha AUD-FINTECH-01. O piloto e as entradas setoriais ativos mantêm-se; o enquadramento regulatório completo permanece pendente, agora discriminado por ato, artigo e peça. B, COUNTRY02, publicações e histórico não foram alterados. Não há importação/publicação de outro acervo nem envio às autoridades.
|
||||
@@ -1,51 +1,51 @@
|
||||
ID legado,Título,Autor,Categoria,Publicado,Modificado,SHA256 conteúdo,URLs observadas,Recurso QA,Situação
|
||||
171985,Agronegocio,tempo,Oportunidades,2026-04-06T09:19:07+00:00,2026-04-20T12:41:43+00:00,28383a11d95f13894381357d8f1227b33031d1d3ff74507da4ea8e5ce2470913,https://investemoz.tempo.co.mz/agronegocio,6,recurso único QA; não é oportunidade
|
||||
62413,15/30 costa do sol com dua na zona de mupulene muito lindo,tempo,Categoria,2017-06-26T11:44:21+00:00,2017-06-26T11:44:21+00:00,c04ae821317ef556c01c3141ce75eeeeb5da7787e0c6849b1b3709b757edb9eb,https://investemoz.tempo.co.mz/1530-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo,,inventariado; cadastro/versão por reconciliar
|
||||
173220,Alumínio “Verde”,tempo,Oportunidades,2026-06-16T12:41:02+00:00,2026-06-16T12:41:06+00:00,c61f05a56bb5a5f13d9d5d54dbefd270cf9ac40320917d77aaad76cac56c7b97,https://investemoz.tempo.co.mz/aluminio-verde,,inventariado; cadastro/versão por reconciliar
|
||||
73945,Banco Mundial classifica de proibitivos juros praticados em Moçambique,tempo,Nas Redes,2017-07-31T19:55:24+00:00,2017-07-31T19:55:24+00:00,36ba82b8885b00a4ea2fd9e4b1d8cf304a8e78e591972682f0aa53717f648d19,https://investemoz.tempo.co.mz/banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique,,inventariado; cadastro/versão por reconciliar
|
||||
173213,Bens de Consumo e Franquias,tempo,Oportunidades,2026-06-16T11:31:06+00:00,2026-06-16T11:32:10+00:00,abd5f36a0c2b89d2989334137aae5d59b3158da38d556013ccd55deaa5069e92,https://investemoz.tempo.co.mz/bens-de-consumo-franquias,,inventariado; cadastro/versão por reconciliar
|
||||
172223,"Cabo Delgado - Pemba, A capital do turismo costeiro do norte de Moçambique",tempo,Turismo,2026-04-14T10:21:20+00:00,2026-04-14T10:41:05+00:00,c96b2430c44b8edc9cc1d0a7974c23290dd0207cff366fea8326bb28bcab8285,https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique/ | https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique,20,RecursoQA20; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
173482,Checklist para Contratação e Direitos do Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T12:36:11+00:00,2026-09-15T12:36:14+00:00,309b51ebc53bf840f9014da733bc09f8d162138be4e6e9d5a72670e26cc8e482,https://investemoz.tempo.co.mz/checklist-para-contratacao-e-direitos-do-trabalho-domestico,,inventariado; cadastro/versão por reconciliar
|
||||
76474,"Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador",tempo,Categoria,2017-08-08T17:29:51+00:00,2017-08-08T17:29:51+00:00,c8beeb94f936b3bfc69c720770bd84376e9f19b668d96185aaefbada05727010,https://investemoz.tempo.co.mz/coloque-o-seu-numero-para-o-grupo-de-whatsapp-venda-de-acessorios-de-computador,,inventariado; cadastro/versão por reconciliar
|
||||
173484,Direitos Especiais da Trabalhadora Doméstica no Regulamento,tempo,Trabalho Doméstico,2026-09-15T12:38:08+00:00,2026-09-15T12:38:11+00:00,34c31bb02a3ad0886f12ac2853283de2ffb89a925be3cda73b7ce9385c6caec4,https://investemoz.tempo.co.mz/direitos-especiais-da-trabalhadora-domestica-no-regulamento,,inventariado; cadastro/versão por reconciliar
|
||||
171981,Energia & Mineração,tempo,Oportunidades,2026-04-06T09:17:46+00:00,2026-04-30T13:35:32+00:00,e9a95f0c8176eea48a75bd2c5bce69f15308806988fa5203a688af7c40305e9c,https://investemoz.tempo.co.mz/energia-mineracao,7,RecursoQA7; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
173222,Energia e Recursos Naturais,tempo,Oportunidades,2026-06-16T12:47:16+00:00,2026-06-16T12:51:30+00:00,6f8236b0441d61fce5171994ba6b82ffc8b5f2de3e8242de7be29248ed046ad2,https://investemoz.tempo.co.mz/energia-recursos-naturais,,inventariado; cadastro/versão por reconciliar
|
||||
62414,Frelimo e Zanu-PF: Evocados laços de irmandade,tempo,Categoria,2017-06-26T12:03:20+00:00,2017-06-26T12:03:20+00:00,013307965b8fcb349a0d936d844ed12437bda4c90389f8efe958d4ffdb9ce62b,https://investemoz.tempo.co.mz/frelimo-e-zanu-pf-evocados-lacos-de-irmandade,,inventariado; cadastro/versão por reconciliar
|
||||
62418,Governo dará todo O apoio à PGR no seguimento da auditoria,tempo,Categoria,2017-06-26T12:30:37+00:00,2017-06-26T12:30:45+00:00,65299b6711499e417be778b51c7ab7880616b0ccbf362854370eb775fc54caf3,https://investemoz.tempo.co.mz/governo-dara-todo-o-apoio-a-pgr-no-seguimento-da-auditoria,,inventariado; cadastro/versão por reconciliar
|
||||
75002,Governo pretende construir 100 mil habitações em dois anos,tempo,Nas Redes,2017-08-04T20:01:55+00:00,2017-08-04T20:01:55+00:00,b32ea95039c2af387687738ed601f0947384eb7e19ca4bd282d603c60ca26afa,https://investemoz.tempo.co.mz/governo-pretende-construir-100-mil-habitacoes-em-dois-anos,,inventariado; cadastro/versão por reconciliar
|
||||
173478,Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T12:30:34+00:00,2026-09-15T12:30:37+00:00,8038d8c221ba3cbbc4712304a6b17a6bba8ad946c8bac1a7836d472944aaf930,https://investemoz.tempo.co.mz/guia-pratico-para-empregadores-sobre-contratacao-e-direitos-no-trabalho-domestico,,inventariado; cadastro/versão por reconciliar
|
||||
173218,Imobiliário,tempo,Oportunidades,2026-06-16T11:34:45+00:00,2026-06-16T11:34:49+00:00,be8b606f087a939bd88a86f4436a0ff18c5fb774a179e6e915d4abb10a95f930,https://investemoz.tempo.co.mz/imobiliario,,inventariado; cadastro/versão por reconciliar
|
||||
171992,Infraestruturas,tempo,Oportunidades,2026-04-06T09:25:07+00:00,2026-04-30T12:44:37+00:00,9716da16aba58eec173343f0bbd582d62d23a5eee7d20522c080c2da5da8ba66,https://investemoz.tempo.co.mz/infraestruturas,22,RecursoQA22; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
172240,"Maputo Cidade – Plataforma Estratégica de Turismo, Negócios e Investimento Sustentável",tempo,Turismo,2026-04-14T10:58:53+00:00,2026-04-14T11:03:28+00:00,0866639d09c5c0b3b00e8527554065587c793f60df978b66b6a578b3c741bc0d,https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel/ | https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel,16,RecursoQA16; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
171994,Mercado Financeiro,tempo,Oportunidades,2026-04-06T09:27:00+00:00,2026-04-17T09:53:42+00:00,e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,https://investemoz.tempo.co.mz/mercado-financeiro,23,"RecursoQA23; original/hash/ClamD/replay demonstrados. Corpo vazio na origemHTML/Inertia200;privado,sem página publicada."
|
||||
173480,Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias,tempo,Trabalho Doméstico,2026-09-15T12:34:17+00:00,2026-09-15T12:34:19+00:00,5b95ad9010fcbdc1000052f47766ca54409d3e0649211729ced9ef142f5c6db0,https://investemoz.tempo.co.mz/modelo-de-contrato-de-trabalho-domestico-para-pequenas-familias,,inventariado; cadastro/versão por reconciliar
|
||||
172219,Niassa - O último grande destino virgem do turismo africano,tempo,Turismo,2026-04-14T10:17:14+00:00,2026-04-14T10:43:56+00:00,47d82a59a86c3cbdef04ea065e711e7139d50137e440f03efbd710e3c4220ef7,https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano/ | https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano,21,RecursoQA21; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
173476,Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique,tempo,Trabalho Doméstico,2026-09-15T11:39:21+00:00,2026-09-15T11:39:24+00:00,bb634a9021da9d7b46ed105317aa54e4af42a16dab042e0ceb2bdc0d702d1a67,https://investemoz.tempo.co.mz/procedimentos-para-rescisao-do-contrato-de-trabalho-domestico-segundo-o-regulamento-de-mocambique,,inventariado; cadastro/versão por reconciliar
|
||||
172263,"Província da Zambézia: Onde os Corredores de Moçambique Convergem com a Natureza, a Cultura e o Turismo Sustentável",tempo,Turismo,2026-04-14T14:21:52+00:00,2026-04-14T14:26:27+00:00,9e7ca4e9542135d5969f5c008ce8e29b037cc06a53875cfa7dc3e7452ec47744,https://investemoz.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel,11,RecursoQA11; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
172233,Província de Gaza: Oportunidades mais sólidas e estratégicas de investimento no turismo no sul de Moçambique.,tempo,Turismo,2026-04-14T10:52:30+00:00,2026-04-17T08:28:56+00:00,2bf2df9bd3b7ab8656209a48f4928b5d8bbf2959e77c292fc4c9987e67ba2fea,https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique/ | https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique,18,RecursoQA18; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
172253,Província de Inhambane: Um Destino Estratégico para Investimento Turístico,tempo,Turismo,2026-04-14T14:15:12+00:00,2026-04-14T14:25:44+00:00,2d1cc729481ce65a5e50898c0eea4a1eb2418273b03fc749009e2ffaaa72fe71,https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico/ | https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico,15,RecursoQA15; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
172258,"Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento",tempo,Turismo,2026-04-14T14:18:28+00:00,2026-04-17T10:42:16+00:00,4c8bdd79212ba98fa347733e2f58aef8796b29cc8cb8b649d200bd37435df1c3,https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento/ | https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento,14,RecursoQA14; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
172237,"Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável",tempo,Turismo,2026-04-14T10:55:21+00:00,2026-04-17T08:27:24+00:00,d112d0e535912f4487c2b8d41978e5e663f1db43f1a2cdf170dbbec535f13f27,https://investemoz.tempo.co.mz/provincia-de-maputo-turismo/ | https://investemoz.tempo.co.mz/provincia-de-maputo-turismo,17,RecursoQA17; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
172230,Província de Nampula - Perfil de investimento no setor do turismo,tempo,Turismo,2026-04-14T10:50:32+00:00,2026-04-14T11:10:23+00:00,d18ccc1e036b3480605462ce7176be75153f6aa988bc9b37d8d395b01e555a7a,https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo/ | https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo,19,RecursoQA19; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
172256,"Província de Sofala: Onde a Natureza, a História e o Futuro do Turismo Convergem",tempo,Turismo,2026-04-14T14:16:47+00:00,2026-04-14T14:26:17+00:00,12b46a34ba61c6ef0058a6c410ebc17329d897fe4b06a13b4ea3fe3c85a28342,https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem/ | https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem,12,RecursoQA12; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
172261,"Província de Tete: Onde o Rio Zambeze, a Cultura Viva e a Conservação Comunitária Criam o Futuro do Turismo",tempo,Turismo,2026-04-14T14:19:48+00:00,2026-04-14T14:26:25+00:00,e78fce2931260a7d6f82270897e906feb640f65d084c2d4ffb5ba19303858275,https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo/ | https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo,13,RecursoQA13; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
73246,Rofino Licuco preso cinco meses depois de condenado por agressão,tempo,Nas Redes,2017-07-28T20:23:11+00:00,2017-07-28T20:23:11+00:00,806c54948641f4f5933a2ea4a6935dfb7a67202ab227960451d62435880289f6,https://investemoz.tempo.co.mz/rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao,,inventariado; cadastro/versão por reconciliar
|
||||
77232,Sete indivíduos mortos a tiro na Matola,tempo,Nas Redes,2017-08-11T20:30:32+00:00,2017-08-11T20:30:32+00:00,e657a97d5d6db7fa0ea6b7d14029ff873ea5d36dfdadda5f8b9bc8f1ef5dd011,https://investemoz.tempo.co.mz/sete-individuos-mortos-a-tiro-na-matola,,inventariado; cadastro/versão por reconciliar
|
||||
62416,Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia,tempo,Categoria,2017-06-26T12:14:48+00:00,2017-06-26T12:14:48+00:00,0fe20a9ca9dd99c58072f43b3dece1de347ef4063ee5f75bcffe8b2f4bf253b5,https://investemoz.tempo.co.mz/sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india,,inventariado; cadastro/versão por reconciliar
|
||||
173209,Fintech,tempo,Oportunidades,2026-06-16T11:24:22+00:00,2026-06-23T10:03:06+00:00,8db9206bf5192b68e7c9bdfb87e9dc9c7063a4b7eca56630685b0e6c294f55ab,https://investemoz.tempo.co.mz/tech-fintech,,inventariado; cadastro/versão por reconciliar
|
||||
171990,Turismo,tempo,Oportunidades,2026-04-06T09:22:51+00:00,2026-06-16T13:07:59+00:00,604d30a740cc6ed20d24e3447806e733aa4aefb9f339f81d3dc57b644dd19fb7,https://investemoz.tempo.co.mz/turismo,10,RecursoQA10; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
74364,,tempo,Categoria,2017-07-26T21:20:33+00:00,2017-07-26T21:20:33+00:00,2a7f0a5b09e0136fec9eae357ac8a88a159ead23b25ed7bb735c75997b10ec5e,https://investemoz.tempo.co.mz/74364-2,,inventariado; cadastro/versão por reconciliar
|
||||
62929,Daúde Razaque já não é treinador da Liga Desportiva de Maputo,tempo,Nas Redes,2017-06-27T16:41:43+00:00,2017-06-27T16:41:43+00:00,c3b57ea685290bfb01c50403bc83db98cf1a42ad51c04d5b8d288c99b8c0a808,https://investemoz.tempo.co.mz/daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo,,inventariado; cadastro/versão por reconciliar
|
||||
62649,Daviz Simango não se incomoda com possível sucessão na Beira,tempo,Nas Redes,2017-06-26T19:38:09+00:00,2017-06-26T19:38:09+00:00,090e5f41ed11c8e680d2e30ea5c8310b7c6b165ddec318a8b0cf94927f78da74,https://investemoz.tempo.co.mz/daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira,,inventariado; cadastro/versão por reconciliar
|
||||
173470,Direitos e Deveres do Trabalhador Doméstico,tempo,Trabalho Doméstico,2026-09-15T11:28:25+00:00,2026-09-15T11:28:28+00:00,f69fd6fd8509913f2d79df0267c469dc7a9d0d30420ce8428749d53ba21446ab,https://investemoz.tempo.co.mz/direitos-e-deveres-do-trabalhador-domestico,,inventariado; cadastro/versão por reconciliar
|
||||
172679,Energia,tempo,Featured,2026-04-30T13:03:57+00:00,2026-04-30T13:28:48+00:00,e2a7eb4be0a2cf4139737f6428c147ac35de99899478ce79195dc5e1b0a960f3,https://investemoz.tempo.co.mz/energia | https://investemoz.tempo.co.mz/energia/,8,RecursoQA8; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
62739,"“Exigimos responsabilização dos agentes do crime”, Daviz Simango",tempo,Nas Redes,2017-06-26T23:13:36+00:00,2017-06-26T23:13:36+00:00,e37ea18176246dab529d2ecec7734f0fb2b0a54cadc507fbd789033d5b8e5b93,https://investemoz.tempo.co.mz/exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango-2,,inventariado; cadastro/versão por reconciliar
|
||||
62854,Governo e parceiros reforçam mecanismos de controlo de HIV/Sida,tempo,Nas Redes,2017-06-27T11:07:53+00:00,2017-06-27T11:07:53+00:00,0073816b1fa4bd50ec6417b07272da06565230d06a19079ca76cb006c882d2f1,https://investemoz.tempo.co.mz/governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida,,inventariado; cadastro/versão por reconciliar
|
||||
63128,Graça Machel diz que desnutrição é um problema de desenvolvimento,tempo,Nas Redes,2017-06-27T22:01:59+00:00,2017-06-27T22:01:59+00:00,711f3707e3a0d72ec919216fc50823de9060349104ee98fe0a6b20d6684b6031,https://investemoz.tempo.co.mz/graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento,,inventariado; cadastro/versão por reconciliar
|
||||
63181,In dependência,tempo,Nas Redes,2017-06-27T21:38:06+00:00,2017-06-27T21:38:06+00:00,b0d87c0d58d6d1343d102cd3141bda1215c5afd54f3780a1c6c262d786dbfe27,https://investemoz.tempo.co.mz/in-dependencia,,inventariado; cadastro/versão por reconciliar
|
||||
63146,"Kroll não descobriu como foram gastos 2 biliões de dólares; Governo de Nyusi não apoiou a Auditoria; criação da Proindicus, EMATUM e MAM não foi para proteção da Zona Económica Exclusiva",tempo,Nas Redes,2017-06-27T19:30:01+00:00,2017-06-27T19:30:01+00:00,4ccbad5c92ddc3884f58181a4f1ed3c1d3d6a59f005bfd99b197a6fc1fc3c280,https://investemoz.tempo.co.mz/kroll-nao-descobriu-como-foram-gastos-2-bilioes-de-dolares-governo-de-nyusi-nao-apoiou-a-auditoria-criacao-da-proindicus-ematum-e-mam-nao-foi-para-protecao-da-zona-economica-exclusiva-2,,inventariado; cadastro/versão por reconciliar
|
||||
172674,Mineração,tempo,Featured,2026-04-30T13:12:09+00:00,2026-04-30T13:30:13+00:00,8d3acc292ed806bc4cc7bcb6a3a6a5759f30b610766a5ef4b3d6a0b7c56d5861,https://investemoz.tempo.co.mz/mineracao,9,RecursoQA9; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
62688,O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ...,tempo,Nas Redes,2017-06-26T18:21:18+00:00,2017-06-26T18:21:18+00:00,396fe2575641622015505eb11d4c7152b6e3e1b741966f14c0cd1673fd455fd3,https://investemoz.tempo.co.mz/o-instituto-nacional-de-meteorologia-preve-o-seguinte-estado-do-tempo-para-esta-29,,inventariado; cadastro/versão por reconciliar
|
||||
173474,Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique,tempo,Trabalho Doméstico,2026-09-15T11:37:04+00:00,2026-09-15T11:37:06+00:00,e09a0fe71397e2b060ff8435111117aa487b476a85ec522fffcdf9e23a6cdac2,https://investemoz.tempo.co.mz/sancoes-disciplinares-aplicaveis-a-trabalhadores-domesticos-segundo-o-regulamento-de-mocambique,,inventariado; cadastro/versão por reconciliar
|
||||
63248,Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (...,tempo,Nas Redes,2017-06-28T11:30:01+00:00,2017-06-28T11:30:01+00:00,2220ca2c07d10f10b2bd6fd0f103ee733b83570d436c751c449c85b42df46a13,https://investemoz.tempo.co.mz/dois-alunos-da-9a-classe-cairam-nas-maos-da-policia-da-republica-de-mocambique,,inventariado; cadastro/versão por reconciliar
|
||||
173463,Regulamento do Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T10:56:07+00:00,2026-09-15T12:41:44+00:00,eb43b6c1f097631250f0b36d3d01b4d106db2fcae07a56bb154819143fff11e9,https://investemoz.tempo.co.mz/regulamento-do-trabalho-domestico,,inventariado; cadastro/versão por reconciliar
|
||||
ID legado,Título,Autor,Categoria,Publicado,Modificado,SHA256 conteúdo,URLs observadas,Recurso QA,Situação,Situação anterior à reconciliação 15/10/2026,Recurso ativo,Grupo restante,Imagem atual,Dependência concreta,Próxima ação,Evidência atual
|
||||
171985,Agronegocio,tempo,Oportunidades,2026-04-06T09:19:07+00:00,2026-04-20T12:41:43+00:00,28383a11d95f13894381357d8f1227b33031d1d3ff74507da4ea8e5ce2470913,https://investemoz.tempo.co.mz/agronegocio,6,publicado,recurso único QA; não é oportunidade,5,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 6, ""sha256"": ""5e3840705cf98226d1f189cf665aaa98cb05da96c645159a1332a1d429d642eb""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
62413,15/30 costa do sol com dua na zona de mupulene muito lindo,tempo,Categoria,2017-06-26T11:44:21+00:00,2017-06-26T11:44:21+00:00,c04ae821317ef556c01c3141ce75eeeeb5da7787e0c6849b1b3709b757edb9eb,https://investemoz.tempo.co.mz/1530-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/817802064_1_644x461_15-30-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo-maputo.jpg | Referência não recolhida: https://www.olx.co.mz/imoveis-casas/terrenos/terrenos-venda/maputo-maputo/?search%5Bprivate_business%5D=private | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173220,Alumínio “Verde”,tempo,Oportunidades,2026-06-16T12:41:02+00:00,2026-06-16T12:41:06+00:00,c61f05a56bb5a5f13d9d5d54dbefd270cf9ac40320917d77aaad76cac56c7b97,https://investemoz.tempo.co.mz/aluminio-verde,,existente por integrar,inventariado; cadastro/versão por reconciliar,,setorial,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Ausente da biblioteca ativa e QA; falta exemplar versionado no manifesto de um novo lote e extensão nominal do importador. | Slug ausente no mapa do leitor; falta ligação ao percurso/dossier fundamentada para este artigo. | Não há setor mestre Alumínio Verde com correspondência exata; fundamentar o agrupamento sem inventar vínculo a projeto ou criar setor automaticamente.,Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
73945,Banco Mundial classifica de proibitivos juros praticados em Moçambique,tempo,Nas Redes,2017-07-31T19:55:24+00:00,2017-07-31T19:55:24+00:00,36ba82b8885b00a4ea2fd9e4b1d8cf304a8e78e591972682f0aa53717f648d19,https://investemoz.tempo.co.mz/banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/economia/38-economia/45893-banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Banco-Mundial-classifica-de-proibitivos-juros-praticados-em-Mo%C3%A7ambique.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1460805843956666 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173213,Bens de Consumo e Franquias,tempo,Oportunidades,2026-06-16T11:31:06+00:00,2026-06-16T11:32:10+00:00,abd5f36a0c2b89d2989334137aae5d59b3158da38d556013ccd55deaa5069e92,https://investemoz.tempo.co.mz/bens-de-consumo-franquias,29,"Publicado no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados",inventariado; cadastro/versão por reconciliar,29,publicado,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz.,"Preservar publicação; restante acervo separado, sem repetir aceitação.",outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json
|
||||
172223,"Cabo Delgado - Pemba, A capital do turismo costeiro do norte de Moçambique",tempo,Turismo,2026-04-14T10:21:20+00:00,2026-04-14T10:41:05+00:00,c96b2430c44b8edc9cc1d0a7974c23290dd0207cff366fea8326bb28bcab8285,https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique/ | https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique,20,publicado,RecursoQA20; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,20,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173482,Checklist para Contratação e Direitos do Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T12:36:11+00:00,2026-09-15T12:36:14+00:00,309b51ebc53bf840f9014da733bc09f8d162138be4e6e9d5a72670e26cc8e482,https://investemoz.tempo.co.mz/checklist-para-contratacao-e-direitos-do-trabalho-domestico,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
76474,"Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador",tempo,Categoria,2017-08-08T17:29:51+00:00,2017-08-08T17:29:51+00:00,c8beeb94f936b3bfc69c720770bd84376e9f19b668d96185aaefbada05727010,https://investemoz.tempo.co.mz/coloque-o-seu-numero-para-o-grupo-de-whatsapp-venda-de-acessorios-de-computador,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: https://www.facebook.com/photo.php?fbid=741844132690980&set=gm.1566816196708735&type=3 | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Coloque-o-seu-n%C3%BAmero-para-o-grupo-de-whatsapp-venda-de-acess%C3%B3rios-de-computador.jpg | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/1502293415_298_Coloque-o-seu-n%C3%BAmero-para-o-grupo-de-whatsapp-venda-de-acess%C3%B3rios-de-computador.jpg | Referência não recolhida: https://www.facebook.com/179463555444013/posts/1566816196708735 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173484,Direitos Especiais da Trabalhadora Doméstica no Regulamento,tempo,Trabalho Doméstico,2026-09-15T12:38:08+00:00,2026-09-15T12:38:11+00:00,34c31bb02a3ad0886f12ac2853283de2ffb89a925be3cda73b7ce9385c6caec4,https://investemoz.tempo.co.mz/direitos-especiais-da-trabalhadora-domestica-no-regulamento,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
171981,Energia & Mineração,tempo,Oportunidades,2026-04-06T09:17:46+00:00,2026-04-30T13:35:32+00:00,e9a95f0c8176eea48a75bd2c5bce69f15308806988fa5203a688af7c40305e9c,https://investemoz.tempo.co.mz/energia-mineracao,7,publicado,RecursoQA7; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,7,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 23, ""sha256"": ""0a2c50d91dad3a6007544634540e0f61b11d3506682a5a19066bae03cdcba490""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173222,Energia e Recursos Naturais,tempo,Oportunidades,2026-06-16T12:47:16+00:00,2026-06-16T12:51:30+00:00,6f8236b0441d61fce5171994ba6b82ffc8b5f2de3e8242de7be29248ed046ad2,https://investemoz.tempo.co.mz/energia-recursos-naturais,,existente por integrar,inventariado; cadastro/versão por reconciliar,,setorial,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Ausente da biblioteca ativa e QA; falta exemplar versionado no manifesto de um novo lote e extensão nominal do importador. | Slug ausente no mapa do leitor; falta ligação ao percurso/dossier fundamentada para este artigo. | Texto distinto de Energia/Mineração já publicado; preservar a ligação declarada /energia-mineracao e delimitar agrupamento, sem fundir os exemplares.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
62414,Frelimo e Zanu-PF: Evocados laços de irmandade,tempo,Categoria,2017-06-26T12:03:20+00:00,2017-06-26T12:03:20+00:00,013307965b8fcb349a0d936d844ed12437bda4c90389f8efe958d4ffdb9ce62b,https://investemoz.tempo.co.mz/frelimo-e-zanu-pf-evocados-lacos-de-irmandade,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência indisponível na captura (HTTP 404): https://investemoz.tempo.co.mz/images/ANO-2017/JUNHO/21/GOVERNADOR-in.gif | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
62418,Governo dará todo O apoio à PGR no seguimento da auditoria,tempo,Categoria,2017-06-26T12:30:37+00:00,2017-06-26T12:30:45+00:00,65299b6711499e417be778b51c7ab7880616b0ccbf362854370eb775fc54caf3,https://investemoz.tempo.co.mz/governo-dara-todo-o-apoio-a-pgr-no-seguimento-da-auditoria,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/a84c6c1e4d1780f63086a86817521b40 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
75002,Governo pretende construir 100 mil habitações em dois anos,tempo,Nas Redes,2017-08-04T20:01:55+00:00,2017-08-04T20:01:55+00:00,b32ea95039c2af387687738ed601f0947384eb7e19ca4bd282d603c60ca26afa,https://investemoz.tempo.co.mz/governo-pretende-construir-100-mil-habitacoes-em-dois-anos,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45963-governo-pretende-construir-100-mil-habitacoes-em-dois-anos.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Governo-pretende-construir-100-mil-habita%C3%A7%C3%B5es-em-dois-anos.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1464602060243711 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173478,Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T12:30:34+00:00,2026-09-15T12:30:37+00:00,8038d8c221ba3cbbc4712304a6b17a6bba8ad946c8bac1a7836d472944aaf930,https://investemoz.tempo.co.mz/guia-pratico-para-empregadores-sobre-contratacao-e-direitos-no-trabalho-domestico,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173218,Imobiliário,tempo,Oportunidades,2026-06-16T11:34:45+00:00,2026-06-16T11:34:49+00:00,be8b606f087a939bd88a86f4436a0ff18c5fb774a179e6e915d4abb10a95f930,https://investemoz.tempo.co.mz/imobiliario,28,"Publicado no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados",inventariado; cadastro/versão por reconciliar,28,publicado,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz.,"Preservar publicação; restante acervo separado, sem repetir aceitação.",outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json
|
||||
171992,Infraestruturas,tempo,Oportunidades,2026-04-06T09:25:07+00:00,2026-04-30T12:44:37+00:00,9716da16aba58eec173343f0bbd582d62d23a5eee7d20522c080c2da5da8ba66,https://investemoz.tempo.co.mz/infraestruturas,22,publicado,RecursoQA22; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,22,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 26, ""sha256"": ""8e58544e49e719f9c865c91e07ef1030155a9e3d59260e6dc93e9c9e25674e39""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172240,"Maputo Cidade – Plataforma Estratégica de Turismo, Negócios e Investimento Sustentável",tempo,Turismo,2026-04-14T10:58:53+00:00,2026-04-14T11:03:28+00:00,0866639d09c5c0b3b00e8527554065587c793f60df978b66b6a578b3c741bc0d,https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel/ | https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel,16,publicado,RecursoQA16; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,16,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
171994,Mercado Financeiro,tempo,Oportunidades,2026-04-06T09:27:00+00:00,2026-04-17T09:53:42+00:00,e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,https://investemoz.tempo.co.mz/mercado-financeiro,23,vazio — dependência concreta,"RecursoQA23; original/hash/ClamD/replay demonstrados. Corpo vazio na origemHTML/Inertia200;privado,sem página publicada.",,mercado_financeiro,"{""status"": ""capturada mas não publicada no ativo"", ""sha256"": ""417b4a33468f360acef272ce3e4180c1d0a171980befa73ddb9a33de5a9d4c4e""}",Corpo do artigo vazio; imagem não substitui conteúdo.,"Manter pendente e separado, sem bloquear outros lotes.",outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173480,Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias,tempo,Trabalho Doméstico,2026-09-15T12:34:17+00:00,2026-09-15T12:34:19+00:00,5b95ad9010fcbdc1000052f47766ca54409d3e0649211729ced9ef142f5c6db0,https://investemoz.tempo.co.mz/modelo-de-contrato-de-trabalho-domestico-para-pequenas-familias,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172219,Niassa - O último grande destino virgem do turismo africano,tempo,Turismo,2026-04-14T10:17:14+00:00,2026-04-14T10:43:56+00:00,47d82a59a86c3cbdef04ea065e711e7139d50137e440f03efbd710e3c4220ef7,https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano/ | https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano,21,publicado,RecursoQA21; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,21,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173476,Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique,tempo,Trabalho Doméstico,2026-09-15T11:39:21+00:00,2026-09-15T11:39:24+00:00,bb634a9021da9d7b46ed105317aa54e4af42a16dab042e0ceb2bdc0d702d1a67,https://investemoz.tempo.co.mz/procedimentos-para-rescisao-do-contrato-de-trabalho-domestico-segundo-o-regulamento-de-mocambique,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172263,"Província da Zambézia: Onde os Corredores de Moçambique Convergem com a Natureza, a Cultura e o Turismo Sustentável",tempo,Turismo,2026-04-14T14:21:52+00:00,2026-04-14T14:26:27+00:00,9e7ca4e9542135d5969f5c008ce8e29b037cc06a53875cfa7dc3e7452ec47744,https://investemoz.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel,11,publicado,RecursoQA11; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,11,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172233,Província de Gaza: Oportunidades mais sólidas e estratégicas de investimento no turismo no sul de Moçambique.,tempo,Turismo,2026-04-14T10:52:30+00:00,2026-04-17T08:28:56+00:00,2bf2df9bd3b7ab8656209a48f4928b5d8bbf2959e77c292fc4c9987e67ba2fea,https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique/ | https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique,18,publicado,RecursoQA18; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,18,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172253,Província de Inhambane: Um Destino Estratégico para Investimento Turístico,tempo,Turismo,2026-04-14T14:15:12+00:00,2026-04-14T14:25:44+00:00,2d1cc729481ce65a5e50898c0eea4a1eb2418273b03fc749009e2ffaaa72fe71,https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico/ | https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico,15,publicado,RecursoQA15; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,15,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172258,"Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento",tempo,Turismo,2026-04-14T14:18:28+00:00,2026-04-17T10:42:16+00:00,4c8bdd79212ba98fa347733e2f58aef8796b29cc8cb8b649d200bd37435df1c3,https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento/ | https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento,14,publicado,RecursoQA14; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,14,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172237,"Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável",tempo,Turismo,2026-04-14T10:55:21+00:00,2026-04-17T08:27:24+00:00,d112d0e535912f4487c2b8d41978e5e663f1db43f1a2cdf170dbbec535f13f27,https://investemoz.tempo.co.mz/provincia-de-maputo-turismo/ | https://investemoz.tempo.co.mz/provincia-de-maputo-turismo,17,publicado,RecursoQA17; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,17,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172230,Província de Nampula - Perfil de investimento no setor do turismo,tempo,Turismo,2026-04-14T10:50:32+00:00,2026-04-14T11:10:23+00:00,d18ccc1e036b3480605462ce7176be75153f6aa988bc9b37d8d395b01e555a7a,https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo/ | https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo,19,publicado,RecursoQA19; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,19,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172256,"Província de Sofala: Onde a Natureza, a História e o Futuro do Turismo Convergem",tempo,Turismo,2026-04-14T14:16:47+00:00,2026-04-14T14:26:17+00:00,12b46a34ba61c6ef0058a6c410ebc17329d897fe4b06a13b4ea3fe3c85a28342,https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem/ | https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem,12,publicado,RecursoQA12; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,12,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172261,"Província de Tete: Onde o Rio Zambeze, a Cultura Viva e a Conservação Comunitária Criam o Futuro do Turismo",tempo,Turismo,2026-04-14T14:19:48+00:00,2026-04-14T14:26:25+00:00,e78fce2931260a7d6f82270897e906feb640f65d084c2d4ffb5ba19303858275,https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo/ | https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo,13,publicado,RecursoQA13; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,13,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
73246,Rofino Licuco preso cinco meses depois de condenado por agressão,tempo,Nas Redes,2017-07-28T20:23:11+00:00,2017-07-28T20:23:11+00:00,806c54948641f4f5933a2ea4a6935dfb7a67202ab227960451d62435880289f6,https://investemoz.tempo.co.mz/rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45870-rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Rofino-Licuco-preso-cinco-meses-depois-de-condenado-por-agress%C3%A3o.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1458270617543522 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
77232,Sete indivíduos mortos a tiro na Matola,tempo,Nas Redes,2017-08-11T20:30:32+00:00,2017-08-11T20:30:32+00:00,e657a97d5d6db7fa0ea6b7d14029ff873ea5d36dfdadda5f8b9bc8f1ef5dd011,https://investemoz.tempo.co.mz/sete-individuos-mortos-a-tiro-na-matola,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/46074-sete-individuos-mortos-a-tiro-na-matola-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Sete-indiv%C3%ADduos-mortos-a-tiro-na-Matola.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1471269102910340 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
62416,Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia,tempo,Categoria,2017-06-26T12:14:48+00:00,2017-06-26T12:14:48+00:00,0fe20a9ca9dd99c58072f43b3dece1de347ef4063ee5f75bcffe8b2f4bf253b5,https://investemoz.tempo.co.mz/sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.verdade.co.mz/internacional/62604-sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173209,Fintech,tempo,Oportunidades,2026-06-16T11:24:22+00:00,2026-06-23T10:03:06+00:00,8db9206bf5192b68e7c9bdfb87e9dc9c7063a4b7eca56630685b0e6c294f55ab,https://investemoz.tempo.co.mz/tech-fintech,27,"Publicado no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados",inventariado; cadastro/versão por reconciliar,27,publicado,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz.,"Preservar publicação; restante acervo separado, sem repetir aceitação.",outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json
|
||||
171990,Turismo,tempo,Oportunidades,2026-04-06T09:22:51+00:00,2026-06-16T13:07:59+00:00,604d30a740cc6ed20d24e3447806e733aa4aefb9f339f81d3dc57b644dd19fb7,https://investemoz.tempo.co.mz/turismo,10,publicado,RecursoQA10; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,10,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 25, ""sha256"": ""fe9a2e382e385b35f6e61ae320e199a979678677fd327fb7d4b07d8ce0111c11""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
74364,,tempo,Categoria,2017-07-26T21:20:33+00:00,2017-07-26T21:20:33+00:00,2a7f0a5b09e0136fec9eae357ac8a88a159ead23b25ed7bb735c75997b10ec5e,https://investemoz.tempo.co.mz/74364-2,,dependência concreta — título ausente,inventariado; cadastro/versão por reconciliar,,identidade_incompleta,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/1501695692_133_notitle.jpg | Referência não recolhida: https://www.facebook.com/179463555444013/posts/1552815684775453 | Título vazio no post 74364; corpo com 20 caracteres; identidade editorial a esclarecer sem inventar título.,Preservar exemplar e referências; delimitar recuperação editorial antes de integrar.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
62929,Daúde Razaque já não é treinador da Liga Desportiva de Maputo,tempo,Nas Redes,2017-06-27T16:41:43+00:00,2017-06-27T16:41:43+00:00,c3b57ea685290bfb01c50403bc83db98cf1a42ad51c04d5b8d288c99b8c0a808,https://investemoz.tempo.co.mz/daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/desporto/74-desporto/45358-daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Da%C3%BAde-Razaque-j%C3%A1-n%C3%A3o-%C3%A9-treinador-da-Liga-Desportiva-de-Maputo.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1425759480794636 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
62649,Daviz Simango não se incomoda com possível sucessão na Beira,tempo,Nas Redes,2017-06-26T19:38:09+00:00,2017-06-26T19:38:09+00:00,090e5f41ed11c8e680d2e30ea5c8310b7c6b165ddec318a8b0cf94927f78da74,https://investemoz.tempo.co.mz/daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/politica/63-politica/45340-daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Daviz-Simango-n%C3%A3o-se-incomoda-com-poss%C3%ADvel-sucess%C3%A3o-na-Beira.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1424683617568889 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173470,Direitos e Deveres do Trabalhador Doméstico,tempo,Trabalho Doméstico,2026-09-15T11:28:25+00:00,2026-09-15T11:28:28+00:00,f69fd6fd8509913f2d79df0267c469dc7a9d0d30420ce8428749d53ba21446ab,https://investemoz.tempo.co.mz/direitos-e-deveres-do-trabalhador-domestico,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172679,Energia,tempo,Featured,2026-04-30T13:03:57+00:00,2026-04-30T13:28:48+00:00,e2a7eb4be0a2cf4139737f6428c147ac35de99899478ce79195dc5e1b0a960f3,https://investemoz.tempo.co.mz/energia | https://investemoz.tempo.co.mz/energia/,8,publicado,RecursoQA8; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,8,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
62739,"“Exigimos responsabilização dos agentes do crime”, Daviz Simango",tempo,Nas Redes,2017-06-26T23:13:36+00:00,2017-06-26T23:13:36+00:00,e37ea18176246dab529d2ecec7734f0fb2b0a54cadc507fbd789033d5b8e5b93,https://investemoz.tempo.co.mz/exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango-2,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/politica/63-politica/45345-exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/%E2%80%9CExigimos-responsabiliza%C3%A7%C3%A3o-dos-agentes-do-crime%E2%80%9D-Daviz-Simango.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1424873994216518 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
62854,Governo e parceiros reforçam mecanismos de controlo de HIV/Sida,tempo,Nas Redes,2017-06-27T11:07:53+00:00,2017-06-27T11:07:53+00:00,0073816b1fa4bd50ec6417b07272da06565230d06a19079ca76cb006c882d2f1,https://investemoz.tempo.co.mz/governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45352-governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Governo-e-parceiros-refor%C3%A7am-mecanismos-de-controlo-de-HIVSida.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1425451974158720 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
63128,Graça Machel diz que desnutrição é um problema de desenvolvimento,tempo,Nas Redes,2017-06-27T22:01:59+00:00,2017-06-27T22:01:59+00:00,711f3707e3a0d72ec919216fc50823de9060349104ee98fe0a6b20d6684b6031,https://investemoz.tempo.co.mz/graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45368-graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Gra%C3%A7a-Machel-diz-que-desnutri%C3%A7%C3%A3o-%C3%A9-um-problema-de-desenvolvimento.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1426040144099903 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
63181,In dependência,tempo,Nas Redes,2017-06-27T21:38:06+00:00,2017-06-27T21:38:06+00:00,b0d87c0d58d6d1343d102cd3141bda1215c5afd54f3780a1c6c262d786dbfe27,https://investemoz.tempo.co.mz/in-dependencia,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://opais.sapo.mz/index.php/opiniao/182-helder-faife/45364-in-dependencia.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/In-depend%C3%AAncia.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1426022220768362 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
63146,"Kroll não descobriu como foram gastos 2 biliões de dólares; Governo de Nyusi não apoiou a Auditoria; criação da Proindicus, EMATUM e MAM não foi para proteção da Zona Económica Exclusiva",tempo,Nas Redes,2017-06-27T19:30:01+00:00,2017-06-27T19:30:01+00:00,4ccbad5c92ddc3884f58181a4f1ed3c1d3d6a59f005bfd99b197a6fc1fc3c280,https://investemoz.tempo.co.mz/kroll-nao-descobriu-como-foram-gastos-2-bilioes-de-dolares-governo-de-nyusi-nao-apoiou-a-auditoria-criacao-da-proindicus-ematum-e-mam-nao-foi-para-protecao-da-zona-economica-exclusiva-2,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.verdade.co.mz/tema-de-fundo/35/62615 | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Kroll-n%C3%A3o-descobriu-como-foram-gastos-2-bili%C3%B5es-de-d%C3%B3lares-Governo-de-Nyusi-n%C3%A3o-apoiou-a-Auditoria-cria%C3%A7%C3%A3o-da-Proindicus-EMATUM-e-MAM-n%C3%A3o-foi-para-prote%C3%A7%C3%A3o-da-Zona-Econ%C3%B3mica-Exclusiva.jpg | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1492451004109920 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
172674,Mineração,tempo,Featured,2026-04-30T13:12:09+00:00,2026-04-30T13:30:13+00:00,8d3acc292ed806bc4cc7bcb6a3a6a5759f30b610766a5ef4b3d6a0b7c56d5861,https://investemoz.tempo.co.mz/mineracao,9,publicado,RecursoQA9; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,9,publicados,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}",,Reutilizar a versão e a aceitação existentes; não importar ou aceitar novamente.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
62688,O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ...,tempo,Nas Redes,2017-06-26T18:21:18+00:00,2017-06-26T18:21:18+00:00,396fe2575641622015505eb11d4c7152b6e3e1b741966f14c0cd1673fd455fd3,https://investemoz.tempo.co.mz/o-instituto-nacional-de-meteorologia-preve-o-seguinte-estado-do-tempo-para-esta-29,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.verdade.co.mz/newsflash/62607 | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1491493337539020 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173474,Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique,tempo,Trabalho Doméstico,2026-09-15T11:37:04+00:00,2026-09-15T11:37:06+00:00,e09a0fe71397e2b060ff8435111117aa487b476a85ec522fffcdf9e23a6cdac2,https://investemoz.tempo.co.mz/sancoes-disciplinares-aplicaveis-a-trabalhadores-domesticos-segundo-o-regulamento-de-mocambique,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
63248,Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (...,tempo,Nas Redes,2017-06-28T11:30:01+00:00,2017-06-28T11:30:01+00:00,2220ca2c07d10f10b2bd6fd0f103ee733b83570d436c751c449c85b42df46a13,https://investemoz.tempo.co.mz/dois-alunos-da-9a-classe-cairam-nas-maos-da-policia-da-republica-de-mocambique,,existente por integrar,inventariado; cadastro/versão por reconciliar,,historico_noticioso,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Referência não recolhida: http://www.verdade.co.mz/newsflash/62625 | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1493133914041629 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
173463,Regulamento do Trabalho Doméstico,tempo,Trabalho Doméstico,2026-09-15T10:56:07+00:00,2026-09-15T12:41:44+00:00,eb43b6c1f097631250f0b36d3d01b4d106db2fcae07a56bb154819143fff11e9,https://investemoz.tempo.co.mz/regulamento-do-trabalho-domestico,,existente por integrar,inventariado; cadastro/versão por reconciliar,,trabalho_domestico,"{""status"": ""imagem já publicada; reutilizar"", ""resource_id"": 24, ""sha256"": ""28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa""}","Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",Preparar apenas se escolhido para o próximo lote; não publicar por esta reconciliação.,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
|
||||
|
@@ -1,93 +1,93 @@
|
||||
URL,HTTP,Tipo,Título,ID legado,Autor,Categoria legado,Publicado,Modificado,Bytes,SHA256,Destino proposto,Situação
|
||||
https://investemoz.tempo.co.mz/,200,text/html,Informacao Publica,,,,,,8368,42a2f14ca41b028045e9f2b2bb70fa324feb811698d9223f913b0b002a309f89,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/agronegocio,200,text/html,Agronegocio,171985,tempo,Oportunidades,2026-04-06T09:19:07+00:00,2026-04-20T12:41:43+00:00,88030,0bcd03e0e73cdf9b0f1a3a686689ae1a5ed80e990dcc34c77c9627c32f9d156f,/agronegocio,piloto preparado
|
||||
https://investemoz.tempo.co.mz/portal-do-investidor,200,text/html,Informacao Publica,,,,,,8368,f62485a612c9c8cc5765758614fdbcaafdd77e1d7eb35139c67045f40e638689,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/robots.txt,200,text/plain,,,,,,,153,70743fc5a6acd78ea3083b92220bbd775e9c37642843fa16b7e353726e839228,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/sitemap.xml,200,text/xml,,,,,,,7606912,8470ee4038c9d4b1d722edda9044d71ad3afdfd1817c9b41680d0b910d77d011,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://contentmanager.tempo.co.mz/wp-content/uploads/2026/04/Agronegocio.png,200,image/png,,,,,,,550888,5e3840705cf98226d1f189cf665aaa98cb05da96c645159a1332a1d429d642eb,biblioteca / correspondência por rever,piloto preparado
|
||||
https://contentmanager.tempo.co.mz/wp-content/uploads/2026/04/Energia-Mineracao.png,200,image/png,,,,,,,534405,0a2c50d91dad3a6007544634540e0f61b11d3506682a5a19066bae03cdcba490,biblioteca existente recursoQA24;URLs/versão originais preservados,RecursoQA24; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://contentmanager.tempo.co.mz/wp-content/uploads/2026/04/Infraestruturas.png,200,image/png,,,,,,,363037,8e58544e49e719f9c865c91e07ef1030155a9e3d59260e6dc93e9c9e25674e39,biblioteca existente recursoQA27;URLs/versão originais preservados,RecursoQA27; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://contentmanager.tempo.co.mz/wp-content/uploads/2026/04/Mercado-Financeiro.png,200,image/png,,,,,,,708105,417b4a33468f360acef272ce3e4180c1d0a171980befa73ddb9a33de5a9d4c4e,biblioteca existente recursoQA28;URLs/versão originais preservados,RecursoQA28; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://contentmanager.tempo.co.mz/wp-content/uploads/2026/04/Turismo.png,200,image/png,,,,,,,575317,fe9a2e382e385b35f6e61ae320e199a979678677fd327fb7d4b07d8ce0111c11,biblioteca existente recursoQA26;URLs/versão originais preservados,RecursoQA26; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz,200,text/html,Informacao Publica,,,,,,8368,db5c258c7a10d2d9ec91d378c153e1da53de4eef1dfa168b2dc666ba9aea36fc,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/1530-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo,200,text/html,15/30 costa do sol com dua na zona de mupulene muito lindo,62413,tempo,Categoria,2017-06-26T11:44:21+00:00,2017-06-26T11:44:21+00:00,46443,b9b6634f98240994fdd6a1d9f41012f9336e0a32e43a939710113802e0eca948,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/aluminio-verde,200,text/html,Alumínio “Verde”,173220,tempo,Oportunidades,2026-06-16T12:41:02+00:00,2026-06-16T12:41:06+00:00,88028,b6667ab0ed4cb3eca5ba7d9e09b829697a84ac1338d94025eada726b0b84addd,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/apple-touch-icon.png,200,image/png,,,,,,,1662,4001aa032ff113e1a268a9bbf1ab0fd9949439f9f54a85895956eb323aba977d,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique,200,text/html,Banco Mundial classifica de proibitivos juros praticados em Moçambique,73945,tempo,Nas Redes,2017-07-31T19:55:24+00:00,2017-07-31T19:55:24+00:00,63817,3b4535a181412bc95ef25725d32e997479328d6096f80046f95ca567233b1ce7,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/bens-de-consumo-franquias,200,text/html,Bens de Consumo e Franquias,173213,tempo,Oportunidades,2026-06-16T11:31:06+00:00,2026-06-16T11:32:10+00:00,88150,c7287adeaf11d2d8a40b0dc6a7b35e83ca0e2f312e2ac314caa01f166c08e3f8,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/build/assets/app-5tyHq2tj.js,200,application/javascript,,,,,,,76449,befcbe0252f450f664935a51f077030a30ae5955487f863990f204822bb7da1b,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/build/assets/app-CChIcWcY.js,200,application/javascript,,,,,,,115,81538671d6a533184b030e29c12d953c5dc584fd27e57ded6a576634e439f077,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/build/assets/app-CshAeK4J.css,200,text/css,,,,,,,219921,4c5addbbbb41752b8d8b17e1f3545ec461ec2631af24891940d3afa7347ccb91,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/build/assets/vendor-core-CDlfZzJQ.js,200,application/javascript,,,,,,,460473,fd4fdef257763f052e34a444b691d7322f49425e61e36d5fb83da8f0c340538b,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/build/assets/vendor-i18n-BY-fwNFQ.js,200,application/javascript,,,,,,,53387,7e87c342349f3e03d817f42e5f4da03a53f924839bc3f491d3cdf09d9c7f5886,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique/,200,text/html,"Cabo Delgado - Pemba, A capital do turismo costeiro do norte de Moçambique",172223,tempo,Turismo,2026-04-14T10:21:20+00:00,2026-04-14T10:41:05+00:00,123385,2ea7aa8588d4055b7033c66197d819e48716fcbf9520dd39ffe1713ef75a22c2,biblioteca existente recursoQA20;URLs/versão originais preservados,RecursoQA20; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/cdn-cgi/challenge-platform/scripts/jsd/main.js,200,application/javascript,,,,,,,22552,37f21e386bbbbaf80c7d98a667bbe049a55acfaebc7902fb88e56d03d5064e1d,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/checklist-para-contratacao-e-direitos-do-trabalho-domestico,200,text/html,Checklist para Contratação e Direitos do Trabalho Doméstico,173482,tempo,Trabalho Doméstico,2026-09-15T12:36:11+00:00,2026-09-15T12:36:14+00:00,86191,5e68de9c525c7779772fd5eb6f6e9e0a36ab93ca06ca4f2a686e2f0afa6482e2,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/coloque-o-seu-numero-para-o-grupo-de-whatsapp-venda-de-acessorios-de-computador,200,text/html,"Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador",76474,tempo,Categoria,2017-08-08T17:29:51+00:00,2017-08-08T17:29:51+00:00,44204,d1c7794dd9ef8b223bad657753162b6a5a6f64ce52870b05440e5d3ec961fb52,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/direitos-especiais-da-trabalhadora-domestica-no-regulamento,200,text/html,Direitos Especiais da Trabalhadora Doméstica no Regulamento,173484,tempo,Trabalho Doméstico,2026-09-15T12:38:08+00:00,2026-09-15T12:38:11+00:00,86424,b7aeb6d6143a2925a220bb899af2cac8363c542d0f1f337b72191f4994793aa6,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/energia-mineracao,200,text/html,Energia & Mineração,171981,tempo,Oportunidades,2026-04-06T09:17:46+00:00,2026-04-30T13:35:32+00:00,60048,f0d3fb494743c7dbec389fd3650754402135ceb6f2293ae6cef00fd0af93cbad,biblioteca existente recursoQA7;URLs/versão originais preservados,RecursoQA7; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/energia-recursos-naturais,200,text/html,Energia e Recursos Naturais,173222,tempo,Oportunidades,2026-06-16T12:47:16+00:00,2026-06-16T12:51:30+00:00,88150,718e69adfa50a11de8aeda60209afc0cbff1fd0c2be4bcb18ff59c43abed356a,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/favicon.ico,200,image/x-icon,,,,,,,15406,87f9c3a47246509b030080e505c103b48e93f3451ff84f0af38daa9164ce5356,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/favicon.svg,200,image/svg+xml,,,,,,,3545,242f4f8f93f5fbc6c8aeec500c9bac02dcfe68daba166d484c5cdc986c88d8ee,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/frelimo-e-zanu-pf-evocados-lacos-de-irmandade,200,text/html,Frelimo e Zanu-PF: Evocados laços de irmandade,62414,tempo,Categoria,2017-06-26T12:03:20+00:00,2017-06-26T12:03:20+00:00,47408,6b87be9796d5f1f2707ccce29f6dfc76a4c9ce0511f2e91b51333f2f799676e6,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/governo-dara-todo-o-apoio-a-pgr-no-seguimento-da-auditoria,200,text/html,Governo dará todo O apoio à PGR no seguimento da auditoria,62418,tempo,Categoria,2017-06-26T12:30:37+00:00,2017-06-26T12:30:45+00:00,49598,b771655708e07cecb4da3fba87c9474c5e5eb5c47ed2e8d8b5fba2cbc99440d6,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/governo-pretende-construir-100-mil-habitacoes-em-dois-anos,200,text/html,Governo pretende construir 100 mil habitações em dois anos,75002,tempo,Nas Redes,2017-08-04T20:01:55+00:00,2017-08-04T20:01:55+00:00,63563,3dbfba8e5a5df2b6337f623b45927031861d0843c12fd13109191fe74a1be790,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/guia-pratico-para-empregadores-sobre-contratacao-e-direitos-no-trabalho-domestico,200,text/html,Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico,173478,tempo,Trabalho Doméstico,2026-09-15T12:30:34+00:00,2026-09-15T12:30:37+00:00,84088,de793ec332602fbf9bd6310a4d13be43b6a2064d5adc03913a5c27069f2b50fd,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/images/android-chrome-512x512.png,200,image/png,,,,,,,15124,5cf3fb02d85cd40d2e88fb75749070fc981a9346c6419b2f9910e2f7f6961121,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/images/tempo-background.png,200,image/png,,,,,,,10636,28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa,biblioteca existente recursoQA25;URLs/versão originais preservados,RecursoQA25; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/imobiliario,200,text/html,Imobiliário,173218,tempo,Oportunidades,2026-06-16T11:34:45+00:00,2026-06-16T11:34:49+00:00,87978,c044ba5246951dfd1fff8d47db000dc6eba2e29b98b900922ac1cce9ed3467e6,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/infraestruturas,200,text/html,Infraestruturas,171992,tempo,Oportunidades,2026-04-06T09:25:07+00:00,2026-04-30T12:44:37+00:00,88068,fd5df9e47e8e427ca0ce2e558d3fed29ff1ab0a2e5886779fb375329e84d77a2,biblioteca existente recursoQA22;URLs/versão originais preservados,RecursoQA22; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel/,200,text/html,"Maputo Cidade – Plataforma Estratégica de Turismo, Negócios e Investimento Sustentável",172240,tempo,Turismo,2026-04-14T10:58:53+00:00,2026-04-14T11:03:28+00:00,123599,2d5d06531402bab1dd276669b78cce500cb903f6e540f886b832f6856f0d35cc,biblioteca existente recursoQA16;URLs/versão originais preservados,RecursoQA16; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/mercado-financeiro,200,text/html,Mercado Financeiro,171994,tempo,Oportunidades,2026-04-06T09:27:00+00:00,2026-04-17T09:53:42+00:00,87723,3cf0ac4e7acc897d842272465ffc2dd12967cb5484884eccd9107dd8375c3060,biblioteca existente recursoQA23;URLs/versão originais preservados,"RecursoQA23; original/hash/ClamD/replay demonstrados. Corpo vazio na origemHTML/Inertia200;privado,sem página publicada."
|
||||
https://investemoz.tempo.co.mz/modelo-de-contrato-de-trabalho-domestico-para-pequenas-familias,200,text/html,Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias,173480,tempo,Trabalho Doméstico,2026-09-15T12:34:17+00:00,2026-09-15T12:34:19+00:00,86922,93f3910de0a5ff8f3752a7d2fe73e0201d05b717cd4b37380cd584ab9ec087eb,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano/,200,text/html,Niassa - O último grande destino virgem do turismo africano,172219,tempo,Turismo,2026-04-14T10:17:14+00:00,2026-04-14T10:43:56+00:00,126058,cad44af1c05e0d76579dbab7112b35d18938b80156fb58f4580e583fc905976f,biblioteca existente recursoQA21;URLs/versão originais preservados,RecursoQA21; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/procedimentos-para-rescisao-do-contrato-de-trabalho-domestico-segundo-o-regulamento-de-mocambique,200,text/html,Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique,173476,tempo,Trabalho Doméstico,2026-09-15T11:39:21+00:00,2026-09-15T11:39:24+00:00,85371,a76a8c9f6ef4b039a9349f52e8d2f0ce06020ce8101d2736e3c6e0b2e76c7d58,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel,200,text/html,"Província da Zambézia: Onde os Corredores de Moçambique Convergem com a Natureza, a Cultura e o Turismo Sustentável",172263,tempo,Turismo,2026-04-14T14:21:52+00:00,2026-04-14T14:26:27+00:00,124167,e871558095c9d08329651084994266f61afd64eb72ecf85befdd2dbe099c1915,biblioteca existente recursoQA11;URLs/versão originais preservados,RecursoQA11; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique/,200,text/html,Província de Gaza: Oportunidades mais sólidas e estratégicas de investimento no turismo no sul de Moçambique.,172233,tempo,Turismo,2026-04-14T10:52:30+00:00,2026-04-17T08:28:56+00:00,123875,baf3c60fa77742c9b88a67937f9269c95284f3d5d371319009c9af2bdb6be140,biblioteca existente recursoQA18;URLs/versão originais preservados,RecursoQA18; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico/,200,text/html,Província de Inhambane: Um Destino Estratégico para Investimento Turístico,172253,tempo,Turismo,2026-04-14T14:15:12+00:00,2026-04-14T14:25:44+00:00,123445,35829f3b9725650ad51ad7b84f149ddde2157202c17083b1faec4212f5305df6,biblioteca existente recursoQA15;URLs/versão originais preservados,RecursoQA15; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento/,200,text/html,"Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento",172258,tempo,Turismo,2026-04-14T14:18:28+00:00,2026-04-17T10:42:16+00:00,123841,f1ffc7cb73f68643e8ca5883c187bc7b8bb125d9f907ae190d1503d0877c9968,biblioteca existente recursoQA14;URLs/versão originais preservados,RecursoQA14; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-maputo-turismo/,200,text/html,"Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável",172237,tempo,Turismo,2026-04-14T10:55:21+00:00,2026-04-17T08:27:24+00:00,123013,71887a836c75fc67b80a6a83be2a2af23b93acbd5aa353f42c75f598544ac46a,biblioteca existente recursoQA17;URLs/versão originais preservados,RecursoQA17; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo/,200,text/html,Província de Nampula - Perfil de investimento no setor do turismo,172230,tempo,Turismo,2026-04-14T10:50:32+00:00,2026-04-14T11:10:23+00:00,123337,148faca42ca44da6017fbd46e23de27fd497d36f9f8b1b695e0ea3f35474fcbb,biblioteca existente recursoQA19;URLs/versão originais preservados,RecursoQA19; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem/,200,text/html,"Província de Sofala: Onde a Natureza, a História e o Futuro do Turismo Convergem",172256,tempo,Turismo,2026-04-14T14:16:47+00:00,2026-04-14T14:26:17+00:00,123519,5100b90cb6c67fb36ce171ebf04c6801fe3ead214bcff26f942f6946fcd3add0,biblioteca existente recursoQA12;URLs/versão originais preservados,RecursoQA12; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo/,200,text/html,"Província de Tete: Onde o Rio Zambeze, a Cultura Viva e a Conservação Comunitária Criam o Futuro do Turismo",172261,tempo,Turismo,2026-04-14T14:19:48+00:00,2026-04-14T14:26:25+00:00,123849,8e28ccbeed95208d8766bfbc57b5b4b398d5787ea5aac922daa59e596ca58511,biblioteca existente recursoQA13;URLs/versão originais preservados,RecursoQA13; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao,200,text/html,Rofino Licuco preso cinco meses depois de condenado por agressão,73246,tempo,Nas Redes,2017-07-28T20:23:11+00:00,2017-07-28T20:23:11+00:00,63685,0b8053aa5c5a8ee29648394dd7e0a84dd0eb095776c5f3d88b3b59c47f1ae233,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/sete-individuos-mortos-a-tiro-na-matola,200,text/html,Sete indivíduos mortos a tiro na Matola,77232,tempo,Nas Redes,2017-08-11T20:30:32+00:00,2017-08-11T20:30:32+00:00,63135,f903b084f891f13467121990c3deccd2b995c036e9eaa9124ebe53dc2d04c081,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india,200,text/html,Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia,62416,tempo,Categoria,2017-06-26T12:14:48+00:00,2017-06-26T12:14:48+00:00,45244,a193cf19595a6e3de307d0307c3c96bc819d5075678e91ac9ebc5681185f4a89,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/tech-fintech,200,text/html,Fintech,173209,tempo,Oportunidades,2026-06-16T11:24:22+00:00,2026-06-23T10:03:06+00:00,88010,3b3b525c5d7ef34b5b9a1023aea5e6bc70c619672b5d173e6d9fe767782ab2d3,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/turismo,200,text/html,Turismo,171990,tempo,Oportunidades,2026-04-06T09:22:51+00:00,2026-06-16T13:07:59+00:00,87984,b7b4b2f9d9c4fc3a993e97ecdccb48f70ec9f560e13b15a9aad7205d88d22126,biblioteca existente recursoQA10;URLs/versão originais preservados,RecursoQA10; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/74364-2,200,text/html,,74364,tempo,Categoria,2017-07-26T21:20:33+00:00,2017-07-26T21:20:33+00:00,43595,2da21e3e51ccfe3a095710c85c0f549f0d995f2a2cc29bdccb1bebdee10ba805,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique,200,text/html,"Cabo Delgado - Pemba, A capital do turismo costeiro do norte de Moçambique",172223,tempo,Turismo,2026-04-14T10:21:20+00:00,2026-04-14T10:41:05+00:00,123383,99a2d46fed61caf9c8313ec3a695e15608bd478177d3048c3bda7fa2281039e8,biblioteca existente recursoQA20;URLs/versão originais preservados,RecursoQA20; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo,200,text/html,Daúde Razaque já não é treinador da Liga Desportiva de Maputo,62929,tempo,Nas Redes,2017-06-27T16:41:43+00:00,2017-06-27T16:41:43+00:00,64169,80f4f83caa75dcef3df39d697bc9d7afd77468caea640f2bbdeda70960ef8f5d,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira,200,text/html,Daviz Simango não se incomoda com possível sucessão na Beira,62649,tempo,Nas Redes,2017-06-26T19:38:09+00:00,2017-06-26T19:38:09+00:00,64147,16981acbf74f0b85ae8abb4d4853aac8c05a68795b59913370672a4a57c9f1a1,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/direitos-e-deveres-do-trabalhador-domestico,200,text/html,Direitos e Deveres do Trabalhador Doméstico,173470,tempo,Trabalho Doméstico,2026-09-15T11:28:25+00:00,2026-09-15T11:28:28+00:00,86045,1821b7404c7761bd3ca1600fe1b0be0e63c98dc64800c30a3b228bca8dfe7ee3,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/energia,200,text/html,Energia,172679,tempo,Featured,2026-04-30T13:03:57+00:00,2026-04-30T13:28:48+00:00,59488,fe0f7fe20a980bee1f96277e25b2536eaa9941733d63fd39c8f018adcae0a6e8,biblioteca existente recursoQA8;URLs/versão originais preservados,RecursoQA8; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/energia/,200,text/html,Energia,172679,tempo,Featured,2026-04-30T13:03:57+00:00,2026-04-30T13:28:48+00:00,59490,69b5a62220e4f47037cc0c13c74a7c0c9d6b8845b260b12a317099ce4e560339,biblioteca existente recursoQA8;URLs/versão originais preservados,RecursoQA8; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango-2,200,text/html,"“Exigimos responsabilização dos agentes do crime”, Daviz Simango",62739,tempo,Nas Redes,2017-06-26T23:13:36+00:00,2017-06-26T23:13:36+00:00,64225,8eb9a45e56e65febc657c4aba0ddcce77239a5d9c59902a25717a09f4572b5f5,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida,200,text/html,Governo e parceiros reforçam mecanismos de controlo de HIV/Sida,62854,tempo,Nas Redes,2017-06-27T11:07:53+00:00,2017-06-27T11:07:53+00:00,64139,0bb91025f1790b9571ad761351ed2fbf52b4d7ee7f33c7e4bc7aee2e9c1c90b1,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento,200,text/html,Graça Machel diz que desnutrição é um problema de desenvolvimento,63128,tempo,Nas Redes,2017-06-27T22:01:59+00:00,2017-06-27T22:01:59+00:00,64267,4c7c9a780d23a580b9f229b2a965d0f6145e5950c8d56a963047d720905a09e4,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/images/ANO-2017/JUNHO/21/GOVERNADOR-in.gif,404,,,,,,,,,,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/in-dependencia,200,text/html,In dependência,63181,tempo,Nas Redes,2017-06-27T21:38:06+00:00,2017-06-27T21:38:06+00:00,63079,ec3bc03878819dfb5af3c6268b4a812010d177924489ac49190351ac0b2f5bd4,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/kroll-nao-descobriu-como-foram-gastos-2-bilioes-de-dolares-governo-de-nyusi-nao-apoiou-a-auditoria-criacao-da-proindicus-ematum-e-mam-nao-foi-para-protecao-da-zona-economica-exclusiva-2,200,text/html,"Kroll não descobriu como foram gastos 2 biliões de dólares; Governo de Nyusi não apoiou a Auditoria; criação da Proindicus, EMATUM e MAM não foi para proteção da Zona Económica Exclusiva",63146,tempo,Nas Redes,2017-06-27T19:30:01+00:00,2017-06-27T19:30:01+00:00,66959,9cf92d04143df86c4cd86bf0a372696da3463b71239e4b4d737d355ff09e7e76,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel,200,text/html,"Maputo Cidade – Plataforma Estratégica de Turismo, Negócios e Investimento Sustentável",172240,tempo,Turismo,2026-04-14T10:58:53+00:00,2026-04-14T11:03:28+00:00,123597,4a4a88ac0c6fdeb26bdfe7183c9b618075ceb1460875ace0b351e96a2f1dd9e9,biblioteca existente recursoQA16;URLs/versão originais preservados,RecursoQA16; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/mineracao,200,text/html,Mineração,172674,tempo,Featured,2026-04-30T13:12:09+00:00,2026-04-30T13:30:13+00:00,104140,803652cd4358d0b65a364a91ef916f6c5cbfe6bb539867e3d94b6ca36fbf10c7,biblioteca existente recursoQA9;URLs/versão originais preservados,RecursoQA9; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano,200,text/html,Niassa - O último grande destino virgem do turismo africano,172219,tempo,Turismo,2026-04-14T10:17:14+00:00,2026-04-14T10:43:56+00:00,126056,c19557c9937180420d7ae52d28fbc3aea51e1229eefe2e05a33f576f98bcd2d0,biblioteca existente recursoQA21;URLs/versão originais preservados,RecursoQA21; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/o-instituto-nacional-de-meteorologia-preve-o-seguinte-estado-do-tempo-para-esta-29,200,text/html,O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ...,62688,tempo,Nas Redes,2017-06-26T18:21:18+00:00,2017-06-26T18:21:18+00:00,64583,b1de67ebe5fefc505086bad0469295e41bf50f6f7aba7fe9e27f30220a14071f,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique,200,text/html,Província de Gaza: Oportunidades mais sólidas e estratégicas de investimento no turismo no sul de Moçambique.,172233,tempo,Turismo,2026-04-14T10:52:30+00:00,2026-04-17T08:28:56+00:00,123873,e2835df9992914631c34a5e3006e86277ddf135a0fc264f6ecf3811f778ac60d,biblioteca existente recursoQA18;URLs/versão originais preservados,RecursoQA18; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico,200,text/html,Província de Inhambane: Um Destino Estratégico para Investimento Turístico,172253,tempo,Turismo,2026-04-14T14:15:12+00:00,2026-04-14T14:25:44+00:00,123443,919876fd899936071aa7a56a76c357ae30370b29014db2b1e7837450a099f0bd,biblioteca existente recursoQA15;URLs/versão originais preservados,RecursoQA15; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento,200,text/html,"Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento",172258,tempo,Turismo,2026-04-14T14:18:28+00:00,2026-04-17T10:42:16+00:00,123839,37b9eebf01ccf49ff3832755aa91b2595bbb80729b7b7cc861558c556d3f4cb7,biblioteca existente recursoQA14;URLs/versão originais preservados,RecursoQA14; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-maputo-turismo,200,text/html,"Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável",172237,tempo,Turismo,2026-04-14T10:55:21+00:00,2026-04-17T08:27:24+00:00,123011,e6bbe002132682c1bbcf5cf7666dcc78dc18915c92bf298a5540db6c07935a23,biblioteca existente recursoQA17;URLs/versão originais preservados,RecursoQA17; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo,200,text/html,Província de Nampula - Perfil de investimento no setor do turismo,172230,tempo,Turismo,2026-04-14T10:50:32+00:00,2026-04-14T11:10:23+00:00,123335,704d23e4c838df4249894b550f087eb36b90797d61d26de82b829c8d2b7d444f,biblioteca existente recursoQA19;URLs/versão originais preservados,RecursoQA19; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem,200,text/html,"Província de Sofala: Onde a Natureza, a História e o Futuro do Turismo Convergem",172256,tempo,Turismo,2026-04-14T14:16:47+00:00,2026-04-14T14:26:17+00:00,123517,cc0d8bead12f2e42af60cdf10fb2412756e67c2c03ddc8d91c621e31e921933c,biblioteca existente recursoQA12;URLs/versão originais preservados,RecursoQA12; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo,200,text/html,"Província de Tete: Onde o Rio Zambeze, a Cultura Viva e a Conservação Comunitária Criam o Futuro do Turismo",172261,tempo,Turismo,2026-04-14T14:19:48+00:00,2026-04-14T14:26:25+00:00,123847,70ca06168749124e2eaae340b1396ccbe183a1e5dfd348dfd93575d9b3519205,biblioteca existente recursoQA13;URLs/versão originais preservados,RecursoQA13; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.
|
||||
https://investemoz.tempo.co.mz/sancoes-disciplinares-aplicaveis-a-trabalhadores-domesticos-segundo-o-regulamento-de-mocambique,200,text/html,Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique,173474,tempo,Trabalho Doméstico,2026-09-15T11:37:04+00:00,2026-09-15T11:37:06+00:00,86561,6af9a928c826dd6a756310c0f948cb0db8c1b8bd98ca15577faba528ba6f3cf3,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/dois-alunos-da-9a-classe-cairam-nas-maos-da-policia-da-republica-de-mocambique,200,text/html,Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (...,63248,tempo,Nas Redes,2017-06-28T11:30:01+00:00,2017-06-28T11:30:01+00:00,64573,be57946f86277610a1597e73eaedeaf55941de76aaef3f8eda77e3a92672a6f0,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/regulamento-do-trabalho-domestico,200,text/html,Regulamento do Trabalho Doméstico,173463,tempo,Trabalho Doméstico,2026-09-15T10:56:07+00:00,2026-09-15T12:41:44+00:00,93646,6cafa4cc6a5a327de0ca4c5d98fce5e10bf7152c1dc987aa42350034fd747e1c,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/build/assets/welcome-DyF43GB5.js,200,application/javascript,,,,,,,19506,c94067f98b9d24cc457a20ed759f6beec1dbf9675354299f6141ed6056e95ab0,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/assets/logos/1_COR.png,200,image/png,,,,,,,25390,73c30a98a87960fc388d33aaf9ed3a15c3123338f8e82e84c3538adb6d816c9c,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/images/hero/hero-1.png,200,image/png,,,,,,,2315768,3c9246169025b9b1b4d1d10fb51c1f644123984bde56c6c2d9bf869d851024fc,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/images/entidades/APIEX.jpg,200,image/jpeg,,,,,,,240665,e04e4da3a1478b34a14e1d92dbebdea5bdf9bfd645c942d785b184d63dc58c48,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/images/entidades/BM.png,200,image/png,,,,,,,369795,3a8deddcf90f2376e8fe28447724739ce57da64b26e6887ddade566871deeea6,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/images/entidades/BM.jpg,200,image/jpeg,,,,,,,15681,bb93f6bb51104d4fe9d0776a79bbf3b2978f31c6802884e6f0fc3d50056268ff,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/images/entidades/bvm.jpg,200,image/jpeg,,,,,,,296992,8d3e532137896c9319bab4422e836bd1232fa81babf4626efa8c411927052731,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/images/entidades/BMM.png,200,image/png,,,,,,,199364,a92c6ed17cf8769d97a0e70c5db31cc6de1b583a71e161b8b35a7eae21468122,biblioteca / correspondência por rever,inventariado; não importado
|
||||
https://investemoz.tempo.co.mz/images/hero/hero-3.jpg,200,image/jpeg,,,,,,,9875137,91377213b6286aca7ee4af90860a7dc7a75fa08a165ef7b3192081db43f92dff,biblioteca / correspondência por rever,inventariado; não importado
|
||||
URL,HTTP,Tipo,Título,ID legado,Autor,Categoria legado,Publicado,Modificado,Bytes,SHA256,Destino proposto,Situação,Situação anterior à reconciliação 15/10/2026,Recurso ativo,Coberto por,Dependência concreta,SHA256 corpo,Evidência atual
|
||||
https://investemoz.tempo.co.mz/,200,text/html,Informacao Publica,,,,,,8368,42a2f14ca41b028045e9f2b2bb70fa324feb811698d9223f913b0b002a309f89,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/agronegocio,200,text/html,Agronegocio,171985,tempo,Oportunidades,2026-04-06T09:19:07+00:00,2026-04-20T12:41:43+00:00,88030,0bcd03e0e73cdf9b0f1a3a686689ae1a5ed80e990dcc34c77c9627c32f9d156f,/agronegocio,publicado,piloto preparado,5,,,28383a11d95f13894381357d8f1227b33031d1d3ff74507da4ea8e5ce2470913,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/portal-do-investidor,200,text/html,Informacao Publica,,,,,,8368,f62485a612c9c8cc5765758614fdbcaafdd77e1d7eb35139c67045f40e638689,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/robots.txt,200,text/plain,,,,,,,153,70743fc5a6acd78ea3083b92220bbd775e9c37642843fa16b7e353726e839228,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/sitemap.xml,200,text/xml,,,,,,,7606912,8470ee4038c9d4b1d722edda9044d71ad3afdfd1817c9b41680d0b910d77d011,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://contentmanager.tempo.co.mz/wp-content/uploads/2026/04/Agronegocio.png,200,image/png,,,,,,,550888,5e3840705cf98226d1f189cf665aaa98cb05da96c645159a1332a1d429d642eb,biblioteca / correspondência por rever,publicado,piloto preparado,6,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://contentmanager.tempo.co.mz/wp-content/uploads/2026/04/Energia-Mineracao.png,200,image/png,,,,,,,534405,0a2c50d91dad3a6007544634540e0f61b11d3506682a5a19066bae03cdcba490,biblioteca existente recursoQA24;URLs/versão originais preservados,publicado,RecursoQA24; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,23,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://contentmanager.tempo.co.mz/wp-content/uploads/2026/04/Infraestruturas.png,200,image/png,,,,,,,363037,8e58544e49e719f9c865c91e07ef1030155a9e3d59260e6dc93e9c9e25674e39,biblioteca existente recursoQA27;URLs/versão originais preservados,publicado,RecursoQA27; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,26,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://contentmanager.tempo.co.mz/wp-content/uploads/2026/04/Mercado-Financeiro.png,200,image/png,,,,,,,708105,417b4a33468f360acef272ce3e4180c1d0a171980befa73ddb9a33de5a9d4c4e,biblioteca existente recursoQA28;URLs/versão originais preservados,dependência concreta — imagem de conteúdo vazio,RecursoQA28; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,,,Fica separada com Mercado Financeiro; publicação QA da imagem não autoriza ativo.,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://contentmanager.tempo.co.mz/wp-content/uploads/2026/04/Turismo.png,200,image/png,,,,,,,575317,fe9a2e382e385b35f6e61ae320e199a979678677fd327fb7d4b07d8ce0111c11,biblioteca existente recursoQA26;URLs/versão originais preservados,publicado,RecursoQA26; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,25,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz,200,text/html,Informacao Publica,,,,,,8368,db5c258c7a10d2d9ec91d378c153e1da53de4eef1dfa168b2dc666ba9aea36fc,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/1530-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo,200,text/html,15/30 costa do sol com dua na zona de mupulene muito lindo,62413,tempo,Categoria,2017-06-26T11:44:21+00:00,2017-06-26T11:44:21+00:00,46443,b9b6634f98240994fdd6a1d9f41012f9336e0a32e43a939710113802e0eca948,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/817802064_1_644x461_15-30-costa-do-sol-com-dua-na-zona-de-mupulene-muito-lindo-maputo.jpg | Referência não recolhida: https://www.olx.co.mz/imoveis-casas/terrenos/terrenos-venda/maputo-maputo/?search%5Bprivate_business%5D=private | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",c04ae821317ef556c01c3141ce75eeeeb5da7787e0c6849b1b3709b757edb9eb,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/aluminio-verde,200,text/html,Alumínio “Verde”,173220,tempo,Oportunidades,2026-06-16T12:41:02+00:00,2026-06-16T12:41:06+00:00,88028,b6667ab0ed4cb3eca5ba7d9e09b829697a84ac1338d94025eada726b0b84addd,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,Ausente da biblioteca ativa e QA; falta exemplar versionado no manifesto de um novo lote e extensão nominal do importador. | Slug ausente no mapa do leitor; falta ligação ao percurso/dossier fundamentada para este artigo. | Não há setor mestre Alumínio Verde com correspondência exata; fundamentar o agrupamento sem inventar vínculo a projeto ou criar setor automaticamente.,c61f05a56bb5a5f13d9d5d54dbefd270cf9ac40320917d77aaad76cac56c7b97,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/apple-touch-icon.png,200,image/png,,,,,,,1662,4001aa032ff113e1a268a9bbf1ab0fd9949439f9f54a85895956eb323aba977d,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique,200,text/html,Banco Mundial classifica de proibitivos juros praticados em Moçambique,73945,tempo,Nas Redes,2017-07-31T19:55:24+00:00,2017-07-31T19:55:24+00:00,63817,3b4535a181412bc95ef25725d32e997479328d6096f80046f95ca567233b1ce7,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://opais.sapo.mz/index.php/economia/38-economia/45893-banco-mundial-classifica-de-proibitivos-juros-praticados-em-mocambique.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Banco-Mundial-classifica-de-proibitivos-juros-praticados-em-Mo%C3%A7ambique.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1460805843956666 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",36ba82b8885b00a4ea2fd9e4b1d8cf304a8e78e591972682f0aa53717f648d19,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/bens-de-consumo-franquias,200,text/html,Bens de Consumo e Franquias,173213,tempo,Oportunidades,2026-06-16T11:31:06+00:00,2026-06-16T11:32:10+00:00,88150,c7287adeaf11d2d8a40b0dc6a7b35e83ca0e2f312e2ac314caa01f166c08e3f8,biblioteca / correspondência por rever,"Publicado no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados",inventariado; não importado,29,setores-fintech-QA-d5b4dc354265 DOC01; recurso ativo 29,Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz.,abd5f36a0c2b89d2989334137aae5d59b3158da38d556013ccd55deaa5069e92,outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json
|
||||
https://investemoz.tempo.co.mz/build/assets/app-5tyHq2tj.js,200,application/javascript,,,,,,,76449,befcbe0252f450f664935a51f077030a30ae5955487f863990f204822bb7da1b,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/build/assets/app-CChIcWcY.js,200,application/javascript,,,,,,,115,81538671d6a533184b030e29c12d953c5dc584fd27e57ded6a576634e439f077,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/build/assets/app-CshAeK4J.css,200,text/css,,,,,,,219921,4c5addbbbb41752b8d8b17e1f3545ec461ec2631af24891940d3afa7347ccb91,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/build/assets/vendor-core-CDlfZzJQ.js,200,application/javascript,,,,,,,460473,fd4fdef257763f052e34a444b691d7322f49425e61e36d5fb83da8f0c340538b,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/build/assets/vendor-i18n-BY-fwNFQ.js,200,application/javascript,,,,,,,53387,7e87c342349f3e03d817f42e5f4da03a53f924839bc3f491d3cdf09d9c7f5886,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique/,200,text/html,"Cabo Delgado - Pemba, A capital do turismo costeiro do norte de Moçambique",172223,tempo,Turismo,2026-04-14T10:21:20+00:00,2026-04-14T10:41:05+00:00,123385,2ea7aa8588d4055b7033c66197d819e48716fcbf9520dd39ffe1713ef75a22c2,biblioteca existente recursoQA20;URLs/versão originais preservados,publicado,RecursoQA20; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,20,,,c96b2430c44b8edc9cc1d0a7974c23290dd0207cff366fea8326bb28bcab8285,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/cdn-cgi/challenge-platform/scripts/jsd/main.js,200,application/javascript,,,,,,,22552,37f21e386bbbbaf80c7d98a667bbe049a55acfaebc7902fb88e56d03d5064e1d,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/checklist-para-contratacao-e-direitos-do-trabalho-domestico,200,text/html,Checklist para Contratação e Direitos do Trabalho Doméstico,173482,tempo,Trabalho Doméstico,2026-09-15T12:36:11+00:00,2026-09-15T12:36:14+00:00,86191,5e68de9c525c7779772fd5eb6f6e9e0a36ab93ca06ca4f2a686e2f0afa6482e2,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",309b51ebc53bf840f9014da733bc09f8d162138be4e6e9d5a72670e26cc8e482,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/coloque-o-seu-numero-para-o-grupo-de-whatsapp-venda-de-acessorios-de-computador,200,text/html,"Coloque o seu número para o grupo de whatsapp, venda de acessórios de computador",76474,tempo,Categoria,2017-08-08T17:29:51+00:00,2017-08-08T17:29:51+00:00,44204,d1c7794dd9ef8b223bad657753162b6a5a6f64ce52870b05440e5d3ec961fb52,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: https://www.facebook.com/photo.php?fbid=741844132690980&set=gm.1566816196708735&type=3 | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Coloque-o-seu-n%C3%BAmero-para-o-grupo-de-whatsapp-venda-de-acess%C3%B3rios-de-computador.jpg | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/1502293415_298_Coloque-o-seu-n%C3%BAmero-para-o-grupo-de-whatsapp-venda-de-acess%C3%B3rios-de-computador.jpg | Referência não recolhida: https://www.facebook.com/179463555444013/posts/1566816196708735 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",c8beeb94f936b3bfc69c720770bd84376e9f19b668d96185aaefbada05727010,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/direitos-especiais-da-trabalhadora-domestica-no-regulamento,200,text/html,Direitos Especiais da Trabalhadora Doméstica no Regulamento,173484,tempo,Trabalho Doméstico,2026-09-15T12:38:08+00:00,2026-09-15T12:38:11+00:00,86424,b7aeb6d6143a2925a220bb899af2cac8363c542d0f1f337b72191f4994793aa6,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",34c31bb02a3ad0886f12ac2853283de2ffb89a925be3cda73b7ce9385c6caec4,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/energia-mineracao,200,text/html,Energia & Mineração,171981,tempo,Oportunidades,2026-04-06T09:17:46+00:00,2026-04-30T13:35:32+00:00,60048,f0d3fb494743c7dbec389fd3650754402135ceb6f2293ae6cef00fd0af93cbad,biblioteca existente recursoQA7;URLs/versão originais preservados,publicado,RecursoQA7; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,7,,,e9a95f0c8176eea48a75bd2c5bce69f15308806988fa5203a688af7c40305e9c,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/energia-recursos-naturais,200,text/html,Energia e Recursos Naturais,173222,tempo,Oportunidades,2026-06-16T12:47:16+00:00,2026-06-16T12:51:30+00:00,88150,718e69adfa50a11de8aeda60209afc0cbff1fd0c2be4bcb18ff59c43abed356a,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Ausente da biblioteca ativa e QA; falta exemplar versionado no manifesto de um novo lote e extensão nominal do importador. | Slug ausente no mapa do leitor; falta ligação ao percurso/dossier fundamentada para este artigo. | Texto distinto de Energia/Mineração já publicado; preservar a ligação declarada /energia-mineracao e delimitar agrupamento, sem fundir os exemplares.",6f8236b0441d61fce5171994ba6b82ffc8b5f2de3e8242de7be29248ed046ad2,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/favicon.ico,200,image/x-icon,,,,,,,15406,87f9c3a47246509b030080e505c103b48e93f3451ff84f0af38daa9164ce5356,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/favicon.svg,200,image/svg+xml,,,,,,,3545,242f4f8f93f5fbc6c8aeec500c9bac02dcfe68daba166d484c5cdc986c88d8ee,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/frelimo-e-zanu-pf-evocados-lacos-de-irmandade,200,text/html,Frelimo e Zanu-PF: Evocados laços de irmandade,62414,tempo,Categoria,2017-06-26T12:03:20+00:00,2017-06-26T12:03:20+00:00,47408,6b87be9796d5f1f2707ccce29f6dfc76a4c9ce0511f2e91b51333f2f799676e6,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência indisponível na captura (HTTP 404): https://investemoz.tempo.co.mz/images/ANO-2017/JUNHO/21/GOVERNADOR-in.gif | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",013307965b8fcb349a0d936d844ed12437bda4c90389f8efe958d4ffdb9ce62b,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/governo-dara-todo-o-apoio-a-pgr-no-seguimento-da-auditoria,200,text/html,Governo dará todo O apoio à PGR no seguimento da auditoria,62418,tempo,Categoria,2017-06-26T12:30:37+00:00,2017-06-26T12:30:45+00:00,49598,b771655708e07cecb4da3fba87c9474c5e5eb5c47ed2e8d8b5fba2cbc99440d6,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/a84c6c1e4d1780f63086a86817521b40 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",65299b6711499e417be778b51c7ab7880616b0ccbf362854370eb775fc54caf3,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/governo-pretende-construir-100-mil-habitacoes-em-dois-anos,200,text/html,Governo pretende construir 100 mil habitações em dois anos,75002,tempo,Nas Redes,2017-08-04T20:01:55+00:00,2017-08-04T20:01:55+00:00,63563,3dbfba8e5a5df2b6337f623b45927031861d0843c12fd13109191fe74a1be790,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45963-governo-pretende-construir-100-mil-habitacoes-em-dois-anos.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Governo-pretende-construir-100-mil-habita%C3%A7%C3%B5es-em-dois-anos.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1464602060243711 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",b32ea95039c2af387687738ed601f0947384eb7e19ca4bd282d603c60ca26afa,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/guia-pratico-para-empregadores-sobre-contratacao-e-direitos-no-trabalho-domestico,200,text/html,Guia Prático para Empregadores sobre Contratação e Direitos no Trabalho Doméstico,173478,tempo,Trabalho Doméstico,2026-09-15T12:30:34+00:00,2026-09-15T12:30:37+00:00,84088,de793ec332602fbf9bd6310a4d13be43b6a2064d5adc03913a5c27069f2b50fd,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",8038d8c221ba3cbbc4712304a6b17a6bba8ad946c8bac1a7836d472944aaf930,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/images/android-chrome-512x512.png,200,image/png,,,,,,,15124,5cf3fb02d85cd40d2e88fb75749070fc981a9346c6419b2f9910e2f7f6961121,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/images/tempo-background.png,200,image/png,,,,,,,10636,28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa,biblioteca existente recursoQA25;URLs/versão originais preservados,publicado,RecursoQA25; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,24,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/imobiliario,200,text/html,Imobiliário,173218,tempo,Oportunidades,2026-06-16T11:34:45+00:00,2026-06-16T11:34:49+00:00,87978,c044ba5246951dfd1fff8d47db000dc6eba2e29b98b900922ac1cce9ed3467e6,biblioteca / correspondência por rever,"Publicado no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados",inventariado; não importado,28,setores-fintech-QA-d5b4dc354265 DOC01; recurso ativo 28,Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz.,be8b606f087a939bd88a86f4436a0ff18c5fb774a179e6e915d4abb10a95f930,outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json
|
||||
https://investemoz.tempo.co.mz/infraestruturas,200,text/html,Infraestruturas,171992,tempo,Oportunidades,2026-04-06T09:25:07+00:00,2026-04-30T12:44:37+00:00,88068,fd5df9e47e8e427ca0ce2e558d3fed29ff1ab0a2e5886779fb375329e84d77a2,biblioteca existente recursoQA22;URLs/versão originais preservados,publicado,RecursoQA22; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,22,,,9716da16aba58eec173343f0bbd582d62d23a5eee7d20522c080c2da5da8ba66,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel/,200,text/html,"Maputo Cidade – Plataforma Estratégica de Turismo, Negócios e Investimento Sustentável",172240,tempo,Turismo,2026-04-14T10:58:53+00:00,2026-04-14T11:03:28+00:00,123599,2d5d06531402bab1dd276669b78cce500cb903f6e540f886b832f6856f0d35cc,biblioteca existente recursoQA16;URLs/versão originais preservados,publicado,RecursoQA16; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,16,,,0866639d09c5c0b3b00e8527554065587c793f60df978b66b6a578b3c741bc0d,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/mercado-financeiro,200,text/html,Mercado Financeiro,171994,tempo,Oportunidades,2026-04-06T09:27:00+00:00,2026-04-17T09:53:42+00:00,87723,3cf0ac4e7acc897d842272465ffc2dd12967cb5484884eccd9107dd8375c3060,biblioteca existente recursoQA23;URLs/versão originais preservados,vazio — dependência concreta,"RecursoQA23; original/hash/ClamD/replay demonstrados. Corpo vazio na origemHTML/Inertia200;privado,sem página publicada.",,,Corpo do artigo vazio; imagem não substitui conteúdo.,e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/modelo-de-contrato-de-trabalho-domestico-para-pequenas-familias,200,text/html,Modelo de Contrato de Trabalho Doméstico para Pequenas Famílias,173480,tempo,Trabalho Doméstico,2026-09-15T12:34:17+00:00,2026-09-15T12:34:19+00:00,86922,93f3910de0a5ff8f3752a7d2fe73e0201d05b717cd4b37380cd584ab9ec087eb,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",5b95ad9010fcbdc1000052f47766ca54409d3e0649211729ced9ef142f5c6db0,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano/,200,text/html,Niassa - O último grande destino virgem do turismo africano,172219,tempo,Turismo,2026-04-14T10:17:14+00:00,2026-04-14T10:43:56+00:00,126058,cad44af1c05e0d76579dbab7112b35d18938b80156fb58f4580e583fc905976f,biblioteca existente recursoQA21;URLs/versão originais preservados,publicado,RecursoQA21; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,21,,,47d82a59a86c3cbdef04ea065e711e7139d50137e440f03efbd710e3c4220ef7,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/procedimentos-para-rescisao-do-contrato-de-trabalho-domestico-segundo-o-regulamento-de-mocambique,200,text/html,Procedimentos para Rescisão do Contrato de Trabalho Doméstico segundo o Regulamento de Moçambique,173476,tempo,Trabalho Doméstico,2026-09-15T11:39:21+00:00,2026-09-15T11:39:24+00:00,85371,a76a8c9f6ef4b039a9349f52e8d2f0ce06020ce8101d2736e3c6e0b2e76c7d58,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",bb634a9021da9d7b46ed105317aa54e4af42a16dab042e0ceb2bdc0d702d1a67,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-da-zambezia-onde-os-corredores-de-mocambique-convergem-com-a-natureza-a-cultura-e-o-turismo-sustentavel,200,text/html,"Província da Zambézia: Onde os Corredores de Moçambique Convergem com a Natureza, a Cultura e o Turismo Sustentável",172263,tempo,Turismo,2026-04-14T14:21:52+00:00,2026-04-14T14:26:27+00:00,124167,e871558095c9d08329651084994266f61afd64eb72ecf85befdd2dbe099c1915,biblioteca existente recursoQA11;URLs/versão originais preservados,publicado,RecursoQA11; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,11,,,9e7ca4e9542135d5969f5c008ce8e29b037cc06a53875cfa7dc3e7452ec47744,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique/,200,text/html,Província de Gaza: Oportunidades mais sólidas e estratégicas de investimento no turismo no sul de Moçambique.,172233,tempo,Turismo,2026-04-14T10:52:30+00:00,2026-04-17T08:28:56+00:00,123875,baf3c60fa77742c9b88a67937f9269c95284f3d5d371319009c9af2bdb6be140,biblioteca existente recursoQA18;URLs/versão originais preservados,publicado,RecursoQA18; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,18,,,2bf2df9bd3b7ab8656209a48f4928b5d8bbf2959e77c292fc4c9987e67ba2fea,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico/,200,text/html,Província de Inhambane: Um Destino Estratégico para Investimento Turístico,172253,tempo,Turismo,2026-04-14T14:15:12+00:00,2026-04-14T14:25:44+00:00,123445,35829f3b9725650ad51ad7b84f149ddde2157202c17083b1faec4212f5305df6,biblioteca existente recursoQA15;URLs/versão originais preservados,publicado,RecursoQA15; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,15,,,2d1cc729481ce65a5e50898c0eea4a1eb2418273b03fc749009e2ffaaa72fe71,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento/,200,text/html,"Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento",172258,tempo,Turismo,2026-04-14T14:18:28+00:00,2026-04-17T10:42:16+00:00,123841,f1ffc7cb73f68643e8ca5883c187bc7b8bb125d9f907ae190d1503d0877c9968,biblioteca existente recursoQA14;URLs/versão originais preservados,publicado,RecursoQA14; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,14,,,4c8bdd79212ba98fa347733e2f58aef8796b29cc8cb8b649d200bd37435df1c3,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-maputo-turismo/,200,text/html,"Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável",172237,tempo,Turismo,2026-04-14T10:55:21+00:00,2026-04-17T08:27:24+00:00,123013,71887a836c75fc67b80a6a83be2a2af23b93acbd5aa353f42c75f598544ac46a,biblioteca existente recursoQA17;URLs/versão originais preservados,publicado,RecursoQA17; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,17,,,d112d0e535912f4487c2b8d41978e5e663f1db43f1a2cdf170dbbec535f13f27,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo/,200,text/html,Província de Nampula - Perfil de investimento no setor do turismo,172230,tempo,Turismo,2026-04-14T10:50:32+00:00,2026-04-14T11:10:23+00:00,123337,148faca42ca44da6017fbd46e23de27fd497d36f9f8b1b695e0ea3f35474fcbb,biblioteca existente recursoQA19;URLs/versão originais preservados,publicado,RecursoQA19; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,19,,,d18ccc1e036b3480605462ce7176be75153f6aa988bc9b37d8d395b01e555a7a,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem/,200,text/html,"Província de Sofala: Onde a Natureza, a História e o Futuro do Turismo Convergem",172256,tempo,Turismo,2026-04-14T14:16:47+00:00,2026-04-14T14:26:17+00:00,123519,5100b90cb6c67fb36ce171ebf04c6801fe3ead214bcff26f942f6946fcd3add0,biblioteca existente recursoQA12;URLs/versão originais preservados,publicado,RecursoQA12; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,12,,,12b46a34ba61c6ef0058a6c410ebc17329d897fe4b06a13b4ea3fe3c85a28342,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo/,200,text/html,"Província de Tete: Onde o Rio Zambeze, a Cultura Viva e a Conservação Comunitária Criam o Futuro do Turismo",172261,tempo,Turismo,2026-04-14T14:19:48+00:00,2026-04-14T14:26:25+00:00,123849,8e28ccbeed95208d8766bfbc57b5b4b398d5787ea5aac922daa59e596ca58511,biblioteca existente recursoQA13;URLs/versão originais preservados,publicado,RecursoQA13; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,13,,,e78fce2931260a7d6f82270897e906feb640f65d084c2d4ffb5ba19303858275,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao,200,text/html,Rofino Licuco preso cinco meses depois de condenado por agressão,73246,tempo,Nas Redes,2017-07-28T20:23:11+00:00,2017-07-28T20:23:11+00:00,63685,0b8053aa5c5a8ee29648394dd7e0a84dd0eb095776c5f3d88b3b59c47f1ae233,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45870-rofino-licuco-preso-cinco-meses-depois-de-condenado-por-agressao-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Rofino-Licuco-preso-cinco-meses-depois-de-condenado-por-agress%C3%A3o.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1458270617543522 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",806c54948641f4f5933a2ea4a6935dfb7a67202ab227960451d62435880289f6,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/sete-individuos-mortos-a-tiro-na-matola,200,text/html,Sete indivíduos mortos a tiro na Matola,77232,tempo,Nas Redes,2017-08-11T20:30:32+00:00,2017-08-11T20:30:32+00:00,63135,f903b084f891f13467121990c3deccd2b995c036e9eaa9124ebe53dc2d04c081,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/46074-sete-individuos-mortos-a-tiro-na-matola-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Sete-indiv%C3%ADduos-mortos-a-tiro-na-Matola.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1471269102910340 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",e657a97d5d6db7fa0ea6b7d14029ff873ea5d36dfdadda5f8b9bc8f1ef5dd011,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india,200,text/html,Sete pessoas morrem e 150 são resgatados em acidente com eléctrico na Índia,62416,tempo,Categoria,2017-06-26T12:14:48+00:00,2017-06-26T12:14:48+00:00,45244,a193cf19595a6e3de307d0307c3c96bc819d5075678e91ac9ebc5681185f4a89,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://www.verdade.co.mz/internacional/62604-sete-pessoas-morrem-e-150-sao-resgatados-em-acidente-com-electrico-na-india | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",0fe20a9ca9dd99c58072f43b3dece1de347ef4063ee5f75bcffe8b2f4bf253b5,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/tech-fintech,200,text/html,Fintech,173209,tempo,Oportunidades,2026-06-16T11:24:22+00:00,2026-06-23T10:03:06+00:00,88010,3b3b525c5d7ef34b5b9a1023aea5e6bc70c619672b5d173e6d9fe767782ab2d3,biblioteca / correspondência por rever,"Publicado no ativo — setores-fintech-QA-d5b4dc354265 DOC01; importação privada, scan, metadados e publicação separados",inventariado; não importado,27,setores-fintech-QA-d5b4dc354265 DOC01; recurso ativo 27,Entrega concluída; nenhum novo envio ou republicação da imagem. Regulação específica Fintech permanece na matriz.,8db9206bf5192b68e7c9bdfb87e9dc9c7063a4b7eca56630685b0e6c294f55ab,outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md; PROVA-DELTA-QA.json; HTTP-DELTA-QA.json; PROVA-FINAL-DELTA-QA.json; HTTP-RECUPERACAO-FINAL-QA.json; MANIFESTO-ENTREGA.json | outputs/investmoz-setores-fintech-ativacao-20261015/RELATORIO-ENTREGA.md; PUBLISHED.json; PRESERVACAO-FINAL.json; HTTP-OPERACIONAL.json; FRESH-BACKUP.json; RECIBO-FINAL.json
|
||||
https://investemoz.tempo.co.mz/turismo,200,text/html,Turismo,171990,tempo,Oportunidades,2026-04-06T09:22:51+00:00,2026-06-16T13:07:59+00:00,87984,b7b4b2f9d9c4fc3a993e97ecdccb48f70ec9f560e13b15a9aad7205d88d22126,biblioteca existente recursoQA10;URLs/versão originais preservados,publicado,RecursoQA10; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,10,,,604d30a740cc6ed20d24e3447806e733aa4aefb9f339f81d3dc57b644dd19fb7,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/74364-2,200,text/html,,74364,tempo,Categoria,2017-07-26T21:20:33+00:00,2017-07-26T21:20:33+00:00,43595,2da21e3e51ccfe3a095710c85c0f549f0d995f2a2cc29bdccb1bebdee10ba805,biblioteca / correspondência por rever,dependência concreta — título ausente,inventariado; não importado,,,Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/1501695692_133_notitle.jpg | Referência não recolhida: https://www.facebook.com/179463555444013/posts/1552815684775453 | Título vazio no post 74364; corpo com 20 caracteres; identidade editorial a esclarecer sem inventar título.,2a7f0a5b09e0136fec9eae357ac8a88a159ead23b25ed7bb735c75997b10ec5e,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique,200,text/html,"Cabo Delgado - Pemba, A capital do turismo costeiro do norte de Moçambique",172223,tempo,Turismo,2026-04-14T10:21:20+00:00,2026-04-14T10:41:05+00:00,123383,99a2d46fed61caf9c8313ec3a695e15608bd478177d3048c3bda7fa2281039e8,biblioteca existente recursoQA20;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA20; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,20,https://investemoz.tempo.co.mz/cabo-delgado-pemba-a-capital-do-turismo-costeiro-do-norte-de-mocambique/,,c96b2430c44b8edc9cc1d0a7974c23290dd0207cff366fea8326bb28bcab8285,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo,200,text/html,Daúde Razaque já não é treinador da Liga Desportiva de Maputo,62929,tempo,Nas Redes,2017-06-27T16:41:43+00:00,2017-06-27T16:41:43+00:00,64169,80f4f83caa75dcef3df39d697bc9d7afd77468caea640f2bbdeda70960ef8f5d,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://opais.sapo.mz/index.php/desporto/74-desporto/45358-daude-razaque-ja-nao-e-treinador-da-liga-desportiva-de-maputo.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Da%C3%BAde-Razaque-j%C3%A1-n%C3%A3o-%C3%A9-treinador-da-Liga-Desportiva-de-Maputo.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1425759480794636 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",c3b57ea685290bfb01c50403bc83db98cf1a42ad51c04d5b8d288c99b8c0a808,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira,200,text/html,Daviz Simango não se incomoda com possível sucessão na Beira,62649,tempo,Nas Redes,2017-06-26T19:38:09+00:00,2017-06-26T19:38:09+00:00,64147,16981acbf74f0b85ae8abb4d4853aac8c05a68795b59913370672a4a57c9f1a1,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://opais.sapo.mz/index.php/politica/63-politica/45340-daviz-simango-nao-se-incomoda-com-possivel-sucessao-na-beira-.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Daviz-Simango-n%C3%A3o-se-incomoda-com-poss%C3%ADvel-sucess%C3%A3o-na-Beira.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1424683617568889 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",090e5f41ed11c8e680d2e30ea5c8310b7c6b165ddec318a8b0cf94927f78da74,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/direitos-e-deveres-do-trabalhador-domestico,200,text/html,Direitos e Deveres do Trabalhador Doméstico,173470,tempo,Trabalho Doméstico,2026-09-15T11:28:25+00:00,2026-09-15T11:28:28+00:00,86045,1821b7404c7761bd3ca1600fe1b0be0e63c98dc64800c30a3b228bca8dfe7ee3,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",f69fd6fd8509913f2d79df0267c469dc7a9d0d30420ce8428749d53ba21446ab,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/energia,200,text/html,Energia,172679,tempo,Featured,2026-04-30T13:03:57+00:00,2026-04-30T13:28:48+00:00,59488,fe0f7fe20a980bee1f96277e25b2536eaa9941733d63fd39c8f018adcae0a6e8,biblioteca existente recursoQA8;URLs/versão originais preservados,publicado,RecursoQA8; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,8,,,e2a7eb4be0a2cf4139737f6428c147ac35de99899478ce79195dc5e1b0a960f3,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/energia/,200,text/html,Energia,172679,tempo,Featured,2026-04-30T13:03:57+00:00,2026-04-30T13:28:48+00:00,59490,69b5a62220e4f47037cc0c13c74a7c0c9d6b8845b260b12a317099ce4e560339,biblioteca existente recursoQA8;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA8; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,8,https://investemoz.tempo.co.mz/energia,,e2a7eb4be0a2cf4139737f6428c147ac35de99899478ce79195dc5e1b0a960f3,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango-2,200,text/html,"“Exigimos responsabilização dos agentes do crime”, Daviz Simango",62739,tempo,Nas Redes,2017-06-26T23:13:36+00:00,2017-06-26T23:13:36+00:00,64225,8eb9a45e56e65febc657c4aba0ddcce77239a5d9c59902a25717a09f4572b5f5,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://opais.sapo.mz/index.php/politica/63-politica/45345-exigimos-responsabilizacao-dos-agentes-do-crime-daviz-simango.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/%E2%80%9CExigimos-responsabiliza%C3%A7%C3%A3o-dos-agentes-do-crime%E2%80%9D-Daviz-Simango.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1424873994216518 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",e37ea18176246dab529d2ecec7734f0fb2b0a54cadc507fbd789033d5b8e5b93,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida,200,text/html,Governo e parceiros reforçam mecanismos de controlo de HIV/Sida,62854,tempo,Nas Redes,2017-06-27T11:07:53+00:00,2017-06-27T11:07:53+00:00,64139,0bb91025f1790b9571ad761351ed2fbf52b4d7ee7f33c7e4bc7aee2e9c1c90b1,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45352-governo-e-parceiros-reforcam-mecanismos-de-controlo-de-hivsida.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Governo-e-parceiros-refor%C3%A7am-mecanismos-de-controlo-de-HIVSida.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1425451974158720 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",0073816b1fa4bd50ec6417b07272da06565230d06a19079ca76cb006c882d2f1,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento,200,text/html,Graça Machel diz que desnutrição é um problema de desenvolvimento,63128,tempo,Nas Redes,2017-06-27T22:01:59+00:00,2017-06-27T22:01:59+00:00,64267,4c7c9a780d23a580b9f229b2a965d0f6145e5950c8d56a963047d720905a09e4,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://opais.sapo.mz/index.php/sociedade/45-sociedade/45368-graca-machel-diz-que-desnutricao-e-um-problema-de-desenvolvimento.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Gra%C3%A7a-Machel-diz-que-desnutri%C3%A7%C3%A3o-%C3%A9-um-problema-de-desenvolvimento.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1426040144099903 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",711f3707e3a0d72ec919216fc50823de9060349104ee98fe0a6b20d6684b6031,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/images/ANO-2017/JUNHO/21/GOVERNADOR-in.gif,404,,,,,,,,,,biblioteca / correspondência por rever,dependência concreta — ficheiro indisponível,inventariado; não importado,,,HTTP 404 na captura; não afirmar estado atual nem substituir silenciosamente.,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/in-dependencia,200,text/html,In dependência,63181,tempo,Nas Redes,2017-06-27T21:38:06+00:00,2017-06-27T21:38:06+00:00,63079,ec3bc03878819dfb5af3c6268b4a812010d177924489ac49190351ac0b2f5bd4,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://opais.sapo.mz/index.php/opiniao/182-helder-faife/45364-in-dependencia.html | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/In-depend%C3%AAncia.jpg | Referência não recolhida: https://www.facebook.com/196034093767187/posts/1426022220768362 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",b0d87c0d58d6d1343d102cd3141bda1215c5afd54f3780a1c6c262d786dbfe27,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/kroll-nao-descobriu-como-foram-gastos-2-bilioes-de-dolares-governo-de-nyusi-nao-apoiou-a-auditoria-criacao-da-proindicus-ematum-e-mam-nao-foi-para-protecao-da-zona-economica-exclusiva-2,200,text/html,"Kroll não descobriu como foram gastos 2 biliões de dólares; Governo de Nyusi não apoiou a Auditoria; criação da Proindicus, EMATUM e MAM não foi para proteção da Zona Económica Exclusiva",63146,tempo,Nas Redes,2017-06-27T19:30:01+00:00,2017-06-27T19:30:01+00:00,66959,9cf92d04143df86c4cd86bf0a372696da3463b71239e4b4d737d355ff09e7e76,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://www.verdade.co.mz/tema-de-fundo/35/62615 | Referência não recolhida: http://www.newsaiep.com/moz_news/wp-content/uploads/Kroll-n%C3%A3o-descobriu-como-foram-gastos-2-bili%C3%B5es-de-d%C3%B3lares-Governo-de-Nyusi-n%C3%A3o-apoiou-a-Auditoria-cria%C3%A7%C3%A3o-da-Proindicus-EMATUM-e-MAM-n%C3%A3o-foi-para-prote%C3%A7%C3%A3o-da-Zona-Econ%C3%B3mica-Exclusiva.jpg | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1492451004109920 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",4ccbad5c92ddc3884f58181a4f1ed3c1d3d6a59f005bfd99b197a6fc1fc3c280,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel,200,text/html,"Maputo Cidade – Plataforma Estratégica de Turismo, Negócios e Investimento Sustentável",172240,tempo,Turismo,2026-04-14T10:58:53+00:00,2026-04-14T11:03:28+00:00,123597,4a4a88ac0c6fdeb26bdfe7183c9b618075ceb1460875ace0b351e96a2f1dd9e9,biblioteca existente recursoQA16;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA16; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,16,https://investemoz.tempo.co.mz/maputo-cidade-plataforma-estrategica-de-turismo-negocios-e-investimento-sustentavel/,,0866639d09c5c0b3b00e8527554065587c793f60df978b66b6a578b3c741bc0d,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/mineracao,200,text/html,Mineração,172674,tempo,Featured,2026-04-30T13:12:09+00:00,2026-04-30T13:30:13+00:00,104140,803652cd4358d0b65a364a91ef916f6c5cbfe6bb539867e3d94b6ca36fbf10c7,biblioteca existente recursoQA9;URLs/versão originais preservados,publicado,RecursoQA9; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,9,,,8d3acc292ed806bc4cc7bcb6a3a6a5759f30b610766a5ef4b3d6a0b7c56d5861,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano,200,text/html,Niassa - O último grande destino virgem do turismo africano,172219,tempo,Turismo,2026-04-14T10:17:14+00:00,2026-04-14T10:43:56+00:00,126056,c19557c9937180420d7ae52d28fbc3aea51e1229eefe2e05a33f576f98bcd2d0,biblioteca existente recursoQA21;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA21; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,21,https://investemoz.tempo.co.mz/niassa-o-ultimo-grande-destino-virgem-do-turismo-africano/,,47d82a59a86c3cbdef04ea065e711e7139d50137e440f03efbd710e3c4220ef7,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/o-instituto-nacional-de-meteorologia-preve-o-seguinte-estado-do-tempo-para-esta-29,200,text/html,O Instituto Nacional de Meteorologia prevê o seguinte estado do tempo para esta ...,62688,tempo,Nas Redes,2017-06-26T18:21:18+00:00,2017-06-26T18:21:18+00:00,64583,b1de67ebe5fefc505086bad0469295e41bf50f6f7aba7fe9e27f30220a14071f,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://www.verdade.co.mz/newsflash/62607 | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1491493337539020 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",396fe2575641622015505eb11d4c7152b6e3e1b741966f14c0cd1673fd455fd3,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique,200,text/html,Província de Gaza: Oportunidades mais sólidas e estratégicas de investimento no turismo no sul de Moçambique.,172233,tempo,Turismo,2026-04-14T10:52:30+00:00,2026-04-17T08:28:56+00:00,123873,e2835df9992914631c34a5e3006e86277ddf135a0fc264f6ecf3811f778ac60d,biblioteca existente recursoQA18;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA18; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,18,https://investemoz.tempo.co.mz/provincia-de-gaza-oportunidades-mais-solidas-e-estrategicas-de-investimento-no-turismo-no-sul-de-mocambique/,,2bf2df9bd3b7ab8656209a48f4928b5d8bbf2959e77c292fc4c9987e67ba2fea,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico,200,text/html,Província de Inhambane: Um Destino Estratégico para Investimento Turístico,172253,tempo,Turismo,2026-04-14T14:15:12+00:00,2026-04-14T14:25:44+00:00,123443,919876fd899936071aa7a56a76c357ae30370b29014db2b1e7837450a099f0bd,biblioteca existente recursoQA15;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA15; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,15,https://investemoz.tempo.co.mz/provincia-de-inhambane-um-destino-estrategico-para-investimento-turistico/,,2d1cc729481ce65a5e50898c0eea4a1eb2418273b03fc749009e2ffaaa72fe71,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento,200,text/html,"Província de Manica: Onde o Turismo de Montanha, Natureza e Cultura Encontra o Próximo Ciclo de Investimento",172258,tempo,Turismo,2026-04-14T14:18:28+00:00,2026-04-17T10:42:16+00:00,123839,37b9eebf01ccf49ff3832755aa91b2595bbb80729b7b7cc861558c556d3f4cb7,biblioteca existente recursoQA14;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA14; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,14,https://investemoz.tempo.co.mz/provincia-de-manica-onde-o-turismo-de-montanha-natureza-e-cultura-encontra-o-proximo-ciclo-de-investimento/,,4c8bdd79212ba98fa347733e2f58aef8796b29cc8cb8b649d200bd37435df1c3,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-maputo-turismo,200,text/html,"Província de Maputo: Natureza, Cultura e Conectividade como Motores de Crescimento Sustentável",172237,tempo,Turismo,2026-04-14T10:55:21+00:00,2026-04-17T08:27:24+00:00,123011,e6bbe002132682c1bbcf5cf7666dcc78dc18915c92bf298a5540db6c07935a23,biblioteca existente recursoQA17;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA17; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,17,https://investemoz.tempo.co.mz/provincia-de-maputo-turismo/,,d112d0e535912f4487c2b8d41978e5e663f1db43f1a2cdf170dbbec535f13f27,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo,200,text/html,Província de Nampula - Perfil de investimento no setor do turismo,172230,tempo,Turismo,2026-04-14T10:50:32+00:00,2026-04-14T11:10:23+00:00,123335,704d23e4c838df4249894b550f087eb36b90797d61d26de82b829c8d2b7d444f,biblioteca existente recursoQA19;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA19; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,19,https://investemoz.tempo.co.mz/provincia-de-nampula-perfil-de-investimento-no-setor-do-turismo/,,d18ccc1e036b3480605462ce7176be75153f6aa988bc9b37d8d395b01e555a7a,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem,200,text/html,"Província de Sofala: Onde a Natureza, a História e o Futuro do Turismo Convergem",172256,tempo,Turismo,2026-04-14T14:16:47+00:00,2026-04-14T14:26:17+00:00,123517,cc0d8bead12f2e42af60cdf10fb2412756e67c2c03ddc8d91c621e31e921933c,biblioteca existente recursoQA12;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA12; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,12,https://investemoz.tempo.co.mz/provincia-de-sofala-onde-a-natureza-a-historia-e-o-futuro-do-turismo-convergem/,,12b46a34ba61c6ef0058a6c410ebc17329d897fe4b06a13b4ea3fe3c85a28342,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo,200,text/html,"Província de Tete: Onde o Rio Zambeze, a Cultura Viva e a Conservação Comunitária Criam o Futuro do Turismo",172261,tempo,Turismo,2026-04-14T14:19:48+00:00,2026-04-14T14:26:25+00:00,123847,70ca06168749124e2eaae340b1396ccbe183a1e5dfd348dfd93575d9b3519205,biblioteca existente recursoQA13;URLs/versão originais preservados,duplicado/versão coberta,RecursoQA13; original/hash/ClamD/replay demonstrados. DivulgaçãoQAseparada;consumidorHTTP/desktop observado;não é oportunidade nem geometria.,13,https://investemoz.tempo.co.mz/provincia-de-tete-onde-o-rio-zambeze-a-cultura-viva-e-a-conservacao-comunitaria-criam-o-futuro-do-turismo/,,e78fce2931260a7d6f82270897e906feb640f65d084c2d4ffb5ba19303858275,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/sancoes-disciplinares-aplicaveis-a-trabalhadores-domesticos-segundo-o-regulamento-de-mocambique,200,text/html,Sanções Disciplinares Aplicáveis a Trabalhadores Domésticos segundo o Regulamento de Moçambique,173474,tempo,Trabalho Doméstico,2026-09-15T11:37:04+00:00,2026-09-15T11:37:06+00:00,86561,6af9a928c826dd6a756310c0f948cb0db8c1b8bd98ca15577faba528ba6f3cf3,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",e09a0fe71397e2b060ff8435111117aa487b476a85ec522fffcdf9e23a6cdac2,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/dois-alunos-da-9a-classe-cairam-nas-maos-da-policia-da-republica-de-mocambique,200,text/html,Dois alunos da 9ª classe caíram nas mãos da Polícia da República de Moçambique (...,63248,tempo,Nas Redes,2017-06-28T11:30:01+00:00,2017-06-28T11:30:01+00:00,64573,be57946f86277610a1597e73eaedeaf55941de76aaef3f8eda77e3a92672a6f0,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Referência não recolhida: http://www.verdade.co.mz/newsflash/62625 | Referência não recolhida: https://www.facebook.com/113487338672967/posts/1493133914041629 | Notícia/anúncio histórico; definir destino de consulta e prioridade pela Tempo, sem converter em orientação atual ou oportunidade vigente.",2220ca2c07d10f10b2bd6fd0f103ee733b83570d436c751c449c85b42df46a13,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/regulamento-do-trabalho-domestico,200,text/html,Regulamento do Trabalho Doméstico,173463,tempo,Trabalho Doméstico,2026-09-15T10:56:07+00:00,2026-09-15T12:41:44+00:00,93646,6cafa4cc6a5a327de0ca4c5d98fce5e10bf7152c1dc987aa42350034fd747e1c,biblioteca / correspondência por rever,existente por integrar,inventariado; não importado,,,"Conteúdo editorial não oficial; falta recorte e ligação ao consumidor/apoio apropriado. Eventual uso jurídico ou cálculo requer citação/âmbito, sem revalidar credibilidade de fontes oficiais já aceites.",eb43b6c1f097631250f0b36d3d01b4d106db2fcae07a56bb154819143fff11e9,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/build/assets/welcome-DyF43GB5.js,200,application/javascript,,,,,,,19506,c94067f98b9d24cc457a20ed759f6beec1dbf9675354299f6141ed6056e95ab0,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/assets/logos/1_COR.png,200,image/png,,,,,,,25390,73c30a98a87960fc388d33aaf9ed3a15c3123338f8e82e84c3538adb6d816c9c,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/images/hero/hero-1.png,200,image/png,,,,,,,2315768,3c9246169025b9b1b4d1d10fb51c1f644123984bde56c6c2d9bf869d851024fc,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/images/entidades/APIEX.jpg,200,image/jpeg,,,,,,,240665,e04e4da3a1478b34a14e1d92dbebdea5bdf9bfd645c942d785b184d63dc58c48,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/images/entidades/BM.png,200,image/png,,,,,,,369795,3a8deddcf90f2376e8fe28447724739ce57da64b26e6887ddade566871deeea6,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/images/entidades/BM.jpg,200,image/jpeg,,,,,,,15681,bb93f6bb51104d4fe9d0776a79bbf3b2978f31c6802884e6f0fc3d50056268ff,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/images/entidades/bvm.jpg,200,image/jpeg,,,,,,,296992,8d3e532137896c9319bab4422e836bd1232fa81babf4626efa8c411927052731,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/images/entidades/BMM.png,200,image/png,,,,,,,199364,a92c6ed17cf8769d97a0e70c5db31cc6de1b583a71e161b8b35a7eae21468122,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
https://investemoz.tempo.co.mz/images/hero/hero-3.jpg,200,image/jpeg,,,,,,,9875137,91377213b6286aca7ee4af90860a7dc7a75fa08a165ef7b3192081db43f92dff,biblioteca / correspondência por rever,recurso técnico/navegação — exemplar preservado,inventariado; não importado,,,,,outputs/investmoz-legado-inventario-reconciliado-20261015/RECONCILIACAO-LEGADO.json; LEITURA-ESTADO.json (SQL READ ONLY)
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@@ -1,3 +1,13 @@
|
||||
## 15/10/2026 — disponibilização autorizada do contexto normal
|
||||
|
||||
`promotor-contexto-QA-e8858cb44dca` disponibilizado por decisão expressa da Tempo. Editor da conta 2 aberto em autenticação normal, sem guardar; elevação excecional, MFA, âmbito, Auditor e independência preservados. Relatório operacional e recibo: outputs/investmoz-promotor-contexto-ativacao-20261015/. A preparação QA e interpretações anteriores abaixo permanecem como histórico, com a sua data.
|
||||
|
||||
## 15/10/2026 — interpretação atual do contexto de Promotor
|
||||
|
||||
O original v1 §3.2/§5 distingue a atuação normal do Promotor da elevação excecional do Superutilizador. A orientação atual da Tempo exige preservar essa distinção quando a mesma conta acumula papéis. As afirmações históricas abaixo de que toda a atuação da conta acumulada exige elevação registam a interpretação de implementação então adotada; não constituem por si uma disposição expressa da Tempo para agravar a atuação normal de Promotor.
|
||||
|
||||
Complemento `promotor-contexto-QA-e8858cb44dca` preparado e verificado apenas em QA, sem grants, credenciais ativas, build, migrations ou nova auditoria global. Abertura visual passou; ativo DOC01 e os controlos excecionais permanecem inalterados. Fonte, condição de código, provas e decisão concreta em outputs/investmoz-promotor-contexto-QA-20261015/RELATORIO-E-DECISAO.md. Disponibilização desta correção depende de autorização específica. O conteúdo anterior fica preservado abaixo como histórico.
|
||||
|
||||
<!-- internal-tempo-designation-20261011-2876cdfa900a -->
|
||||
## Regra definida pela proprietária: equipa interna Tempo — 11/10/2026
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -2050,3 +2050,41 @@ A Tempo autorizou `B-final-fabf722bc8c6` com C137 e as limitações documentadas
|
||||
Backup/restauro fresco às 15:09:24 UTC: 295 tabelas, 31 sequências e 815 ficheiros. Comparação posterior por leitura confirma os dados de negócio anteriores preservados; acréscimos esperados: migration, definição e auditoria; variações técnicas de sessão/cache. COUNTRY02, demais configurações, serviços e DevTools preservados. Os 12 critérios aceites não foram repetidos. Mantêm-se as limitações aceites: linha 07 documental; C137 sem aceitação visual específica; estado intermédio sustentado por código/provas anteriores.
|
||||
|
||||
Resultado e recibo: `outputs/investmoz-audit-current-20261012/B-ativacao-concluida-20261015/`. ZIP das provas SHA-256 `bacefba6d72c3f36d8630ffc02e58f02fded3e71a44e71d4cddd6fc1a799cf83`. Candidata e suplemento imutáveis novamente verificados. Reversão conforme procedimento aprovado, preservando dados posteriores. Esta nota atualiza somente esta entrega; as restantes pendências da matriz mantêm-se.
|
||||
|
||||
|
||||
## 15/10/2026 — piloto agronegócio disponibilizado, operação encerrada
|
||||
|
||||
A Tempo confirmou a extensão do importador; autorização inicial e âmbito exclusivo do piloto preservados. Backup/restauro fresco 18:49:57 UTC+02:00: 295 tabelas/31 sequências/996 ficheiros iguais. Três fontes entregues, build preservado e manutenção terminada. Importação nominal de dois originais ausentes como privados; scan real clean nos hashes autorizados. Metadados e publicação autenticada por Osmane Nala: imagem #6 e artigo #5, ambos v3; leitor habilitado só depois.
|
||||
|
||||
Artigo/entrada/imagem públicos responderam HTTP200 anónimo, sem contorno TLS; hash público da imagem igual ao original. Comparação READ ONLY confirmou todos os registos de negócio anteriores preservados; acréscimos limitados aos dois recursos, scans/revisões/auditoria e variação técnica da sessão. B/Country02/serviços e apoio v5 preservados; nenhum novo dossier/pedido, migration ou importação/publicação do restante legado. Percurso funcional e 12 critérios não repetidos. Evidências e reversão real em outputs/investmoz-legado-ativacao-20261015; pacote final e recibo anexados na página privada. Apenas esta entrega é encerrada; requisitos globais AUD-LEG-01–07/AUD-LIB-01–02 conservam as restantes pendências por consumidor/acervo.
|
||||
|
||||
|
||||
## 15/10/2026 — fecho do piloto na matriz e recorte dos restantes setores
|
||||
|
||||
AUD-LEG-03 encerrado como piloto ativo; nove linhas AUD-LEG-01–07/AUD-LIB-01–02 reconciliadas para distinguir piloto entregue de integração integral pendente. Mesmos 3401 IDs, restantes linhas byte a byte preservadas. Sem repetir aceitação nem alterar o ativo/B/COUNTRY02.
|
||||
|
||||
Levantamento READ ONLY: lote proposto de 16 conteúdos não financeiros e 4 imagens distintas (20 recursos): Energia/Mineração 3, Turismo12, Infraestruturas1. Ficheiros/hash/scan/publicação QA existentes e todos ausentes no ativo. Energia/Mineração é índice curto; imagem tempo-background é partilhada, sem duplicação. Mercado Financeiro: corpo0, artigo QA privado e imagem própria fora do recorte, apesar de já publicada em QA. Não inventar texto ou ativar calculador para preencher o vazio.
|
||||
|
||||
Dependência técnica principal: importador ativo nominal só aceita agronegócio; novo manifesto e extensão de escopo específicos devem ser preparados antes de nova disponibilização. Setores/rotas e apoio v5 já existem. Fonte, autorização de divulgação por recurso, scan no destino, importação privada/publicação separadas e backup fresco futuro mantêm-se. Nenhuma implementação nesta etapa. Detalhes em outputs/investmoz-legado-restantes-setores-preparacao-20261015/FECHO-E-PREPARACAO-LOTE.md; inventário completo22 e recorte20 associados aos IDs existentes.
|
||||
|
||||
|
||||
### 15/10/2026 — lote setorial preparado em QA
|
||||
|
||||
AUD-LEG-01/06/07 e AUD-LIB-01/02: manifesto fechado de 20 recursos (16 conteúdos + 4 imagens), importador nominal --sectors-lot20 preparado em cópia QA e 133 verificações dirigidas passadas. Plano e mapa: outputs/investmoz-legado-setores-lote20-QA-20261015/PLANO-UNICO.md. Agronegócio ativo/AUD-LEG-03 e B mantêm-se encerrados; Mercado Financeiro excluído. Sem alteração/publicação ativa. Saldo operacional futuro 2h30–5h, condicionado a decisão específica da Tempo e backup/restauro fresco; não inclui trabalho QA concluído. Reutilizar a aceitação anterior, sem novos ciclos.
|
||||
|
||||
|
||||
### 15/10/2026 — lote setorial disponibilizado no ativo
|
||||
|
||||
Tempo autorizou o procedimento. Entregue apenas ImportDocumentBatch.php na revisão f429fb2655a3956f4025d3a42db64d161643872045a134f63ab183f5dc011eb8. Importados 20 ausentes como privados; scan dos hashes verificado; publicação expressa pela sessão Osmane Nala, recursos 7–26/v3. Consulta anónima dos 16 conteúdos, três entradas setoriais e quatro imagens confirmada. Backup/restauro fresco: 295 tabelas, 31 sequências e ficheiros verificados. Sem alterações aos registos de negócio preexistentes, agronegócio, B, COUNTRY02, configuração ou build. Sem novos dossiers/pedidos e sem repetir aceitação funcional. Mercado Financeiro e integração integral do restante legado permanecem pendentes. Provas e reversão: outputs/investmoz-legado-setores-ativacao-20261015/.
|
||||
|
||||
|
||||
### 15/10/2026 — inventário restante do legado reconciliado por leitura
|
||||
|
||||
Mesma matriz e inventários atualizados: 50 artigos distintos, dos quais 17 publicados, 31 com corpo ainda por integrar (5 setoriais, 8 trabalho doméstico, 18 históricos/noticiosos), Mercado Financeiro vazio e post 74364 sem título. Onze URLs equivalentes não acrescentam artigos; 47 ficheiros adicionais inventariados não acrescentam identidades. Cinco imagens já públicas; próximos artigos setoriais reutilizam o fundo do recurso 24. Recorte sugerido para escolha da Tempo: Fintech, Imobiliário e Bens de Consumo/Franquias, cujos setores mestres existem. Não é autorização de nova implementação/publicação. Referências externas e 30.170 URLs do sitemap infopublica permanecem delimitados, sem bloquear os conteúdos disponíveis. Provas: outputs/investmoz-legado-inventario-reconciliado-20261015/SALDO-LEGADO.md e RECONCILIACAO-LEGADO.json. Sem nova aceitação dos já publicados ou alterações no ativo.
|
||||
|
||||
|
||||
## 15/10/2026 — candidata setorial/Fintech concluída em QA
|
||||
|
||||
setores-fintech-QA-d5b4dc354265: 16 fontes, compilação, três artigos e imagem existente reutilizada. Sete entradas comerciais articulam conteúdo/oportunidades/ações com o mesmo dossier; Fintech especializa as cinco fases/19 etapas. Provas dirigidas, recuperação, scan, resultados separados, revisão seletiva e interface descritos em outputs/investmoz-fintech-investimento-QA-20261015/RESULTADO-QA.md. Somente AUD-FINTECH-01 acrescentado à matriz; fechos anteriores preservados.
|
||||
|
||||
A disponibilidade ativa dos três artigos/novo delta não foi autorizada nesta preparação. Proposta única e reversão prontas; saldo operacional previsto 1h30–3h após decisão, backup/restauro fresco e sessão administrativa. Correspondência jurídica específica permanece indeterminada; artigo geral Mercado Financeiro vazio permanece separado da entrada comercial. B, COUNTRY02 e as aceitações anteriores não são reabertos.
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"at": "2026-10-15T20:28:08+00:00",
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"restore_target": {
|
||||
"database": "classification_before_20261015_202406_test",
|
||||
"port": 55441
|
||||
},
|
||||
"application_base_is_private_clone": true,
|
||||
"source_and_build_from_fresh_backup": true,
|
||||
"shared_vendor_dependencies_unchanged": true,
|
||||
"DB_read_only": true,
|
||||
"kernel_bootstrap": "passed",
|
||||
"HTTP_kernel_routes": [
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "\/up",
|
||||
"status": 200,
|
||||
"body_bytes": 1757,
|
||||
"body_sha256": "0e5f4ba27dfb22f477127fb7e6a45085f7f3e8cce5b541f99f785cd00751aaf0"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "\/login",
|
||||
"status": 200,
|
||||
"body_bytes": 14351,
|
||||
"body_sha256": "0ff2812b42702c71e022a3ff46c0f4183bb2ead4502c07e29a5e270ac6fcedb3"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "\/oportunidades",
|
||||
"status": 200,
|
||||
"body_bytes": 211804,
|
||||
"body_sha256": "006b47887d6dbc2a74de46fd1927ca2991953275f379b9ab325b49f2962c8ab9"
|
||||
}
|
||||
],
|
||||
"view_rendering_and_Vite_manifest": "passed",
|
||||
"session_and_cache": "array in clone only",
|
||||
"external_connectors_disabled": true,
|
||||
"database_changes": 0,
|
||||
"active_changes": 0,
|
||||
"accepted_QA_tests_repeated": false,
|
||||
"real_web_server_TLS_worker_boot_test": false
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"before_sha256": "77ca8f755dc4f0e31baeb734421bb12007571d60c3dc2da14ccac581725af6bc",
|
||||
"after_sha256": "b0c3e267985a2f4a2c97da95efa8c1c7aaeb545731141ab6294736c66497159f",
|
||||
"rows": 3402,
|
||||
"changed_ids": [
|
||||
"M2-d0c06a75-0029",
|
||||
"M2-d0c06a75-0158",
|
||||
"MASTER-e1169a77-0043",
|
||||
"MASTER-e1169a77-0062",
|
||||
"OP-9f173ed3-0165",
|
||||
"RF-CLU-002",
|
||||
"RF-CLU-003",
|
||||
"RF-COR-003"
|
||||
],
|
||||
"other_raw_rows_preserved": 3394,
|
||||
"accepted_items_reopened": 0,
|
||||
"global_requirements_closed": 0,
|
||||
"new_requirements": 0,
|
||||
"same_existing_matrix": true
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"at": "2026-10-15T20:31:04.143730+00:00",
|
||||
"origin": "Express user decision by Tempo in current conversation",
|
||||
"user_statement": "A Tempo autoriza a disponibilizaçaõ",
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"document_revision": "DOC01",
|
||||
"candidate_zip_sha256": "334d8ef2e47848a3c30cf526ae4d394004f112288cdddbcf635f06a1be1e0bc6",
|
||||
"candidate_receipt_sha256": "5e6fc4e3661de95c18e3192dfe3f68c048a5e676b0df44485a0a0650ab032505",
|
||||
"authorized": "17 sources and coherent build; fresh backup/isolated restore; compatible reversal; preserve data cache, B, COUNTRY02, permissions, contents and history",
|
||||
"excluded": "migrations, QA fixtures/synthetic classifications, real association changes, repeated accepted QA or unrelated functionality",
|
||||
"remaining_global_gaps": [
|
||||
"/negocios",
|
||||
"full operational parks record",
|
||||
"missing economic references",
|
||||
"duplicate consolidation",
|
||||
"complete specific Fintech regulation"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"store": "database",
|
||||
"driver": "database",
|
||||
"rows": 95,
|
||||
"sha256": "c04547355eb26f70100322ec4c5c32ac6f5e93e6baea18ad4ede58c4bc94742c"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"store": "database",
|
||||
"driver": "database",
|
||||
"rows": 95,
|
||||
"sha256": "c04547355eb26f70100322ec4c5c32ac6f5e93e6baea18ad4ede58c4bc94742c"
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"recent_create_denials": [
|
||||
{
|
||||
"actor_user_id": 2,
|
||||
"action": "request_denied",
|
||||
"occurred_at": "2026-10-15 20:35:05.694244+00",
|
||||
"path": "minhas-oportunidades\/create",
|
||||
"method": "GET",
|
||||
"status": "403"
|
||||
},
|
||||
{
|
||||
"actor_user_id": 2,
|
||||
"action": "request_denied",
|
||||
"occurred_at": "2026-10-15 20:34:12.106119+00",
|
||||
"path": "minhas-oportunidades\/create",
|
||||
"method": "GET",
|
||||
"status": "403"
|
||||
}
|
||||
],
|
||||
"current_approved_elevations": [],
|
||||
"at": "2026-10-15T20:36:22+00:00",
|
||||
"target": {
|
||||
"database": "investemoz",
|
||||
"port": 5432
|
||||
},
|
||||
"read_only": true,
|
||||
"osm": [
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Osmane Nala",
|
||||
"verified": true
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "Osmane Nala",
|
||||
"verified": true
|
||||
}
|
||||
],
|
||||
"superuser_pair": [
|
||||
{
|
||||
"id": 1,
|
||||
"first_user_id": 13,
|
||||
"first_name": "Osmane Nala",
|
||||
"second_user_id": 2,
|
||||
"second_name": "Osmane Nala"
|
||||
}
|
||||
],
|
||||
"current_operational_assignments": [
|
||||
{
|
||||
"user_id": 2,
|
||||
"name": "Osmane Nala",
|
||||
"role": "promoter",
|
||||
"organization_id": "9b28d62b-ae68-438d-bb32-36d4fca026a6",
|
||||
"opportunity_types": "[\"investment_project\", \"real_estate\", \"land_rights\", \"business_sale\", \"business_partnership\", \"franchise\"]",
|
||||
"source": "internal-portal-designation",
|
||||
"verified": true
|
||||
},
|
||||
{
|
||||
"user_id": 2,
|
||||
"name": "Osmane Nala",
|
||||
"role": "validator",
|
||||
"organization_id": null,
|
||||
"opportunity_types": "[\"investment_project\", \"real_estate\", \"land_rights\", \"business_sale\", \"business_partnership\", \"franchise\", \"concession\", \"financing\", \"supply\", \"other\"]",
|
||||
"source": "independent-administration",
|
||||
"verified": true
|
||||
},
|
||||
{
|
||||
"user_id": 14,
|
||||
"name": "Aurora Chachuaio",
|
||||
"role": "promoter",
|
||||
"organization_id": "9b28d62b-ae68-438d-bb32-36d4fca026a6",
|
||||
"opportunity_types": "[\"investment_project\", \"real_estate\", \"land_rights\", \"business_sale\", \"business_partnership\", \"franchise\"]",
|
||||
"source": "internal-portal-designation",
|
||||
"verified": true
|
||||
},
|
||||
{
|
||||
"user_id": 15,
|
||||
"name": "Palmira Uamusse",
|
||||
"role": "validator",
|
||||
"organization_id": null,
|
||||
"opportunity_types": "[\"investment_project\", \"real_estate\", \"land_rights\", \"business_sale\", \"business_partnership\", \"franchise\", \"concession\", \"financing\", \"supply\", \"other\"]",
|
||||
"source": "independent-administration",
|
||||
"verified": true
|
||||
},
|
||||
{
|
||||
"user_id": 15,
|
||||
"name": "Palmira Uamusse",
|
||||
"role": "validator",
|
||||
"organization_id": "9b28d62b-ae68-438d-bb32-36d4fca026a6",
|
||||
"opportunity_types": "[\"investment_project\", \"real_estate\", \"land_rights\", \"business_sale\", \"business_partnership\", \"franchise\", \"concession\", \"financing\", \"supply\", \"other\"]",
|
||||
"source": "independent-administration",
|
||||
"verified": true
|
||||
},
|
||||
{
|
||||
"user_id": 15,
|
||||
"name": "Palmira Uamusse",
|
||||
"role": "validator",
|
||||
"organization_id": "9b28d62b-ae68-438d-bb32-36d4fca026a6",
|
||||
"opportunity_types": "[\"investment_project\", \"real_estate\", \"land_rights\", \"business_sale\", \"business_partnership\", \"franchise\", \"concession\", \"financing\", \"supply\", \"other\"]",
|
||||
"source": "independent-administration",
|
||||
"verified": true
|
||||
},
|
||||
{
|
||||
"user_id": 16,
|
||||
"name": "Mario Melembe",
|
||||
"role": "publisher",
|
||||
"organization_id": null,
|
||||
"opportunity_types": "[\"investment_project\", \"real_estate\", \"land_rights\", \"business_sale\", \"business_partnership\", \"franchise\"]",
|
||||
"source": "internal-portal-designation",
|
||||
"verified": true
|
||||
}
|
||||
],
|
||||
"opportunity_owners": [
|
||||
{
|
||||
"owner_user_id": null,
|
||||
"name": null,
|
||||
"records": 6
|
||||
}
|
||||
],
|
||||
"permission_changes": 0
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
{
|
||||
"at": "2026-10-15T20:28:23.367251+00:00",
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"document_revision": "DOC01",
|
||||
"authorization": "Tempo: A Tempo autoriza a disponibilizaçaõ (current conversation)",
|
||||
"maintenance_started": true,
|
||||
"maintenance_ended": true,
|
||||
"sources": {
|
||||
"app/Http/Controllers/InvestmentDiscoveryController.php": "df3cc8f5a43766832399cbde836617bf86e7fcbde56b660f008714daf5560ba8",
|
||||
"app/Http/Controllers/OpportunityClassificationController.php": "7befceff95da3e50fe635cc635f654897b94d26f3a0cddbd861251a5cdf18333",
|
||||
"app/Http/Middleware/ProtectProfileOpportunity.php": "53c30d652a568733ecbd240acc8c22165307de9e26b761b3d26ba1468f4d7b5b",
|
||||
"app/Services/InvestmentCatalogue.php": "65fbb701f3ab589c3b08886f1a8adefa1bd782d30758176b804df4fd10541824",
|
||||
"app/Services/OpportunityCanonicalContract.php": "78f7656b13a09830bd20e1cd4258e1f364e064851348fdbedcb745629f5c9591",
|
||||
"app/Services/OpportunityCanonicalResponse.php": "21b67b9354235a9b586c9db87a7fd7221bc4ed9895b7bb9bc008f28a804b43d4",
|
||||
"app/Services/OpportunityClassification.php": "fc924b187bbe1634a4723c4d11d1412228d7a90816189d2260b2e12f9d9a7cbe",
|
||||
"app/Services/OpportunityManagement.php": "b8fbb40f7f143db71c380be64809e3e8ac2f92b9cdefe6206a0e98be598b9399",
|
||||
"app/Services/OpportunityProfileWorkflow.php": "9c0f7f10efdc55da19e2baf3482d755ba9e6d7239382fc8cdf9c9be636859457",
|
||||
"app/Services/PortalProfileAccess.php": "5ce3b9d9162ba513523bb0ae2b43cfd10f21f4cfddeb17b94b6f4c54f3a007c7",
|
||||
"resources/js/components/opportunity-canonical-fields.tsx": "542ee4d6bdbd259fc1c7a5a41757bb78279cc4210bbe75d2d377f894598cc83d",
|
||||
"resources/js/components/opportunity-classification.tsx": "91a609af736dcaefac3e47ebab30156e8081f7ae5024f38066b8ef9dfdb3505b",
|
||||
"resources/js/pages/investment/catalogue.tsx": "649955876ab712c4cba0bdadf1dd3fa511ad10059b58cd4c242a5f84f7c8be2b",
|
||||
"resources/js/pages/investment/detail.tsx": "c83686fa00fda4de82f3a8d3c842d0526b10635a2b76b1c3ec54d69c96a69e6d",
|
||||
"resources/js/pages/investment/shared.tsx": "56180116aab60d81e345506a9732081878825e143ab452f88df292299cccdce4",
|
||||
"resources/js/pages/management/opportunity-draft.tsx": "d40a69e4f3e4234c4a67732794e53e311c0f4e47c353e9f1535cdbd7e6664ef1",
|
||||
"routes/web.php": "049080ce60b271f9d1a28e5cb7a2a59d8973f6b562a3893b42057d39d336c10f"
|
||||
},
|
||||
"added_build_files": [
|
||||
"build/assets/PortalInvestidor-BXX7D5mc.js",
|
||||
"build/assets/administration-DIeFJMqV.js",
|
||||
"build/assets/ai-ChGVr0lO.js",
|
||||
"build/assets/analysis-O8ywXDIp.js",
|
||||
"build/assets/app-BpQ_dwxz.js",
|
||||
"build/assets/appearance-BfaH8oSi.js",
|
||||
"build/assets/audit-Gbk2oG0G.js",
|
||||
"build/assets/bootstrap-confirmation-SXEYOxn0.js",
|
||||
"build/assets/business-DFWwv-a5.js",
|
||||
"build/assets/business-interest-DNAXzsAZ.js",
|
||||
"build/assets/business-marketplace-VLmaQMoy.js",
|
||||
"build/assets/business-objects-Dg4TuAgv.js",
|
||||
"build/assets/business-opportunity-CnguKkM1.js",
|
||||
"build/assets/business-verifications-B6ydWynn.js",
|
||||
"build/assets/business-wizard-CSDilFq3.js",
|
||||
"build/assets/businesses-DriAYDGP.js",
|
||||
"build/assets/case-Be6gum1W.js",
|
||||
"build/assets/case-OEBgZEyZ.js",
|
||||
"build/assets/catalog-CopKQnDe.js",
|
||||
"build/assets/catalogue-CHPIbGW1.js",
|
||||
"build/assets/catalogue-CKP80q5n.js",
|
||||
"build/assets/catalogue-tfk8z4LY.js",
|
||||
"build/assets/confirm-password-oTGVuLu8.js",
|
||||
"build/assets/context-c9_UBxwN.js",
|
||||
"build/assets/conversation-CZN7v_vS.js",
|
||||
"build/assets/convert-GxM7R5o2.js",
|
||||
"build/assets/dashboard-DQkDq1Ey.js",
|
||||
"build/assets/dashboard-dU2DWYP5.js",
|
||||
"build/assets/desk-internal-operations-BoAeAKeW.js",
|
||||
"build/assets/detail-BOUTE2EC.js",
|
||||
"build/assets/detail-DfMNNBXY.js",
|
||||
"build/assets/dialog-C5eypyXz.js",
|
||||
"build/assets/dist-BHykSMWQ.js",
|
||||
"build/assets/dist-MhNbm6zU.js",
|
||||
"build/assets/document-CpnRUUP9.js",
|
||||
"build/assets/editor-AlSaprMp.js",
|
||||
"build/assets/editor-C6dGcGS9.js",
|
||||
"build/assets/editor-CB1R1_It.js",
|
||||
"build/assets/education-CBYGENHg.js",
|
||||
"build/assets/forgot-password-DVGz2FB6.js",
|
||||
"build/assets/form-CxzomA29.js",
|
||||
"build/assets/guide-Du6ppaW4.js",
|
||||
"build/assets/history-CGJfV8DN.js",
|
||||
"build/assets/install-7BwDhJla.js",
|
||||
"build/assets/installation-CHvjLRDv.js",
|
||||
"build/assets/installation-CwPQjhH5.js",
|
||||
"build/assets/interactive-investment-map-CAX-0AKR.js",
|
||||
"build/assets/interest-BJy832Pe.js",
|
||||
"build/assets/interests-D-B5BBRl.js",
|
||||
"build/assets/investment-map-panel-CCxzTN3P.js",
|
||||
"build/assets/investment-territory-CW0BDi5i.js",
|
||||
"build/assets/investor-CXhJGNZ2.js",
|
||||
"build/assets/investor-path-DUL4FTR4.js",
|
||||
"build/assets/investors-DC8PPcJh.js",
|
||||
"build/assets/label-uPFpYsdE.js",
|
||||
"build/assets/lead-n1xOFhZ9.js",
|
||||
"build/assets/leads-C30F1NT8.js",
|
||||
"build/assets/leaflet-src-Cwj7MbZ4.js",
|
||||
"build/assets/legacy-CQ9nOspV.js",
|
||||
"build/assets/login-BJC6DfMQ.js",
|
||||
"build/assets/manage-AEzC-ARG.js",
|
||||
"build/assets/management-CnSXy3oI.js",
|
||||
"build/assets/management-access-ByT3V1qh.js",
|
||||
"build/assets/notifications-BCStyAVN.js",
|
||||
"build/assets/opportunities-COK8VNwo.js",
|
||||
"build/assets/opportunity-classification-B4UEUrhY.js",
|
||||
"build/assets/opportunity-draft-lHUZeNnA.js",
|
||||
"build/assets/opportunity-install-D8n6mSsB.js",
|
||||
"build/assets/opportunity-origin-B_gD83Dl.js",
|
||||
"build/assets/opportunity-resources--lc4Z7SW.js",
|
||||
"build/assets/panel-CNBwgp5t.js",
|
||||
"build/assets/partnership-source-links-B7OrliV8.js",
|
||||
"build/assets/passkey-verify-Dly1EJzK.js",
|
||||
"build/assets/password-input-CSlmhC-X.js",
|
||||
"build/assets/portfolio-C_Q-Nk8V.js",
|
||||
"build/assets/profile-BYnB_Mq2.js",
|
||||
"build/assets/profile-B_9OCzxs.js",
|
||||
"build/assets/project-dossier-BTTYtUNS.js",
|
||||
"build/assets/react-mlFDtEmO.js",
|
||||
"build/assets/references-86dJ67Zc.js",
|
||||
"build/assets/register-Er2G-F3m.js",
|
||||
"build/assets/relationship-repair-KOVytyPI.js",
|
||||
"build/assets/request-CINhDZym.js",
|
||||
"build/assets/request-DFhstEZc.js",
|
||||
"build/assets/reset-password-CxbTbrIo.js",
|
||||
"build/assets/result-CoXA-Ibg.js",
|
||||
"build/assets/room-BiVdR9q8.js",
|
||||
"build/assets/security-DzWeJG4q.js",
|
||||
"build/assets/services-Cd-m6rpo.js",
|
||||
"build/assets/shared-B0DslzBA.js",
|
||||
"build/assets/shared-Bv15ZcQS.js",
|
||||
"build/assets/shared-_Diy3WCu.js",
|
||||
"build/assets/shared-drdcL7HN.js",
|
||||
"build/assets/show-7jSL953d.js",
|
||||
"build/assets/show-mV475tmT.js",
|
||||
"build/assets/sources-rE0S91jD.js",
|
||||
"build/assets/structure-geography-DCJmB6wg.js",
|
||||
"build/assets/structures-BBKbr9tr.js",
|
||||
"build/assets/submission-CbfZ-mLn.js",
|
||||
"build/assets/territory-associations-Bdv_d3vO.js",
|
||||
"build/assets/territory-geometry-import-D0EBneG2.js",
|
||||
"build/assets/territory-geometry-preview-CT9rz1r6.js",
|
||||
"build/assets/text-link-DE5bJEGx.js",
|
||||
"build/assets/two-factor-challenge-CeHEAK42.js",
|
||||
"build/assets/use-two-factor-auth-Dv2TBEg_.js",
|
||||
"build/assets/value-network-BG8eHihw.js",
|
||||
"build/assets/verify-email-BebQ_QDn.js",
|
||||
"build/assets/welcome-DjOoM67E.js",
|
||||
"build/assets/workspace-BaccTw8S.js",
|
||||
"build/assets/workspace-BqjDqWpq.js",
|
||||
"build/assets/workspace-CJH4dSzM.js",
|
||||
"build/assets/zone-Cxk-nhVJ.js",
|
||||
"build/assets/zone-attachments-DN6HRiW5.js",
|
||||
"build/assets/zone-map-Nu1V2MPg.js",
|
||||
"build/assets/zone-relations-C_4XEKfR.js",
|
||||
"build/assets/zones-BhHvVu0K.js"
|
||||
],
|
||||
"build_files": {
|
||||
"build/assets/PortalInvestidor-BXX7D5mc.js": "9a9d73698be5b90edfe270c72b9bdda932efb81ad726be69401b13e8441d3a1f",
|
||||
"build/assets/administration-DIeFJMqV.js": "b9c8aa043991ecf9b3a5c94cf246cbdd2813db41d8ad16fe1bb2a59655b3bb9b",
|
||||
"build/assets/ai-ChGVr0lO.js": "a63dec0027c404ec6aa11eb12f4cd372eb101a2a60945ab7ad6c3ad72423694d",
|
||||
"build/assets/analysis-O8ywXDIp.js": "e89065fc421eeceac380c7e9fc8f368410549d24fd8c0e30061d2e5be1b1fb5e",
|
||||
"build/assets/app-BpQ_dwxz.js": "d49fddcff9093ae43b8d8666b673eb1a8db4a88ca989d0e0b3ba3176ef7dce04",
|
||||
"build/assets/app-Bq3lXpJL.css": "f1c1531eda03206e53cb4b81a14af8ecee04671a743e29bc2aae371df15ba493",
|
||||
"build/assets/appearance-BfaH8oSi.js": "d45faa884cebe42ee2fd81c0d9b69b5b3df974f65181839e289a84c613c3af06",
|
||||
"build/assets/audit-Gbk2oG0G.js": "751f7ad0cdc59ca9a8dd648bd1ad4ec6f816a3ac95c14551e895fd9353fd4bf3",
|
||||
"build/assets/blank-2jFZEe2q.js": "9e53a0a455027f070e3041db1f445e8b63702f83e264442d8df87e20048ccbe9",
|
||||
"build/assets/bootstrap-confirmation-SXEYOxn0.js": "2382eee498373ef21c9862dc31a68a3a5e7ae4323a461abba1d78451aacc8d1e",
|
||||
"build/assets/business-DFWwv-a5.js": "cd62b9a1b82e72f028cd86f0f3b195519814df818207f845647ad5ccfef3e2b5",
|
||||
"build/assets/business-interest-DNAXzsAZ.js": "91f7b1056177437151b613d9a8a3906a7eadd9905bee6a599fd713cf32221682",
|
||||
"build/assets/business-marketplace-VLmaQMoy.js": "e3001a1c3dcdd53642f544ae02f6012652d34605c145e0c8d109ae046265d4df",
|
||||
"build/assets/business-objects-Dg4TuAgv.js": "ace65e00c1c7c735bebea63a5853e6a05f27584fb11c53b7af68c6ed80f7fb27",
|
||||
"build/assets/business-opportunity-CnguKkM1.js": "37ba4aadf853508ccb2e40297a191e9294d91b12e041af7c9e6cfd9f2f8473c8",
|
||||
"build/assets/business-types-SGCXhH6X.js": "c792ab88a79f57c74d865c47e89e7f2b9aea190acb5c8c676071d4b0a802d58c",
|
||||
"build/assets/business-verifications-B6ydWynn.js": "367c6db9ba0d7a0a86f0f5850cc5467a5623dba857f04b50e902c3e5e9563c7a",
|
||||
"build/assets/business-wizard-CSDilFq3.js": "59ec13e6d71ac04e42a99e8c4fc9c6210e534c7869fdf332727ab14ac68aae5b",
|
||||
"build/assets/businesses-DriAYDGP.js": "530fba2e3bea4d107e27a1e32cdef8c172d0673e70a35161472ecb0d3f921416",
|
||||
"build/assets/button-DAU4R6e9.js": "79b615d0b88db74491fb4b312ae70515d43332e8730f8baed64c81eec510171d",
|
||||
"build/assets/case-Be6gum1W.js": "71daca09df866ec565dc1801c4d3dc41768485e27f7b6043d065c82417b97c9b",
|
||||
"build/assets/case-OEBgZEyZ.js": "325729993e32eb98b68de7b9cc425ef050faa3a1a76d6753ea0c824616d2955b",
|
||||
"build/assets/catalog-CopKQnDe.js": "e12c4cdce4bfcc976006c43115c6f6f8b9818f68abf4b4438a913e461493423d",
|
||||
"build/assets/catalogue-CHPIbGW1.js": "b38d01a4a4bc3262aea8d3e6108e7fca3ae8faf04194d79c335f0de0b69bc0c9",
|
||||
"build/assets/catalogue-CKP80q5n.js": "781dac358d16aedb0675e34297edd7f4108d97eb797c8ae9df55ade31053ead4",
|
||||
"build/assets/catalogue-tfk8z4LY.js": "1b0abbce673f5fbbde4d21da58467bf07c537558f7efcd9a554f90726dd513ad",
|
||||
"build/assets/check-PcBNn_NG.js": "402150a0f6387f9f098fea689a3282723ee063c84e57651f25d35729cdd85063",
|
||||
"build/assets/compiler-runtime-sKsOXjDo.js": "cc5f3db4bfb3bc5ae09b4594e5e137ad20037e8dfc3f0791781665706b860b6d",
|
||||
"build/assets/confirm-Culw9Q-x.js": "263fd058f1562c5729a4091d5d60f5365cc3957ad2cfcb5ffdec04a28f1858c4",
|
||||
"build/assets/confirm-password-oTGVuLu8.js": "e2190e4b06a88ab0b2949dca0bbd91aac1a188123f711e385ff7a0ead8a6a593",
|
||||
"build/assets/context-c9_UBxwN.js": "20e2f30b91e7fc2f995e95b58c220435b56f5233e42801e7e29e49b07f3a7c09",
|
||||
"build/assets/conversation-CZN7v_vS.js": "03ae1a37834e65813d3cdf610b49056c027d833d286eed3c3f8a1d253531ed7f",
|
||||
"build/assets/convert-GxM7R5o2.js": "01d0af1fea4e42a1979baa7548931aaa0555285e76cb86688f10bcf7074484e2",
|
||||
"build/assets/country-select-C3BLoPPG.js": "87822f75957659509b95011d1489f6bed2ff824c215fce862a7fd29186f5189f",
|
||||
"build/assets/createLucideIcon-oMeAlXbs.js": "9398e5f9d8be91b886b9f6283574d6eb89b8fa02a4c21866ab9e376c95b74b56",
|
||||
"build/assets/dashboard-DQkDq1Ey.js": "84655c02837454e4eeacba03e04a4fc01a0b10099dc9eb14ef78cf148a58ceca",
|
||||
"build/assets/dashboard-dU2DWYP5.js": "b80a802cdcd57805f51cd41736ec6274174e3c5a1ba6d7f45d4d392757707592",
|
||||
"build/assets/desk-internal-operations-BoAeAKeW.js": "7e7a16c1d1bcdeb80df70070f286239589938fccc2472909f8451b3b98b5586d",
|
||||
"build/assets/detail-BOUTE2EC.js": "06c84d89582a52400258552757205899195a1f960565a29575c999863244dc7c",
|
||||
"build/assets/detail-DfMNNBXY.js": "e522cbea47ab8df9a8ea34072cbe6eff008c41eed1ac51b81892472b2f5bf088",
|
||||
"build/assets/dialog-C5eypyXz.js": "7062930ecd1066ad6d6ef8fd15a068fda006f67a108d0e7ab19b38d0aee8f739",
|
||||
"build/assets/display-value-DRR1EAAK.js": "202c77561454ec7c1ef9cb39faa4f1833ea066dbb83e17f0eb4440b314b189f6",
|
||||
"build/assets/dist-BHykSMWQ.js": "dad846be6e85e44ccbd91b57620700e98d2aa5334ae6c01cf2fea5d18f71f7cf",
|
||||
"build/assets/dist-Ddn_hEUd.js": "ee0c56af5abd78d01704f2fb0f764ea0746908244078a8014393a672994235d6",
|
||||
"build/assets/dist-MhNbm6zU.js": "002d8b09d24554616192936fd8df3891d6d86d11ecfa6d292462eb6ca8492bdd",
|
||||
"build/assets/document-CpnRUUP9.js": "99a212f338f92febefa9ca9f7eafcf324af6fdafcf6458e53715a33c2842b86b",
|
||||
"build/assets/editor-AlSaprMp.js": "f673042f47c1dba7c015f2ea4f4ebc238d44842b1ab9a4c342ef777b84d30f7c",
|
||||
"build/assets/editor-C6dGcGS9.js": "3086605dd33ebf857b97e6c223e297339f67c28c9f88f095c258f2e0a7e348a4",
|
||||
"build/assets/editor-CB1R1_It.js": "af5d17d46e442284d5567a8487e9bb8412b93d5c0b708ad076e77c6dc2c13c37",
|
||||
"build/assets/education-CBYGENHg.js": "83bac5512926b9a6904a5dbe86aef17cb5aec003f2cc5d1fc9499d659bcd3327",
|
||||
"build/assets/financial-calculators-CsDOUJxx.js": "e76679a1914b5c4dc6c3e74b1b2de8d3d792fcc891dcc61d0fa27042232e2b9a",
|
||||
"build/assets/fonts-DmGVJ3xF.css": "0d8ae8a842951a087a04abd66fd137a310b819bbf335c0fa9e2d4f615981f231",
|
||||
"build/assets/forgot-password-DVGz2FB6.js": "ab2127fb661e47379c7f04cd016024f460d46355c3cff2882c23fc1f36efb198",
|
||||
"build/assets/form-CxzomA29.js": "fef500f87fd9d0ff0ff6eaf2060274e106801bfc45d50ac10ab8a4e702094291",
|
||||
"build/assets/guide-Du6ppaW4.js": "f87f9066b6c4b3f7b90f6955d6ff478f66ef3e00f884d54ef1e4133bcf6ce1d7",
|
||||
"build/assets/history-CGJfV8DN.js": "f443cf737e5ca09258cdba30d5d5255cdf42e3efd521a718795b40b4f728c91c",
|
||||
"build/assets/input-error-U1QKS0ED.js": "4acac92fa624552b14ac1a390e961f9e387d6eefeac384ad4e95bc73fdffa86e",
|
||||
"build/assets/install-7BwDhJla.js": "c9c047adf11c286417c8dc1dc649dd7acc905ddd2c6c40e468b2e4e14d953a37",
|
||||
"build/assets/installation-CHvjLRDv.js": "948f2da0a7c866b55a5564b978f317c19f53e9d11cde249ceb89c195b666d7de",
|
||||
"build/assets/installation-CwPQjhH5.js": "44b917b1d25b5b74d2e880199ded5dded70f136b0ebfbdd4139248002f337445",
|
||||
"build/assets/instrument-sans-400-normal-D1W7dsQl.woff": "797bd3eaa70edbd4757650ab44dad75fbfbfdf18bacedb4b71022c04621d30ad",
|
||||
"build/assets/instrument-sans-400-normal-DRC__1Mx.woff2": "9a91efaa3599a6ef01b2f49e9ec670e3a2f39baeef09c73198f1052cf3bb0850",
|
||||
"build/assets/instrument-sans-500-normal-Dk9ku72i.woff2": "9d3547da16d950d12a677c772a3ff9b69846e60e7dcd1b5efd540993f7286532",
|
||||
"build/assets/instrument-sans-500-normal-Z6ESRlEs.woff": "bd6a8dc8b0dc0cced0c32d3eda93f0e0e82c58ddefea8b53b3307b0c48da3089",
|
||||
"build/assets/instrument-sans-600-normal-B7fBEWYG.woff2": "efb770916eda95a0e31d80cccde9651d4e8617010b21220e9f227c4820d675da",
|
||||
"build/assets/instrument-sans-600-normal-B9e8oLYv.woff": "9b4ce1f2b26be7cb087fd87d6f99a202136292ec820af75bd38ab9e53895cf28",
|
||||
"build/assets/interactive-investment-map-1DTFk8zz.css": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de",
|
||||
"build/assets/interactive-investment-map-CAX-0AKR.js": "05fc509eb9004a3298a700b6a99e4daee230ee8d50c0f16dd7bc846af8480ca0",
|
||||
"build/assets/interest-BJy832Pe.js": "cbc3d82f20df51d9f7f1d869169cc4393f321ced15cbd1b996ca138fa697d2ae",
|
||||
"build/assets/interests-D-B5BBRl.js": "96d73afc0115cad0aabf62146a5ba12b824ddfd34bc286b9d38e78b60cdea8ee",
|
||||
"build/assets/investment-map-panel-CCxzTN3P.js": "4e4ccb829191d6d0c33a0823738c662a895afa963659f45f5933289a29437ec7",
|
||||
"build/assets/investment-maturity-CydhhEfV.js": "c2cc75070cb664ab0b53466dde584dd5473f1b5fd992bf6a59ca8a01b7e19623",
|
||||
"build/assets/investment-territory-CW0BDi5i.js": "87ee85a10f8bb6eab32b2f2eea683c6336b21e5dfa09374e9c244018355a3d24",
|
||||
"build/assets/investor-CXhJGNZ2.js": "93539339aaad4a95d367831245d83591bb2401f289c3cb7a4fb7d550d748c1ae",
|
||||
"build/assets/investor-path-DUL4FTR4.js": "86b5e21b64b8087204b8966dcd9b82f69580e51c273840f569fe2379ca958c65",
|
||||
"build/assets/investors-DC8PPcJh.js": "ae70a63c8429a69849b513df045dc76ae4df4b89fd78fb127d42f6d812a44826",
|
||||
"build/assets/jsx-runtime-BpzPEenQ.js": "60a64ced602d5e913f2a0328d2ec4a7b670c893614a26c47794317523d276398",
|
||||
"build/assets/label-uPFpYsdE.js": "0c9523af7611d23989d7b9d19e605c78be48f9f6a7e92a9bc0a5c855632abc59",
|
||||
"build/assets/labels-DxqjesIG.js": "deace12e77e3f2e0515b1090cbc376cfeff29b59f57b1a2561b1145459c531b8",
|
||||
"build/assets/layers-2x-Bpkbi35X.png": "066daca850d8ffbef007af00b06eac0015728dee279c51f3cb6c716df7c42edf",
|
||||
"build/assets/layers-BWBAp2CZ.png": "1dbbe9d028e292f36fcba8f8b3a28d5e8932754fc2215b9ac69e4cdecf5107c6",
|
||||
"build/assets/lead-n1xOFhZ9.js": "20b6e99206214df971688660f0f3577152a9380fa663a1dd55c3da45991a8cc5",
|
||||
"build/assets/leads-C30F1NT8.js": "e496024b4aa5df6c69223210870f3984243d42a692cb8a01ff3df0c3f4870603",
|
||||
"build/assets/leaflet-src-Cwj7MbZ4.js": "3e24064ee3137630cec87f2df536788ac51fac3cc3b3d282048e434efdd880fd",
|
||||
"build/assets/legacy-CQ9nOspV.js": "32fc2aea43828c65107b620f9266ccb855fdf104217a00acb85a22048f77d6b2",
|
||||
"build/assets/loader-circle-DS8Tf4er.js": "cd9fb22e9d7d12342d5e0941aac953ebb5184550cc8008b5c0f8f5ea6acd8ed2",
|
||||
"build/assets/login-BJC6DfMQ.js": "e561846a370717e74b0f55efb955f3da8a70787dd8d058b94e35b250ecbfb423",
|
||||
"build/assets/manage-AEzC-ARG.js": "ef96e36814f32c4493307e372da4d0e67074c1e9fd8c95baee4407180b0a9767",
|
||||
"build/assets/management-CnSXy3oI.js": "125e43370e562a7de80927f4efa213ce5f3ec76a5e59dd9d8e5d7a31a71ab410",
|
||||
"build/assets/management-access-ByT3V1qh.js": "c9ff172e20d0e60b8f9b6236f823bfa54d4d88431124bfed636f45fbfa7740b8",
|
||||
"build/assets/marker-icon-hN30_KVU.png": "574c3a5cca85f4114085b6841596d62f00d7c892c7b03f28cbfa301deb1dc437",
|
||||
"build/assets/notifications-BCStyAVN.js": "f62b81782f3b4873bdefd5e656a91bc10c91bfdfa3543cb0b0c3836fda9a296d",
|
||||
"build/assets/noto-sans-400-normal-BTkUljjl.woff2": "09aee8065d25508f23a4c3d92cd777ac869c52d93fd868a88f025d888a7937d6",
|
||||
"build/assets/noto-sans-400-normal-DPpKfCgK.woff": "18e2e5b23a9bc5e8e636d6c7984b8ac6635aefc1c497ed1c5012f3c637761b91",
|
||||
"build/assets/noto-sans-500-normal-CDPngY5C.woff": "15f5a154b97262907900b5e3d297333417396cc775ae2e73f801763ebbac1dd6",
|
||||
"build/assets/noto-sans-500-normal-DCA2Z9Cj.woff2": "1d35aaecc5c7a375d87c12787e1e4c5d6a695315b757e1e18a479d1a2f84e973",
|
||||
"build/assets/noto-sans-600-normal-DVJMj_t0.woff": "954cd3f8c324a52a0a78a97a48f459a6656400a814e427d2ef62a680b83d82b8",
|
||||
"build/assets/noto-sans-600-normal-Dkgu5AE5.woff2": "79e274470d1c5a0118eb325e2ea6f2eb2a449336d7fde1a4f20a2f32fe1119ed",
|
||||
"build/assets/noto-sans-700-normal-CrvTEWhy.woff2": "e77bfe1db912f687b0319b60de158cfada67f89c8ee4f8e2bd6020f970accbfb",
|
||||
"build/assets/noto-sans-700-normal-ZyrKABVF.woff": "cac2e44ebc446d5c71a9a16fd5592bf80abf6f56dd564a7b90eb01c5f9d29793",
|
||||
"build/assets/noto-serif-400-normal-BV_iYGc9.woff2": "4c0cbe3eec50d260754d681c17ee2af49a43d7fd93ce42877f665fcb1a889b87",
|
||||
"build/assets/noto-serif-400-normal-DT0cwSa_.woff": "084719f02390eba8960814e1845fba7e6857d63895f53fe8321bcac6b4c73d40",
|
||||
"build/assets/noto-serif-600-normal-BiuDA9L7.woff2": "abf0abc765331d7a1bbe6eb3603cf86be1cf3d1edbcf911cc2d52f78998c02d9",
|
||||
"build/assets/noto-serif-600-normal-RZopCp-J.woff": "a8b4433851ac750477a973bd493289e4df7c45072c6a66b08354d9796d42d405",
|
||||
"build/assets/noto-serif-700-normal-CIw17UNa.woff2": "0d0b440760c93e6fec440ad438d10cea6c70367a0f5ecfcfa15cef0a85c67093",
|
||||
"build/assets/noto-serif-700-normal-mX-AlFMT.woff": "7057093244f719a3fd3706e9d1941b4161941ffcce81ecc661bc93644bbbd6df",
|
||||
"build/assets/operation-key-Dr4VtGxa.js": "416fed7a5197657971af7f378998557c9dba2f99e266e39149b727e598bea439",
|
||||
"build/assets/opportunities-COK8VNwo.js": "1e1d406e10cd67e52b7986dde38df0fb5648ef66861b5b6138fcbffdddbd28c7",
|
||||
"build/assets/opportunity-classification-B4UEUrhY.js": "91fd5e0eb121c6d89a6888cfc1acb5ff4da33b23f70f51b7b53188992b5e5fef",
|
||||
"build/assets/opportunity-draft-lHUZeNnA.js": "a7473984160305f266bd290fdfae8cd5e5260b125fb516b71e462053b20d3e05",
|
||||
"build/assets/opportunity-install-D8n6mSsB.js": "dc2677b2bf109316122c85b5fafa424f7e1af3ca0d1e6d3f6e140b5d41406108",
|
||||
"build/assets/opportunity-origin-B_gD83Dl.js": "c2d9f45c43317eb644682dfaea5529f94aa8ab2fb67886d2ec885375349a7ad2",
|
||||
"build/assets/opportunity-resources--lc4Z7SW.js": "61456522dcbcc1221b96f5fed6dc1271fde5aca2203e9be819820f9a85865c84",
|
||||
"build/assets/panel-CNBwgp5t.js": "23216f07dfcbca3dcc293c8ba3ac91b2019a3692f6edddd259a2a3b86fec5be1",
|
||||
"build/assets/partnership-source-links-B7OrliV8.js": "cc2529bb6328255b966d0749bf4c148996cc295d93fedd6e9da323f9c2c44e40",
|
||||
"build/assets/passkey-verify-Dly1EJzK.js": "455a901a2ca297c3a520d99d6b394538367d8664ccc21dab55f6233840c662b4",
|
||||
"build/assets/password-CB_NxgQN.js": "4415e495723009fc084111bafd2b7714221a3712e5f1d2a4dfa0e698f6308c7a",
|
||||
"build/assets/password-input-CSlmhC-X.js": "e15154fe3d7388e245eb034c32a11bdff7c9c1c7f5bf51222b363de2393f7d40",
|
||||
"build/assets/portal-api-tEuwFTsU.js": "190505d0a96d610ef2893cf06c63edab30f427593452bbc0dafc9d8f8a826c70",
|
||||
"build/assets/portfolio-C_Q-Nk8V.js": "1cc248badb20f658029c8439db65fb4879aad2de7f6d2062dec5069f84010f21",
|
||||
"build/assets/print-EIzSB6Ku.js": "bad87486159deb855589aa92fc7032ea28de222693c2816f2ff54b1583ef6513",
|
||||
"build/assets/profile-BYnB_Mq2.js": "228884ef228b3309c56dfee082ebcb3f15b895296934e866c4604e38155230ec",
|
||||
"build/assets/profile-B_9OCzxs.js": "68bf20e316421c4b035ed83b715aad6bcbb3513968ccab623afe63e74bf5a390",
|
||||
"build/assets/profile-json-BC1mQPe5.js": "269ee0efeb8b9b9e175e6e23e553b5b11b0dd8bdffdde3a99b76427c900dfa2a",
|
||||
"build/assets/project-dossier-BTTYtUNS.js": "fb5df77cb96b696c7945848dd68cd8e3d8f835d00cfd37735e4120405c169870",
|
||||
"build/assets/react-mlFDtEmO.js": "5e08e8c8b2c0adddfcaedcd1e350406e9db7115a86d9dcf4ee02c9508d3158a5",
|
||||
"build/assets/references-86dJ67Zc.js": "4d4401c06edd3558e10a6c0fe250c03b590c843f33ae5cd473996db3405c5c29",
|
||||
"build/assets/register-Er2G-F3m.js": "debf8641f54af3bda5f79e39887ceac1efdae18939df20e1b1d70f45c9182e47",
|
||||
"build/assets/relationship-repair-KOVytyPI.js": "755066b660566a764bc24fd1bc950ecf16a0c04ff91e8b859d30c56653f5614d",
|
||||
"build/assets/request-CINhDZym.js": "6249c3303a498f8d4109bcd2ee2b8a6045b1d685d2b341168af4f8efc1083577",
|
||||
"build/assets/request-DFhstEZc.js": "216695c50f04e344824ea6adc18f7131d3c841abc0361c9adeca4639a829a4cd",
|
||||
"build/assets/reset-password-CxbTbrIo.js": "93d9697724123dc786cbd39efb681bb52ebaa7d7170042e0c90d61c08b9b4cdc",
|
||||
"build/assets/result-CoXA-Ibg.js": "bff88476d6978e18694ea3702565113e5e2e8dca0632b36899e1872055219a87",
|
||||
"build/assets/rolldown-runtime-Dd_uD5pT.js": "c5f0356f5d0918a3137e4e811fd18950efe8ac8f6bf84d1d4da7811c477a24d8",
|
||||
"build/assets/room-BiVdR9q8.js": "c18efd64c83ad8fa115ff14ef42ec9f9d195085b3e2a6048ccdc9c59670a45ea",
|
||||
"build/assets/security-DzWeJG4q.js": "722a21f22e5a7894df9cf78fd7a370ab9e4db005af1cd2c30ba246414e2fbd31",
|
||||
"build/assets/services-Cd-m6rpo.js": "0765eeb4e3d31fa551ab013b2ece2d8fa38edd60296835cc17e1f97a50c05eae",
|
||||
"build/assets/shared-B0DslzBA.js": "4b1773d730b2103a6eb402bc9661b6b3291de0ac58dfc45676ec087bc90a8ada",
|
||||
"build/assets/shared-Bv15ZcQS.js": "75b8e8f27d85bc360840471965b66e99812a1751f2d3da6255238609b890b4c8",
|
||||
"build/assets/shared-_Diy3WCu.js": "41f6ef070e5d1cffe791ad787f37544fa69edd4d4121ed3fa87930e9cd808555",
|
||||
"build/assets/shared-drdcL7HN.js": "bab1bf0c93b891d022f6bfc7a766417b960bd1a66d3fda9c46c923dce54767dc",
|
||||
"build/assets/show-7jSL953d.js": "7b0b45c4db2c76a43dc72317001391c567fe7b5b6747a5554890b7639f373a51",
|
||||
"build/assets/show-mV475tmT.js": "1c0c002e4e4754dc93b14e7897e53a90a014ed06937a80cf457cbd3a4a80df3c",
|
||||
"build/assets/sources-rE0S91jD.js": "01bbab09c78769ed6264d720bf5f10b06fa2b49395de1377b6f536b21c3fc3d9",
|
||||
"build/assets/spinner-hD8hHC_m.js": "0091bbe0e4125cbe30ecd10ec9ff65cff9b7bd270125913d85b4449144aa91fd",
|
||||
"build/assets/structure-geography-DCJmB6wg.js": "5829a3a2af3c155e259d665f3b19e6b662d0caaf3662241c188ff2d9de1d5213",
|
||||
"build/assets/structures-BBKbr9tr.js": "500c1b1ef22d8996daa151a8fe611b767c8d637e56fa3a9a02d95d6803d61d82",
|
||||
"build/assets/submission-CbfZ-mLn.js": "017325cabc230ce085c43691cf2481a699cd5a24e4abb693640a7003134c1310",
|
||||
"build/assets/territorial-source-evidence-eKB4ZB36.js": "14048631c51933a0389cea37ae1909a02ea86d564a5a05452a48b40f055cd605",
|
||||
"build/assets/territory-associations-Bdv_d3vO.js": "8f5a8d9ae6150fc18a220636a8d8e9995dcd650c77939455e729b17dcc75675b",
|
||||
"build/assets/territory-geometry-import-D0EBneG2.js": "7eaf7acfa0eafb2b93ac308b98e73d6de8f1be205df513d3b63cc51067ad003a",
|
||||
"build/assets/territory-geometry-preview-CT9rz1r6.js": "ed13507df1b48defb187dfef5e67419017bc6d1e4bc5395efd772386382c1657",
|
||||
"build/assets/text-link-DE5bJEGx.js": "19d006b567063a6b3a9fb1b299a3c1201530dd2cbacd9ab1f3891cc89acba40d",
|
||||
"build/assets/two-factor-challenge-CeHEAK42.js": "a77520d5fbb6c52bf5e65be7e273e390620027e685c8a450c3c2bf2c22dae4ee",
|
||||
"build/assets/types-BoD_IJFv.js": "75c4a127c1aa0b90fe0b4f956c7e3ae9c67bc0f862c89cd0a594709027b983da",
|
||||
"build/assets/types-Cxp_Nskt.js": "cf4ae8cb539c697ca751dcf96e1db3af9eb1ff00807c088268dd859e7c4a5dab",
|
||||
"build/assets/use-two-factor-auth-Dv2TBEg_.js": "49b905a055455141be220e081ac6ee2c38402196cef590410c2af1f86d3e3430",
|
||||
"build/assets/utils-CCDJ05Ll.js": "ef54f43266d404b8ffe4e5487b346060eaf81d819317f523c966aa3e7490deb8",
|
||||
"build/assets/value-network-BG8eHihw.js": "8afe7e2120fb72ef3c8948dc7f01c250a542da87d51c8b7ce0669e8b10a838ef",
|
||||
"build/assets/value-text-BztaYdGl.js": "873576810a6ba4eb8c9c116f53cdc649b21ab2995aa2adadd4c85130b04bacd2",
|
||||
"build/assets/verification-BOcn3HIw.js": "10addac3d8f1865e855943e0685e88a268ffd8013ff7a7d51fb89d755b12074e",
|
||||
"build/assets/verify-email-BebQ_QDn.js": "141d7ea9f75f44c1b914af3663c0226c222561501b4f4b9e7d1e6120e4a83aee",
|
||||
"build/assets/wayfinder-Dp7PqxvV.js": "3d4c90228fda731e37f541f3087fdf5387d9d59433e35b267b64a97196f70781",
|
||||
"build/assets/welcome-DjOoM67E.js": "c73f247cb93b48961a80415c5b3d683b2cfbf32d2250eea80ae1c3a5393c676b",
|
||||
"build/assets/workspace-BaccTw8S.js": "d9063b84be8f676f4b7beefff38e29e0c2a9cb3a810ece4d7a502db34523099a",
|
||||
"build/assets/workspace-BqjDqWpq.js": "3389a84a9675a8f426a8c890152b87359bb451d5b3839dccda478f291f696581",
|
||||
"build/assets/workspace-CJH4dSzM.js": "834a12557a7fd61112c3eb804bffe52802350482a386b3404969bb15010280cc",
|
||||
"build/assets/zone-Cxk-nhVJ.js": "7070636e16b3c3d00e98718ac4cf296e4e558c18a624b0114f79f52a6c0adeb5",
|
||||
"build/assets/zone-attachments-DN6HRiW5.js": "16987b94fe35b6ee3025d4f353651ff79438452036a186af5e40423d699cb935",
|
||||
"build/assets/zone-map-Nu1V2MPg.js": "50675e1aac392c99a20b7296c88a080db163ec2975b77912eb94e7652dc269f5",
|
||||
"build/assets/zone-relations-C_4XEKfR.js": "6f74bf96da4323a1367c05f15ac7f2e08559bb518ad559fb0250f32d8d3e8d92",
|
||||
"build/assets/zones-BhHvVu0K.js": "4c177052da2150cf6e61bd92a1616c8c81d0d17af3a17944664ba0ccbe26c2c6",
|
||||
"build/fonts-manifest.json": "63af12fa290d22af8ea1893b8dcf9f57ca1a62fbfd7d33efa5d3f6117d7e7f8e",
|
||||
"build/manifest.json": "b1fa5647d63bcf2cd448dd4b197c58497e725ff4897e4114152d22065abc7a7a"
|
||||
},
|
||||
"migrations": 0,
|
||||
"flags_changed": 0,
|
||||
"business_writes": 0,
|
||||
"synthetic_data_imported": false,
|
||||
"accepted_QA_repeated": false,
|
||||
"backup_restore_verified": true,
|
||||
"cache_commands": [
|
||||
"config:clear",
|
||||
"route:clear",
|
||||
"view:clear"
|
||||
],
|
||||
"data_cache_unchanged_during_switch": true,
|
||||
"result": "17 sources and 174 build files delivered; operational GET confirmation pending"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"at": "2026-10-15T20:26:15+00:00",
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"target": {
|
||||
"database": "investemoz",
|
||||
"port": 5432
|
||||
},
|
||||
"restore_target": {
|
||||
"database": "classification_before_20261015_202406_test",
|
||||
"port": 55441
|
||||
},
|
||||
"restore_verified": true,
|
||||
"files_verified": true,
|
||||
"tables": 295,
|
||||
"sequences": 31,
|
||||
"restored_table_hashes_equal": true,
|
||||
"private_directory": "C:\/Users\/macbook\/.config\/investmoz\/classification-before-20261015_202406",
|
||||
"dump_sha256": "7e7bd1b582d25d446dbfce8b4fbb399602caf0b8d4dc503a21e9515f63b57aaf",
|
||||
"files_sha256": "1232b8cf3a0d32f97d7231f6b5504362cbd2b3b24bc0cd13bc82728a02b39629",
|
||||
"file_count": 2221,
|
||||
"document_files": 29,
|
||||
"preexisting_unavailable_document_count": 0,
|
||||
"190000_before": 1,
|
||||
"cache_state": {
|
||||
"configuration_cached": false,
|
||||
"routes_cached": false,
|
||||
"views_precompiled": false,
|
||||
"views_mode_evidence": "Previous installed delivery used view:clear only; views are compiled on request",
|
||||
"configuration_path": "C:\\laragon\\www\\portal-investidor\\bootstrap\\cache\/config.php",
|
||||
"routes_path": "C:\\laragon\\www\\portal-investidor\\bootstrap\\cache\/routes-v7.php",
|
||||
"compiled_views_path": "C:\\laragon\\www\\portal-investidor\\storage\\framework\\views",
|
||||
"data_cache_store": "database",
|
||||
"data_cache_file_path": "C:\\laragon\\www\\portal-investidor\\storage\\framework\/cache\/data"
|
||||
},
|
||||
"B_path_flag_before": true,
|
||||
"legacy_reader_before": true,
|
||||
"active_business_writes": 0
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"at": "2026-10-15T20:28:41.509148+00:00",
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"phase": "after",
|
||||
"TLS_certificate_and_hostname_verified": true,
|
||||
"checks": [
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/up",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/oportunidades",
|
||||
"status": 200,
|
||||
"anonymous": true
|
||||
}
|
||||
],
|
||||
"public_catalogue": {
|
||||
"total": 6,
|
||||
"first_page": [
|
||||
{
|
||||
"id": 6,
|
||||
"slug": "inv-mz-fin-006-plataforma-de-credito-para-pme-agricolas",
|
||||
"title": "Plataforma de crédito para PME agrícolas"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"slug": "inv-mz-blue-005-processamento-de-pescado-e-cadeia-fria",
|
||||
"title": "Processamento de pescado e cadeia fria"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"slug": "inv-mz-inf-004-centro-logistico-provincial",
|
||||
"title": "Centro logístico provincial"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"slug": "inv-mz-tur-003-eco-lodge-costeiro-com-integracao-comunitaria",
|
||||
"title": "Eco-lodge costeiro com integração comunitária"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"slug": "inv-mz-ene-002-mini-rede-solar-para-polo-produtivo",
|
||||
"title": "Mini-rede solar para polo produtivo"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"slug": "inv-mz-agr-001-unidade-de-processamento-agricola-em-nampula",
|
||||
"title": "Unidade de processamento agrícola em Nampula"
|
||||
}
|
||||
]
|
||||
},
|
||||
"served_entry_assets": [
|
||||
{
|
||||
"path": "/build/assets/app-Bq3lXpJL.css",
|
||||
"status": 200,
|
||||
"sha256": "f1c1531eda03206e53cb4b81a14af8ecee04671a743e29bc2aae371df15ba493"
|
||||
},
|
||||
{
|
||||
"path": "/build/assets/interactive-investment-map-1DTFk8zz.css",
|
||||
"status": 200,
|
||||
"sha256": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de"
|
||||
},
|
||||
{
|
||||
"path": "/build/assets/app-BpQ_dwxz.js",
|
||||
"status": 200,
|
||||
"sha256": "d49fddcff9093ae43b8d8666b673eb1a8db4a88ca989d0e0b3ba3176ef7dce04"
|
||||
},
|
||||
{
|
||||
"path": "/build/assets/catalogue-CHPIbGW1.js",
|
||||
"status": 200,
|
||||
"sha256": "b38d01a4a4bc3262aea8d3e6108e7fca3ae8faf04194d79c335f0de0b69bc0c9"
|
||||
}
|
||||
],
|
||||
"public_catalogue_preserved": true,
|
||||
"business_writes": 0,
|
||||
"functional_QA_repeated": false
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"at": "2026-10-15T20:28:08.094438+00:00",
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"phase": "before",
|
||||
"TLS_certificate_and_hostname_verified": true,
|
||||
"checks": [
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/up",
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/oportunidades",
|
||||
"status": 200,
|
||||
"anonymous": true
|
||||
}
|
||||
],
|
||||
"public_catalogue": {
|
||||
"total": 6,
|
||||
"first_page": [
|
||||
{
|
||||
"id": 6,
|
||||
"slug": "inv-mz-fin-006-plataforma-de-credito-para-pme-agricolas",
|
||||
"title": "Plataforma de crédito para PME agrícolas"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"slug": "inv-mz-blue-005-processamento-de-pescado-e-cadeia-fria",
|
||||
"title": "Processamento de pescado e cadeia fria"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"slug": "inv-mz-inf-004-centro-logistico-provincial",
|
||||
"title": "Centro logístico provincial"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"slug": "inv-mz-tur-003-eco-lodge-costeiro-com-integracao-comunitaria",
|
||||
"title": "Eco-lodge costeiro com integração comunitária"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"slug": "inv-mz-ene-002-mini-rede-solar-para-polo-produtivo",
|
||||
"title": "Mini-rede solar para polo produtivo"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"slug": "inv-mz-agr-001-unidade-de-processamento-agricola-em-nampula",
|
||||
"title": "Unidade de processamento agrícola em Nampula"
|
||||
}
|
||||
]
|
||||
},
|
||||
"served_entry_assets": [
|
||||
{
|
||||
"path": "/build/assets/app-Bq3lXpJL.css",
|
||||
"status": 200,
|
||||
"sha256": "f1c1531eda03206e53cb4b81a14af8ecee04671a743e29bc2aae371df15ba493"
|
||||
},
|
||||
{
|
||||
"path": "/build/assets/interactive-investment-map-1DTFk8zz.css",
|
||||
"status": 200,
|
||||
"sha256": "13748a8189dc8c690fc902a1682d30ba289721688f32df4f2459a36de8e383de"
|
||||
},
|
||||
{
|
||||
"path": "/build/assets/app-C9JtWOlF.js",
|
||||
"status": 200,
|
||||
"sha256": "6038fbfe2b6c7e3e6f88bfd44ff816df655f1e05dafc14e991af9a46491cb979"
|
||||
},
|
||||
{
|
||||
"path": "/build/assets/catalogue-Bxt4AUEn.js",
|
||||
"status": 200,
|
||||
"sha256": "3a6ab8f4d7cc3aebb275895433d60f6066e5b29db2c6fb2ece6e45bae6b96231"
|
||||
}
|
||||
],
|
||||
"public_catalogue_preserved": false,
|
||||
"business_writes": 0,
|
||||
"functional_QA_repeated": false
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"document_revision": "DOC01",
|
||||
"delivery_state": "deployed",
|
||||
"files": {
|
||||
"ARRANQUE-CLONE-RESTAURADO.json": {
|
||||
"sha256": "37537022e4c4708ca024c3ee42b6f9c48e3c7192aaf9079c6e82e35f303c7cbc",
|
||||
"bytes": 1462
|
||||
},
|
||||
"ATIVO-403.jpg": {
|
||||
"sha256": "0dce0a45f89cf0603bcbdd50f5b3a848892ab43a418d88019c89b7885aec4c41",
|
||||
"bytes": 16447
|
||||
},
|
||||
"ATIVO-CATALOGO.jpg": {
|
||||
"sha256": "a2ca71cbdcf69f73af5a031f30609a7087c6cab7c93dbbb50aab308672e47157",
|
||||
"bytes": 138849
|
||||
},
|
||||
"ATUALIZACAO-MESMA-MATRIZ.json": {
|
||||
"sha256": "792fe2f6a36db2a536e6a84a1dc9570eb19aa8719a5d0ec55bb60c441381159d",
|
||||
"bytes": 557
|
||||
},
|
||||
"AUTORIZACAO-TEMPO.json": {
|
||||
"sha256": "4b4112da0340a45d687a4ec0f5c6cd563e2b00b1a78078d11c9b34568c6bc14a",
|
||||
"bytes": 977
|
||||
},
|
||||
"CACHE-DADOS-AFTER.json": {
|
||||
"sha256": "495b64153961a283ca4c3e0c76ed2b60867fefed41d40d3a1ab9940b6eb753ff",
|
||||
"bytes": 153
|
||||
},
|
||||
"CACHE-DADOS-BEFORE.json": {
|
||||
"sha256": "495b64153961a283ca4c3e0c76ed2b60867fefed41d40d3a1ab9940b6eb753ff",
|
||||
"bytes": 153
|
||||
},
|
||||
"FONTES-COMPILACAO.json": {
|
||||
"sha256": "232e5096c367d1ab33a7d69090768d4f38aa4c2988946f0fc761bdb555fbea0a",
|
||||
"bytes": 27932
|
||||
},
|
||||
"FRESH-BACKUP.json": {
|
||||
"sha256": "4bdbbebc05d65ad29a2a9820525a0c657f5d9bd27f7aec4adf7b617f0cd2bbd8",
|
||||
"bytes": 1632
|
||||
},
|
||||
"HTTP-AFTER.json": {
|
||||
"sha256": "252eb29d4c51d4f981c6c9d05b250bb7d91cb794368f16480bd02ab0e3873aab",
|
||||
"bytes": 2353
|
||||
},
|
||||
"HTTP-BEFORE.json": {
|
||||
"sha256": "b1e6c52d1aae2a7e8d812600041255aa3955de8145f1de21894b0332ad15a1e0",
|
||||
"bytes": 2355
|
||||
},
|
||||
"INTERFACE-OPERACIONAL.json": {
|
||||
"sha256": "f8f8c714c9bdd2184660b8860591f40619f23d28ff6dc210881cba0d29cf59f2",
|
||||
"bytes": 1512
|
||||
},
|
||||
"MAPA-REVERSAO-EXECUCAO.json": {
|
||||
"sha256": "354bef29bc68d55e27dcede121b3b652a519b2aa6db692380a6639da99496d90",
|
||||
"bytes": 6136
|
||||
},
|
||||
"PREFLIGHT.json": {
|
||||
"sha256": "c743d9c52a3b888dc09c90ab14bec24df898dcc99345da49846b99fc31cbf2e6",
|
||||
"bytes": 117600
|
||||
},
|
||||
"PRESERVACAO-AFTER.json": {
|
||||
"sha256": "6bb5138bd2e455a82a2dc81fc77aedc1889eaa4dde9b438f42599ccb78802393",
|
||||
"bytes": 110702
|
||||
},
|
||||
"PRESERVACAO-BEFORE.json": {
|
||||
"sha256": "cec49616a751e2cd7f349444a0529881ad9ad35f0903eca38bd9271fcd2a6779",
|
||||
"bytes": 110699
|
||||
},
|
||||
"PRESERVACAO-FINAL.json": {
|
||||
"sha256": "a56251c65b8987cabec9be5e36dc90afeec474cc15f85e81a4dda46ecaa8d2bd",
|
||||
"bytes": 111243
|
||||
},
|
||||
"RECUSA-403-REGRA-ANTERIOR.json": {
|
||||
"sha256": "d6911c2d7ac36eff2b8173a823de2de0cc32f79e5c3d914ee1e28146d1d2988e",
|
||||
"bytes": 958
|
||||
},
|
||||
"RELATORIO-ENTREGA.md": {
|
||||
"sha256": "bc24202bdc8f4e2b26d33b78466426fc48ff4a258224522ba84e09fe29718417",
|
||||
"bytes": 6987
|
||||
},
|
||||
"boot-restored-clone.php": {
|
||||
"sha256": "159aff4bcb2d346c8242ae20c1bdb569bb7c5d8d3d70dbdfea8071a1f9de9484",
|
||||
"bytes": 6502
|
||||
},
|
||||
"cache-snapshot.php": {
|
||||
"sha256": "46c8e18eb07b628f69619a0ca1a1c5a769b0321b2c364308241d1da3fc9f4aab",
|
||||
"bytes": 2944
|
||||
},
|
||||
"candidata/classificacao-multidimensional-QA-64ab05e20b95-doc01.zip": {
|
||||
"sha256": "334d8ef2e47848a3c30cf526ae4d394004f112288cdddbcf635f06a1be1e0bc6",
|
||||
"bytes": 1756371
|
||||
},
|
||||
"deliver.py": {
|
||||
"sha256": "c13b0d3c2f7221fc624f38275183ab6bd42677dbc53473c2755d46077f5417bf",
|
||||
"bytes": 6605
|
||||
},
|
||||
"fresh-backup.php": {
|
||||
"sha256": "3e77fb785ac149a6260ccf91a88f1f7f7e9b21b9d500d27f48325f40ee88c08c",
|
||||
"bytes": 10662
|
||||
},
|
||||
"http-operacional.py": {
|
||||
"sha256": "cd86488f65d2a7bb8a3449f4ab5d4fa7d703c049a04909631a9fbd7fda94e2e2",
|
||||
"bytes": 2885
|
||||
},
|
||||
"preflight.py": {
|
||||
"sha256": "55f90f5d633dfdc9131813f8c872d200e4e19e0c6b5ce1ed1bae4491f7799677",
|
||||
"bytes": 3328
|
||||
},
|
||||
"revert-compatible.py": {
|
||||
"sha256": "2b133f546293d6f38a2fa85cbe7b22a13f29906e5399a4205fdff6bbf4f07ecf",
|
||||
"bytes": 3879
|
||||
},
|
||||
"verify-preservation.php": {
|
||||
"sha256": "e8e1faad3335bd271b583fd48d5f78c9874be6b1267623c1d2c33bab7a064c64",
|
||||
"bytes": 6311
|
||||
}
|
||||
},
|
||||
"exclusions": "No database dump, backups of private data, credentials, sessions or configuration contents are attached.",
|
||||
"operational_document_revision": "OPS-DOC01"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"target": "https://portal-investidor.test",
|
||||
"catalogue_visible": true,
|
||||
"catalogue_screenshot": "ATIVO-CATALOGO.jpg",
|
||||
"classification_filter_labels_visible": true,
|
||||
"observed_session": "Osmane Nala",
|
||||
"review_queue_records": 0,
|
||||
"editor_in_authorized_operational_session": "not observed: operational login unavailable; current superuser session has no active elevation",
|
||||
"user_reply": "Não tenho acesso à conta de Aurora",
|
||||
"business_saves": 0,
|
||||
"accepted_QA_repeated": false,
|
||||
"at": "2026-10-15T20:37:26.422282+00:00",
|
||||
"editor_observation_status": "not_observed",
|
||||
"editor_observation_summary": "Editor no ativo: não demonstrado nesta conferência. O utilizador informou não ter acesso à conta de Promotora interna Aurora Chachuaio. A sessão efetiva Osmane Nala, conta 2, recebeu 403 em GET /minhas-oportunidades/create; não existe elevação operacional ativa. Os papéis Promotor/Validador dessa conta permanecem atribuídos; as funções de autorização v1 conferem exatamente com a versão anterior à entrega. Existem seis oportunidades legadas e nenhuma do workflow de promotor no ativo. A mensagem 403 genérica não expõe o motivo; o diagnóstico fica registado, sem alterar permissões, credenciais ou acrescentar uma correção fora do pacote autorizado. Mantêm-se as provas funcionais QA aceites do editor.",
|
||||
"denial_evidence": "RECUSA-403-REGRA-ANTERIOR.json",
|
||||
"denial_screenshot": "ATIVO-403.jpg"
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"backup_restore_proof": "FRESH-BACKUP.json",
|
||||
"clone_boot_proof": "ARRANQUE-CLONE-RESTAURADO.json",
|
||||
"sources": [
|
||||
{
|
||||
"path": "app/Http/Controllers/InvestmentDiscoveryController.php",
|
||||
"delivered_sha256": "df3cc8f5a43766832399cbde836617bf86e7fcbde56b660f008714daf5560ba8",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "8898ea492b6f744917dc2a0606fcbac460275b3540d9c765f939ceb4fccff0a0"
|
||||
},
|
||||
{
|
||||
"path": "app/Http/Controllers/OpportunityClassificationController.php",
|
||||
"delivered_sha256": "7befceff95da3e50fe635cc635f654897b94d26f3a0cddbd861251a5cdf18333",
|
||||
"action": "remove only after references restored and delivered hash matches",
|
||||
"rollback_sha256": null
|
||||
},
|
||||
{
|
||||
"path": "app/Http/Middleware/ProtectProfileOpportunity.php",
|
||||
"delivered_sha256": "53c30d652a568733ecbd240acc8c22165307de9e26b761b3d26ba1468f4d7b5b",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "a9cde5cc47ae04007116740e9c842751ec88948b71eb9fbac633db84c34fa541"
|
||||
},
|
||||
{
|
||||
"path": "app/Services/InvestmentCatalogue.php",
|
||||
"delivered_sha256": "65fbb701f3ab589c3b08886f1a8adefa1bd782d30758176b804df4fd10541824",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "948c9b78f892665700ed324d6e1ac92b591735f120236d86b13b58a1db39d0d5"
|
||||
},
|
||||
{
|
||||
"path": "app/Services/OpportunityCanonicalContract.php",
|
||||
"delivered_sha256": "78f7656b13a09830bd20e1cd4258e1f364e064851348fdbedcb745629f5c9591",
|
||||
"action": "restore compatible previous contract after use; never blindly restore old contract",
|
||||
"rollback_sha256": "6023295d57063b6054662515eb837930ac4bffa642744433499dd0b1912f5107"
|
||||
},
|
||||
{
|
||||
"path": "app/Services/OpportunityCanonicalResponse.php",
|
||||
"delivered_sha256": "21b67b9354235a9b586c9db87a7fd7221bc4ed9895b7bb9bc008f28a804b43d4",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "31c2f60a1337c91c801b2576ee2af545f1d47b1abb76d5859463932b45268ae1"
|
||||
},
|
||||
{
|
||||
"path": "app/Services/OpportunityClassification.php",
|
||||
"delivered_sha256": "fc924b187bbe1634a4723c4d11d1412228d7a90816189d2260b2e12f9d9a7cbe",
|
||||
"action": "remove only after references restored and delivered hash matches",
|
||||
"rollback_sha256": null
|
||||
},
|
||||
{
|
||||
"path": "app/Services/OpportunityManagement.php",
|
||||
"delivered_sha256": "b8fbb40f7f143db71c380be64809e3e8ac2f92b9cdefe6206a0e98be598b9399",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "955bd3fe1541ad9196091692540c40dcef9fb4e6e65195d1f5a39a97ec36f913"
|
||||
},
|
||||
{
|
||||
"path": "app/Services/OpportunityProfileWorkflow.php",
|
||||
"delivered_sha256": "9c0f7f10efdc55da19e2baf3482d755ba9e6d7239382fc8cdf9c9be636859457",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "1d05a8e445c421364a534323e447b8cff84be2254d5f335ef1a1a4a2b18fe365"
|
||||
},
|
||||
{
|
||||
"path": "app/Services/PortalProfileAccess.php",
|
||||
"delivered_sha256": "5ce3b9d9162ba513523bb0ae2b43cfd10f21f4cfddeb17b94b6f4c54f3a007c7",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "9140ac0eb9f55d22bda1d97a5d97b263f7c3120384f28684dae61950ab51d1c3"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/components/opportunity-canonical-fields.tsx",
|
||||
"delivered_sha256": "542ee4d6bdbd259fc1c7a5a41757bb78279cc4210bbe75d2d377f894598cc83d",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "ca5f07627707f0a7a75ea1c7e3fed9bb8381917a07e85d6401242c9f2d87d9eb"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/components/opportunity-classification.tsx",
|
||||
"delivered_sha256": "91a609af736dcaefac3e47ebab30156e8081f7ae5024f38066b8ef9dfdb3505b",
|
||||
"action": "remove only after references restored and delivered hash matches",
|
||||
"rollback_sha256": null
|
||||
},
|
||||
{
|
||||
"path": "resources/js/pages/investment/catalogue.tsx",
|
||||
"delivered_sha256": "649955876ab712c4cba0bdadf1dd3fa511ad10059b58cd4c242a5f84f7c8be2b",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "99707526863691eeef0d3c7971b6a3399d193f8e9fc2ade25ce1dbf2fd866b11"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/pages/investment/detail.tsx",
|
||||
"delivered_sha256": "c83686fa00fda4de82f3a8d3c842d0526b10635a2b76b1c3ec54d69c96a69e6d",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "048c70bb3fa9671721d2a0c0361935df5336c39e46b2d71bb16de29e25d5dd88"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/pages/investment/shared.tsx",
|
||||
"delivered_sha256": "56180116aab60d81e345506a9732081878825e143ab452f88df292299cccdce4",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "d40eac734af27c4bb79f3a968da18a909d26c5890795508dda4f1180b0aa5ecb"
|
||||
},
|
||||
{
|
||||
"path": "resources/js/pages/management/opportunity-draft.tsx",
|
||||
"delivered_sha256": "d40a69e4f3e4234c4a67732794e53e311c0f4e47c353e9f1535cdbd7e6664ef1",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "4b6acdc5565f8c357fb3df6ed3cbae905b52cf908008479aa4f00593ce5dc8c3"
|
||||
},
|
||||
{
|
||||
"path": "routes/web.php",
|
||||
"delivered_sha256": "049080ce60b271f9d1a28e5cb7a2a59d8973f6b562a3893b42057d39d336c10f",
|
||||
"action": "restore from fresh backup",
|
||||
"rollback_sha256": "b5710eeb6432c5643cc91a23ee93a2013d813504336897ce10811d567cb89c9f"
|
||||
}
|
||||
],
|
||||
"build": "restore complete previous build and manifest from fresh backup; old assets retained",
|
||||
"data": "do not restore database after subsequent use; preserve enterprise_size, relations, decisions, publications and history",
|
||||
"cache_commands": [
|
||||
"config:clear",
|
||||
"route:clear",
|
||||
"view:clear"
|
||||
],
|
||||
"data_cache_preserved": true,
|
||||
"reversal_script": "revert-compatible.py --candidate=classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"reversal_script_executed": false,
|
||||
"new_QA_rehearsal": false,
|
||||
"accepted_compatibility_proof": "outputs/investmoz-classificacao-multidimensional-QA-20261015/REVERSAO-COMPAT-QA.json"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"at": "2026-10-15T20:37:28.898094+00:00",
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"document_revision": "DOC01",
|
||||
"state": "deployed",
|
||||
"target": "https://portal-investidor.test",
|
||||
"candidate_zip_sha256": "334d8ef2e47848a3c30cf526ae4d394004f112288cdddbcf635f06a1be1e0bc6",
|
||||
"sources": 17,
|
||||
"replacements": 14,
|
||||
"new_sources": 3,
|
||||
"build_files": 174,
|
||||
"fresh_backup_restore_verified": true,
|
||||
"clone_kernel_boot_verified": true,
|
||||
"business_tables_compared": 295,
|
||||
"business_tables_identical_immediately_after_switch": true,
|
||||
"business_records_and_prior_history_preserved_at_final": true,
|
||||
"expected_access_denial_audit_rows_added": 2,
|
||||
"data_cache_unchanged_during_switch": true,
|
||||
"B_COUNTRY02_permissions_content_history_preserved": true,
|
||||
"migrations_run": 0,
|
||||
"real_association_writes": 0,
|
||||
"synthetic_data_imported": false,
|
||||
"accepted_QA_repeated": false,
|
||||
"editor_observation_status": "not_observed",
|
||||
"editor_observation_summary": "Editor no ativo: não demonstrado nesta conferência. O utilizador informou não ter acesso à conta de Promotora interna Aurora Chachuaio. A sessão efetiva Osmane Nala, conta 2, recebeu 403 em GET /minhas-oportunidades/create; não existe elevação operacional ativa. Os papéis Promotor/Validador dessa conta permanecem atribuídos; as funções de autorização v1 conferem exatamente com a versão anterior à entrega. Existem seis oportunidades legadas e nenhuma do workflow de promotor no ativo. A mensagem 403 genérica não expõe o motivo; o diagnóstico fica registado, sem alterar permissões, credenciais ou acrescentar uma correção fora do pacote autorizado. Mantêm-se as provas funcionais QA aceites do editor.",
|
||||
"compatible_rollback_contract_sha256": "6023295d57063b6054662515eb837930ac4bffa642744433499dd0b1912f5107",
|
||||
"rollback_executed": false,
|
||||
"matrix": {
|
||||
"before_sha256": "77ca8f755dc4f0e31baeb734421bb12007571d60c3dc2da14ccac581725af6bc",
|
||||
"after_sha256": "b0c3e267985a2f4a2c97da95efa8c1c7aaeb545731141ab6294736c66497159f",
|
||||
"rows": 3402,
|
||||
"changed_ids": [
|
||||
"M2-d0c06a75-0029",
|
||||
"M2-d0c06a75-0158",
|
||||
"MASTER-e1169a77-0043",
|
||||
"MASTER-e1169a77-0062",
|
||||
"OP-9f173ed3-0165",
|
||||
"RF-CLU-002",
|
||||
"RF-CLU-003",
|
||||
"RF-COR-003"
|
||||
],
|
||||
"other_raw_rows_preserved": 3394,
|
||||
"accepted_items_reopened": 0,
|
||||
"global_requirements_closed": 0,
|
||||
"new_requirements": 0,
|
||||
"same_existing_matrix": true
|
||||
},
|
||||
"artifact_hashes": {
|
||||
"ARRANQUE-CLONE-RESTAURADO.json": "37537022e4c4708ca024c3ee42b6f9c48e3c7192aaf9079c6e82e35f303c7cbc",
|
||||
"ATIVO-403.jpg": "0dce0a45f89cf0603bcbdd50f5b3a848892ab43a418d88019c89b7885aec4c41",
|
||||
"ATIVO-CATALOGO.jpg": "a2ca71cbdcf69f73af5a031f30609a7087c6cab7c93dbbb50aab308672e47157",
|
||||
"ATUALIZACAO-MESMA-MATRIZ.json": "792fe2f6a36db2a536e6a84a1dc9570eb19aa8719a5d0ec55bb60c441381159d",
|
||||
"AUTORIZACAO-TEMPO.json": "4b4112da0340a45d687a4ec0f5c6cd563e2b00b1a78078d11c9b34568c6bc14a",
|
||||
"CACHE-DADOS-AFTER.json": "495b64153961a283ca4c3e0c76ed2b60867fefed41d40d3a1ab9940b6eb753ff",
|
||||
"CACHE-DADOS-BEFORE.json": "495b64153961a283ca4c3e0c76ed2b60867fefed41d40d3a1ab9940b6eb753ff",
|
||||
"FONTES-COMPILACAO.json": "232e5096c367d1ab33a7d69090768d4f38aa4c2988946f0fc761bdb555fbea0a",
|
||||
"FRESH-BACKUP.json": "4bdbbebc05d65ad29a2a9820525a0c657f5d9bd27f7aec4adf7b617f0cd2bbd8",
|
||||
"HTTP-AFTER.json": "252eb29d4c51d4f981c6c9d05b250bb7d91cb794368f16480bd02ab0e3873aab",
|
||||
"HTTP-BEFORE.json": "b1e6c52d1aae2a7e8d812600041255aa3955de8145f1de21894b0332ad15a1e0",
|
||||
"INTERFACE-OPERACIONAL.json": "f8f8c714c9bdd2184660b8860591f40619f23d28ff6dc210881cba0d29cf59f2",
|
||||
"MAPA-REVERSAO-EXECUCAO.json": "354bef29bc68d55e27dcede121b3b652a519b2aa6db692380a6639da99496d90",
|
||||
"PREFLIGHT.json": "c743d9c52a3b888dc09c90ab14bec24df898dcc99345da49846b99fc31cbf2e6",
|
||||
"PRESERVACAO-AFTER.json": "6bb5138bd2e455a82a2dc81fc77aedc1889eaa4dde9b438f42599ccb78802393",
|
||||
"PRESERVACAO-BEFORE.json": "cec49616a751e2cd7f349444a0529881ad9ad35f0903eca38bd9271fcd2a6779",
|
||||
"PRESERVACAO-FINAL.json": "a56251c65b8987cabec9be5e36dc90afeec474cc15f85e81a4dda46ecaa8d2bd",
|
||||
"RECUSA-403-REGRA-ANTERIOR.json": "d6911c2d7ac36eff2b8173a823de2de0cc32f79e5c3d914ee1e28146d1d2988e",
|
||||
"RELATORIO-ENTREGA.md": "bc24202bdc8f4e2b26d33b78466426fc48ff4a258224522ba84e09fe29718417",
|
||||
"boot-restored-clone.php": "159aff4bcb2d346c8242ae20c1bdb569bb7c5d8d3d70dbdfea8071a1f9de9484",
|
||||
"cache-snapshot.php": "46c8e18eb07b628f69619a0ca1a1c5a769b0321b2c364308241d1da3fc9f4aab",
|
||||
"deliver.py": "c13b0d3c2f7221fc624f38275183ab6bd42677dbc53473c2755d46077f5417bf",
|
||||
"fresh-backup.php": "3e77fb785ac149a6260ccf91a88f1f7f7e9b21b9d500d27f48325f40ee88c08c",
|
||||
"http-operacional.py": "cd86488f65d2a7bb8a3449f4ab5d4fa7d703c049a04909631a9fbd7fda94e2e2",
|
||||
"preflight.py": "55f90f5d633dfdc9131813f8c872d200e4e19e0c6b5ce1ed1bae4491f7799677",
|
||||
"revert-compatible.py": "2b133f546293d6f38a2fa85cbe7b22a13f29906e5399a4205fdff6bbf4f07ecf",
|
||||
"verify-preservation.php": "e8e1faad3335bd271b583fd48d5f78c9874be6b1267623c1d2c33bab7a064c64"
|
||||
},
|
||||
"inventory_sha256": "9f0a0aac61f05753feb90fd46098e566935a88c6e5fa4ce206822ad34a6dbf8b",
|
||||
"zip": {
|
||||
"name": "classificacao-multidimensional-disponibilizado-20261015-64ab05e20b95-doc01.zip",
|
||||
"bytes": 1969142,
|
||||
"sha256": "6e8bfa5a39788368f23f816a215e6ed7037c6b23b0e64cea0950370a2ee76d3c",
|
||||
"entries": 29,
|
||||
"all_entries_verified": true
|
||||
},
|
||||
"remaining_global_gaps": [
|
||||
"/negocios",
|
||||
"full operational parks record",
|
||||
"missing economic references",
|
||||
"duplicate consolidation",
|
||||
"complete specific Fintech regulation"
|
||||
],
|
||||
"operational_document_revision": "OPS-DOC01",
|
||||
"operational_text_revised_at": "2026-10-15T20:39:27.411913+00:00",
|
||||
"previous_operational_zip_preserved": {
|
||||
"name": "classificacao-multidimensional-disponibilizado-20261015-64ab05e20b95.zip",
|
||||
"sha256": "d2fc6b5adace2358dd78cd964a02aba6f0c45d306c8228a1a72e76682163f455"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"authorization_functions_unchanged_since_before_delivery": {
|
||||
"grants": "e8dbd18926ad0909a2042b3ee5dc9b25e4f85f860dfe3d0b038836469f0be4f7",
|
||||
"superuser": "ab4c6d32cf35bd6cc60f93844f579c52f98326a1b645e1edb794f799437a6603",
|
||||
"mfa": "dd22c5bf7fa7cb56eec45bb394cfcc408f9bc965861eb83702e7d4747c5941b8",
|
||||
"operational": "b3a56a0a93ae7ae50dc410ad33b0de01cb6d6438ab81d705efe35cb94254eb38",
|
||||
"canCreate": "1dd29426be6b9a24395bb55a3cc9e526f4e5e1b4323d4dd9a81062122075baed",
|
||||
"scope": "a0a599a90e607ef61ca9c63ebd3e3f05fa516f1adb96e099d3b64731d33ec009",
|
||||
"navigation": "978a1cef4c4b76785d45af2b34201a3bd5e21906cf79763626e1b24fdb75a854"
|
||||
},
|
||||
"origin": "profiles-v1-20261010; AUD-PROFILE-10 and AUD-PROFILE-14 in perfis-v1-reconciliacao.md",
|
||||
"create_guard": "PortalProfileController::edit requires nonempty navigation contexts; superuser canCreate requires operational elevation and recent MFA",
|
||||
"permissions_changed": false
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
{
|
||||
"page_url": "https://chatgpt.com/space/page_d6f090dba9048191a92c9175b3605dee",
|
||||
"page_sequence": 12,
|
||||
"readback_verified": true,
|
||||
"document_revision": "DOC01",
|
||||
"operational_document_revision": "OPS-DOC01",
|
||||
"uploads": {
|
||||
"report": {
|
||||
"page_id": "page_d6f090dba9048191a92c9175b3605dee",
|
||||
"reference": "library-file:fde1_bGliZmlsZV95SDZzVERlV0FlSk4yQWxVZ3RJT3dR_FileDrive_c902110ccc308191b2f4f6a2fc8c014a",
|
||||
"file_name": "RELATORIO-ENTREGA-fa92fddf161444ab951f1e5a628c8b28.md",
|
||||
"mime_type": "text/markdown",
|
||||
"byte_size": 6987,
|
||||
"sha256": "bc24202bdc8f4e2b26d33b78466426fc48ff4a258224522ba84e09fe29718417",
|
||||
"file_access_confirmed": true,
|
||||
"is_image": false,
|
||||
"markdown": "[Classificação multidimensional — relatório final de disponibilização](library-file:fde1_bGliZmlsZV95SDZzVERlV0FlSk4yQWxVZ3RJT3dR_FileDrive_c902110ccc308191b2f4f6a2fc8c014a)",
|
||||
"inserted": false,
|
||||
"next_step": "Read the Page and use edit_page with its fresh guards to insert markdown."
|
||||
},
|
||||
"map": {
|
||||
"page_id": "page_d6f090dba9048191a92c9175b3605dee",
|
||||
"reference": "library-file:fde1_bGliZmlsZV9TVFZ6ZXd3S2pnUEYyZGJMTjVQZ2dn_FileDrive_c902110ccc308191b2f4f6a2fc8c014a",
|
||||
"file_name": "MAPA-REVERSAO-EXECUCAO-d80d5b4181a74695ba8b5c9a8c4eb9a1.json",
|
||||
"mime_type": "application/json",
|
||||
"byte_size": 6136,
|
||||
"sha256": "354bef29bc68d55e27dcede121b3b652a519b2aa6db692380a6639da99496d90",
|
||||
"file_access_confirmed": true,
|
||||
"is_image": false,
|
||||
"markdown": "[Classificação multidimensional — mapa de reversão executável](library-file:fde1_bGliZmlsZV9TVFZ6ZXd3S2pnUEYyZGJMTjVQZ2dn_FileDrive_c902110ccc308191b2f4f6a2fc8c014a)",
|
||||
"inserted": false,
|
||||
"next_step": "Read the Page and use edit_page with its fresh guards to insert markdown."
|
||||
},
|
||||
"receipt": {
|
||||
"page_id": "page_d6f090dba9048191a92c9175b3605dee",
|
||||
"reference": "library-file:fde1_bGliZmlsZV9oZmFQR1NiNEt3Q0staFIwNmRZYnN3_FileDrive_c902110ccc308191b2f4f6a2fc8c014a",
|
||||
"file_name": "RECIBO-FINAL-d4abc4dc1d6542d082bf08a18bebcd3a.json",
|
||||
"mime_type": "application/json",
|
||||
"byte_size": 5984,
|
||||
"sha256": "e4de219d0417b9f45fe9a565e4cee73d669a428924745d4a9b094bcda9b1dcdf",
|
||||
"file_access_confirmed": true,
|
||||
"is_image": false,
|
||||
"markdown": "[Classificação multidimensional — recibo final verificado](library-file:fde1_bGliZmlsZV9oZmFQR1NiNEt3Q0staFIwNmRZYnN3_FileDrive_c902110ccc308191b2f4f6a2fc8c014a)",
|
||||
"inserted": false,
|
||||
"next_step": "Read the Page and use edit_page with its fresh guards to insert markdown."
|
||||
},
|
||||
"zip": {
|
||||
"page_id": "page_d6f090dba9048191a92c9175b3605dee",
|
||||
"reference": "library-file:fde1_bGliZmlsZV9UTTdrY1Nyc3QxdkZ2YlJsS2RqNnh3_FileDrive_c902110ccc308191b2f4f6a2fc8c014a",
|
||||
"file_name": "classificacao-multidimensional-disponibilizado-20261015-64ab05e20b95-doc01-83170247653c49fdbd41d14f18aa6a81.zip",
|
||||
"mime_type": "application/zip",
|
||||
"byte_size": 1969142,
|
||||
"sha256": "6e8bfa5a39788368f23f816a215e6ed7037c6b23b0e64cea0950370a2ee76d3c",
|
||||
"file_access_confirmed": true,
|
||||
"is_image": false,
|
||||
"markdown": "[Classificação multidimensional — pacote operacional verificado](library-file:fde1_bGliZmlsZV9UTTdrY1Nyc3QxdkZ2YlJsS2RqNnh3_FileDrive_c902110ccc308191b2f4f6a2fc8c014a)",
|
||||
"inserted": false,
|
||||
"next_step": "Read the Page and use edit_page with its fresh guards to insert markdown."
|
||||
},
|
||||
"image": {
|
||||
"page_id": "page_d6f090dba9048191a92c9175b3605dee",
|
||||
"reference": "library-file:fde1_bGliZmlsZV8tMVUzSWtFTmJKbkpnXzdlcktfX2pB_FileDrive_c902110ccc308191b2f4f6a2fc8c014a",
|
||||
"file_name": "ATIVO-CATALOGO-ce6d6fef2f57433284c53617f0157461.jpg",
|
||||
"mime_type": "image/jpeg",
|
||||
"byte_size": 138849,
|
||||
"sha256": "a2ca71cbdcf69f73af5a031f30609a7087c6cab7c93dbbb50aab308672e47157",
|
||||
"file_access_confirmed": true,
|
||||
"is_image": true,
|
||||
"markdown": "",
|
||||
"inserted": false,
|
||||
"next_step": "Read the Page and use edit_page with its fresh guards to insert markdown."
|
||||
}
|
||||
},
|
||||
"edited_blocks": [
|
||||
{
|
||||
"id": "add7904c-200c-4c04-a70e-84316b26abcd",
|
||||
"hash": "5568f59fa9122a63dc9f8509f0b349c396ee1d3d071c4468a6bd7a40f0089181"
|
||||
},
|
||||
{
|
||||
"id": "4973b137-a463-4dbd-896a-6f5691e3451a",
|
||||
"hash": "8ff3481780e4745e1d8591845cfd272ac376d96826fc687266e2471f3be7571e"
|
||||
},
|
||||
{
|
||||
"id": "816a333f-11b1-431d-917f-253e3c5f8bb5",
|
||||
"hash": "cd99d93745f3e180e60fee435b17b14a07473b294040675f434e8acaa632aeba"
|
||||
},
|
||||
{
|
||||
"id": "6b04592d-6b43-4157-833d-7d6667d4d6ec",
|
||||
"hash": "cdc0ff6f0a0f1e259a1bc353b5b65bd109a83abee5b820ac48bb482fa0b9c803"
|
||||
},
|
||||
{
|
||||
"id": "3a558ec9-4fe4-4132-b9c3-cec6ededbdbc",
|
||||
"hash": "26a27b0f56f74bed04c1778b4f2b2cffe070a091631d4a0895810f70b46900e9"
|
||||
},
|
||||
{
|
||||
"id": "7ec52731-02b1-4245-8631-1dd58967a26d",
|
||||
"hash": "a7446daddaaf2718d2711d2f2dfed7e24729e07aad13e2d0d83d21c64fd9c57a"
|
||||
},
|
||||
{
|
||||
"id": "2fb0b630-f963-414e-a77e-7d59d5b4feb5",
|
||||
"hash": "1eeb3ce247e7aa27ea02a6cec591ec78cb92a842af3154d5f1fb256b18aaa740"
|
||||
},
|
||||
{
|
||||
"id": "c8b3e98d-782b-4599-8208-2e86cbf0998b",
|
||||
"hash": "a3dbf0a1cbf214230cd8d6a41d5b3c715e65aefe1f22ab25720886312da18155"
|
||||
},
|
||||
{
|
||||
"id": "181087b1-6188-4e2d-945d-715ffca414d8",
|
||||
"hash": "0d946170f71b8da47d63b54b88e6e46d33b5f1db0ddb2f4fa7537c0cbc123f74"
|
||||
},
|
||||
{
|
||||
"id": "c1fb0671-60ea-44a5-8e50-0117a9c05e75",
|
||||
"hash": "e8b35bb2cdb426e3fcc04177752453290ec5836b884568a1b3956e095f112c75"
|
||||
},
|
||||
{
|
||||
"id": "85ce56ed-858f-4315-827f-bf225d9fcd9a",
|
||||
"hash": "e9966f699879443636897459ac2954818eab9e65e8f1db3bd8b468991f5f74cd"
|
||||
},
|
||||
{
|
||||
"id": "e8ff7891-4dc6-48e4-b5b5-2995b5d9d641",
|
||||
"hash": "0376fba656b2081d8a126431e9d8d5b91f54b9887091bbe33edec2bad72845da"
|
||||
},
|
||||
{
|
||||
"id": "beef1abb-ad83-442c-9aaa-9053ecef1800",
|
||||
"hash": "51e98809cfbdc9315c79d81a74108ebfda9a5f82677f282cf8e92d7c24041284"
|
||||
},
|
||||
{
|
||||
"id": "94ba0891-8dc6-4274-856e-a60207ae11ef",
|
||||
"hash": "15d505ef1e2d62d6bc80cbc783cc68d0629e2d458a4dc50e7fa42516fdec29d4"
|
||||
},
|
||||
{
|
||||
"id": "a810f543-6f89-4a1c-b235-43702b80558a",
|
||||
"hash": "4317a857f8682fc0be44106c3708135ab083aa12f48352439221e6522e5447d1"
|
||||
}
|
||||
],
|
||||
"prior_history_and_Fintech_table_preserved": true
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# Classificação multidimensional — disponibilização DOC01
|
||||
|
||||
Entregue no destino `https://portal-investidor.test` a candidata `classificacao-multidimensional-QA-64ab05e20b95`, após autorização expressa da Tempo nesta conversa. O pacote DOC01 aprovado permanece imutável: SHA-256 `334d8ef2e47848a3c30cf526ae4d394004f112288cdddbcf635f06a1be1e0bc6`.
|
||||
|
||||
Foram substituídas 14 fontes e acrescentadas três, com os 174 ficheiros da compilação correspondente conferidos por hash. O preflight confirmou os hashes anteriores, as três ausências e os 1.899 ficheiros protegidos da preparação. Não foram executadas migrations, importações, publicações editoriais, mudanças de flags, permissões ou associações reais. As provas funcionais QA aceites foram reutilizadas; não se repetiu a auditoria.
|
||||
|
||||
## Recuperação preparada junto da execução
|
||||
|
||||
O backup fresco foi restaurado exclusivamente na base isolada `classification_before_20261015_202406_test`, porta 55441, separado do destino `investemoz`, porta 5432. Foram conferidos os conteúdos de 295 tabelas, 31 sequências e 2.221 ficheiros copiados/restaurados, incluindo fontes/build, configuração, ficheiros privados geridos e 29 documentos. Não havia documentos indisponíveis nessa fotografia. Os dumps, configuração e cópias integrais permanecem apenas no armazenamento privado local; não integram o anexo de revisão.
|
||||
|
||||
Hashes do backup: dump `7e7bd1b582d25d446dbfce8b4fbb399602caf0b8d4dc503a21e9515f63b57aaf`; arquivo de ficheiros `1232b8cf3a0d32f97d7231f6b5504362cbd2b3b24bc0cd13bc82728a02b39629`. O recibo `FRESH-BACKUP.json` identifica a localização privada para recuperação.
|
||||
|
||||
O clone de fontes e build restaurados arrancou pelo kernel Laravel e respondeu com HTTP 200 a `/up`, `/login` e `/oportunidades`, com conexão ao clone protegida contra escrita, cache/sessões em memória e conectores externos desabilitados apenas no clone. Esta prova é de kernel/contrato/renderização; não constitui ensaio de um segundo servidor TLS ou de workers. Uma primeira tentativa operacional foi interrompida pela guarda porque o valor de sessão de leitura exclusiva não estava ativo; a tentativa válida aplicou explicitamente essa proteção na conexão isolada, sem enfraquecer a guarda ou alterar o destino.
|
||||
|
||||
## Troca e conferência operacional
|
||||
|
||||
A troca decorreu em manutenção, com saída antes da consulta pela interface. Foram executados exclusivamente `config:clear`, `route:clear` e `view:clear`. O destino não usava cache de configuração ou rotas nem pré-compilação de vistas na sua entrega anterior, pelo que esses modos não foram introduzidos. A cache de dados usa a base de dados; os seus registos ficaram idênticos nas fotografias tomadas antes e depois da troca e dos comandos. Não foi executado `optimize:clear` nem `cache:clear`.
|
||||
|
||||
As duas rotas de classificação constam do código em execução. A conferência HTTP do destino validou o certificado e nome TLS, `/up`, catálogo público sem sessão e quatro assets de entrada servidos com os hashes locais. As mesmas seis oportunidades públicas e a primeira página conservaram identificadores, títulos e slugs. Os novos filtros foram observados no navegador do destino, sem gravar nem classificar anúncios. A captura `ATIVO-CATALOGO.jpg` mostra essa apresentação; observar o ativo não repete a aceitação funcional QA.
|
||||
|
||||
Na comparação de leitura imediatamente após a troca com o restauro fresco, todas as tabelas de negócio ficaram idênticas. Na conferência final, os registos de negócio e todo o histórico anterior permanecem preservados; foram acrescentados apenas dois eventos normais de auditoria das tentativas GET recusadas com 403, identificados em `PRESERVACAO-FINAL.json`. Esses eventos não foram apagados nem tratados como alteração de associações reais. Sessões, cache, locks e filas são identificadas separadamente como tabelas técnicas; a preservação da cache durante a troca tem prova própria. Foram conferidos os 17 hashes entregues, os 174 hashes do build, sete ficheiros de configuração protegidos, os outros 1.827 ficheiros protegidos não abrangidos pela troca, 281 ficheiros privados/públicos geridos e os 29 documentos originais. A instalação 190000 já existente e as flags de B e do leitor permaneceram iguais. Não foi alterado COUNTRY02, o conteúdo publicado ou o histórico.
|
||||
|
||||
## Reversão após utilização
|
||||
|
||||
O mapa `MAPA-REVERSAO-EXECUCAO.json` distingue cada fonte. Após gravação dos campos novos, repor **13 fontes anteriores e o contrato compatível**, com SHA-256 `6023295d57063b6054662515eb837930ac4bffa642744433499dd0b1912f5107`; não repor cegamente os 14 originais. Esse contrato conserva `enterprise_size`, as relações e os dados já gravados, mantendo decisões, publicação e auditoria.
|
||||
|
||||
Restaurar o build anterior completo a partir do backup fresco, repor as referências antes de retirar por hash as três fontes novas e limpar apenas configuração, rotas e vistas. Os assets anteriores foram mantidos. Não restaurar uma fotografia antiga da base sobre operações posteriores, apagar JSON, renumerar registos ou executar down de migrations. A ação preparada `revert-compatible.py --candidate=classificacao-multidimensional-QA-64ab05e20b95` recusa ficheiros entretanto alterados e preserva os dados; não foi executada. Mantém-se a prova QA anterior de compatibilidade, sem novo ensaio funcional de reversão no ativo.
|
||||
|
||||
## Limites mantidos
|
||||
|
||||
O incremento cobre o cadastro canónico Opportunity e `/oportunidades`. Continuam abertos na mesma matriz: anúncios UUID de `/negocios`, ficha operacional integral dos parques, referências económicas em falta, similaridade/consolidação de duplicados e regulação Fintech específica completa. A entrega parcial não encerra essas cláusulas nem reabre B, COUNTRY02 ou as aceitações anteriores.
|
||||
|
||||
As restrições de âmbito, preservação e ausência de migrations/dados sintéticos derivam da autorização expressa da Tempo. Papéis, MFA e independência mantêm as políticas aprovadas. Guardas de hash, manutenção e contrato compatível são escolhas técnicas de execução, sem novos papéis ou exigências organizacionais.
|
||||
|
||||
## Conferência autenticada do editor
|
||||
|
||||
Editor no ativo: não demonstrado nesta conferência. O utilizador informou não ter acesso à conta de Promotora interna Aurora Chachuaio. A sessão efetiva Osmane Nala, conta 2, recebeu 403 em GET /minhas-oportunidades/create; não existe elevação operacional ativa. Os papéis Promotor/Validador dessa conta permanecem atribuídos; as funções de autorização v1 conferem exatamente com a versão anterior à entrega. Existem seis oportunidades legadas e nenhuma do workflow de promotor no ativo. A mensagem 403 genérica não expõe o motivo; o diagnóstico fica registado, sem alterar permissões, credenciais ou acrescentar uma correção fora do pacote autorizado. Mantêm-se as provas funcionais QA aceites do editor.
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"operational_document_revision": "OPS-DOC01",
|
||||
"outer_entries": 29,
|
||||
"all_entry_hashes_verified": true,
|
||||
"matrix_reconstructed_previous_hash_matches": true,
|
||||
"other_raw_matrix_rows_preserved": 3394,
|
||||
"code_build_or_QA_changed": false,
|
||||
"documents": {
|
||||
"RELATORIO-ENTREGA.md": "bc24202bdc8f4e2b26d33b78466426fc48ff4a258224522ba84e09fe29718417",
|
||||
"RECIBO-FINAL.json": "e4de219d0417b9f45fe9a565e4cee73d669a428924745d4a9b094bcda9b1dcdf",
|
||||
"MAPA-REVERSAO-EXECUCAO.json": "354bef29bc68d55e27dcede121b3b652a519b2aa6db692380a6639da99496d90",
|
||||
"ATIVO-CATALOGO.jpg": "a2ca71cbdcf69f73af5a031f30609a7087c6cab7c93dbbb50aab308672e47157"
|
||||
},
|
||||
"zip": {
|
||||
"name": "classificacao-multidimensional-disponibilizado-20261015-64ab05e20b95-doc01.zip",
|
||||
"bytes": 1969142,
|
||||
"sha256": "6e8bfa5a39788368f23f816a215e6ed7037c6b23b0e64cea0950370a2ee76d3c",
|
||||
"entries": 29,
|
||||
"all_entries_verified": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
ini_set('zend.exception_ignore_args','1');set_exception_handler(function(Throwable $e){fwrite(STDERR,'Account scope lookup stopped: '.$e::class.' line '.$e->getLine().PHP_EOL);exit(1);});
|
||||
$root=dirname(__DIR__,2);require $root.'/vendor/autoload.php';$app=require $root.'/bootstrap/app.php';(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
|
||||
$c=config('database.connections.'.config('database.default'));if($c['database']!=='investemoz'||(int)$c['port']!==5432||!in_array($c['host'],['127.0.0.1','localhost'])||!empty($c['url']))throw new RuntimeException('Active identity');
|
||||
$db=new PDO('pgsql:host='.$c['host'].';port=5432;dbname=investemoz',$c['username'],$c['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);$db->exec('BEGIN READ ONLY');
|
||||
try{
|
||||
$pair=$db->query('SELECT p.id,p.first_user_id,u.name AS first_name,p.second_user_id,v.name AS second_name FROM portal_superuser_pair p LEFT JOIN users u ON u.id=p.first_user_id LEFT JOIN users v ON v.id=p.second_user_id')->fetchAll(PDO::FETCH_ASSOC);
|
||||
$roles=$db->query("SELECT r.user_id,u.name,r.role,r.organization_id,r.opportunity_types,r.source,u.email_verified_at IS NOT NULL AS verified FROM portal_role_assignments r JOIN users u ON u.id=r.user_id WHERE r.revoked_at IS NULL AND r.starts_at <= CURRENT_TIMESTAMP AND (r.expires_at IS NULL OR r.expires_at > CURRENT_TIMESTAMP) ORDER BY r.user_id,r.role")->fetchAll(PDO::FETCH_ASSOC);
|
||||
$owners=$db->query('SELECT o.owner_user_id,u.name,COUNT(*) AS records FROM opportunities o LEFT JOIN users u ON u.id=o.owner_user_id WHERE o.deleted_at IS NULL GROUP BY o.owner_user_id,u.name ORDER BY o.owner_user_id NULLS FIRST')->fetchAll(PDO::FETCH_ASSOC);
|
||||
$osm=$db->query("SELECT id,name,email_verified_at IS NOT NULL AS verified FROM users WHERE name ILIKE '%Osmane%Nala%' ORDER BY id")->fetchAll(PDO::FETCH_ASSOC);
|
||||
$denials=$db->query("SELECT actor_user_id,action,occurred_at,after_data->>'path' AS path,after_data->>'method' AS method,after_data->>'status' AS status FROM audit_events WHERE source_system='portal-profiles-v1' AND action='request_denied' AND after_data->>'path'='minhas-oportunidades/create' ORDER BY occurred_at DESC,id DESC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC);
|
||||
$elevations=$db->query("SELECT subject_user_id,COUNT(*) AS current_approved_elevations FROM portal_security_approvals WHERE kind='elevation' AND approved_by IS NOT NULL AND consumed_at IS NULL AND expires_at>CURRENT_TIMESTAMP GROUP BY subject_user_id ORDER BY subject_user_id")->fetchAll(PDO::FETCH_ASSOC);
|
||||
$proof=['recent_create_denials'=>$denials,'current_approved_elevations'=>$elevations,'at' =>gmdate('c'),'target'=>['database'=>'investemoz','port'=>5432],'read_only'=>true,'osm'=> $osm,'superuser_pair'=>$pair,'current_operational_assignments'=>$roles,'opportunity_owners'=>$owners,'permission_changes'=>0];
|
||||
file_put_contents(__DIR__.'/CONTAS-AMBITO-READONLY.json',json_encode($proof,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR).PHP_EOL);echo json_encode($proof,JSON_UNESCAPED_UNICODE).PHP_EOL;
|
||||
}finally{$db->exec('ROLLBACK');}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
ini_set('zend.exception_ignore_args','1');
|
||||
set_exception_handler(function(Throwable $e){fwrite(STDERR,'Restored clone boot stopped: '.$e::class.' line '.$e->getLine().PHP_EOL);exit(1);});
|
||||
$root=dirname(__DIR__,2);$p=json_decode(file_get_contents(__DIR__.'/FRESH-BACKUP.json'),true,512,JSON_THROW_ON_ERROR);
|
||||
if(!$p['restore_verified']||!$p['files_verified']||$p['candidate']!=='classificacao-multidimensional-QA-64ab05e20b95')throw new RuntimeException('Exact restored backup required');
|
||||
$clone=$p['private_directory'].'/application-boot-2';
|
||||
if(is_dir($clone)||!mkdir($clone,0700,true))throw new RuntimeException('Fresh private clone required');
|
||||
$backup=$p['private_directory'].'/files';
|
||||
foreach(['app','config','routes','resources','database','bootstrap','public/build']as$folder){
|
||||
$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($backup.'/'.$folder,FilesystemIterator::SKIP_DOTS));
|
||||
foreach($it as$f)if($f->isFile()){$rel=str_replace('\\','/',substr($f->getPathname(),strlen($backup)+1));$dest=$clone.'/'.$rel;if(!is_dir(dirname($dest)))mkdir(dirname($dest),0700,true);if(!copy($f->getPathname(),$dest)||hash_file('sha256',$dest)!==hash_file('sha256',$f->getPathname()))throw new RuntimeException('Restored source copy mismatch');}
|
||||
}
|
||||
foreach(['.env','artisan','composer.json','composer.lock']as$n)if(!copy($backup.'/'.$n,$clone.'/'.$n))throw new RuntimeException('Runtime file copy');
|
||||
foreach(['storage/framework/views','storage/framework/cache/data','storage/framework/sessions','storage/logs','storage/app/private','storage/app/public','bootstrap/cache']as$d)if(!is_dir($clone.'/'.$d))mkdir($clone.'/'.$d,0700,true);
|
||||
$loader=require $root.'/vendor/autoload.php';$loader->setPsr4('App\\',$clone.'/app');
|
||||
$map=[];foreach($loader->getClassMap()as$class=>$file)if(str_starts_with($class,'App\\')){$path=$clone.'/app/'.str_replace('\\','/',substr($class,4)).'.php';if(is_file($path))$map[$class]=$path;}$loader->addClassMap($map);
|
||||
$values=Dotenv\Dotenv::parse(file_get_contents($clone.'/.env'));
|
||||
foreach(['APP_BASE_PATH'=>$clone,'APP_ENV'=>'testing','APP_URL'=>'https://classification-restore.test','DB_CONNECTION'=>'pgsql','DB_HOST'=>'127.0.0.1','DB_PORT'=>'55441','DB_DATABASE'=>$p['restore_target']['database'],'DB_USERNAME'=>'postgres','DB_PASSWORD'=>'','DB_URL'=>'','APP_CONFIG_CACHE'=>$clone.'/bootstrap/cache/config.php','APP_ROUTES_CACHE'=>$clone.'/bootstrap/cache/routes-v7.php','VIEW_COMPILED_PATH'=>$clone.'/storage/framework/views','SESSION_DRIVER'=>'array','CACHE_STORE'=>'array','QUEUE_CONNECTION'=>'sync','MAIL_MAILER'=>'log','INERTIA_SSR_ENABLED'=>'false','SUITECRM_ENABLED'=>'false','INVESTMOZ_AI_ENABLED'=>'false','PORTAL_NOTIFICATIONS_ENABLED'=>'false','PGOPTIONS'=>'-c default_transaction_read_only=on']as$k=>$v)$values[$k]=$v;
|
||||
foreach($values as$k=>$v)if($v!==null){putenv($k.'='.$v);$_ENV[$k]=$_SERVER[$k]=$v;}
|
||||
$app=require $clone.'/bootstrap/app.php';$app->usePublicPath($clone.'/public');$app->useStoragePath($clone.'/storage');
|
||||
(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
|
||||
$c=config('database.connections.'.config('database.default'));
|
||||
if($c['host']!=='127.0.0.1'||(int)$c['port']!==55441||$c['database']!==$p['restore_target']['database']||!preg_match('/^classification_before_\d{8}_\d{6}_test$/D',$c['database'])||!empty($c['url']))throw new RuntimeException('Isolated restored clone only');
|
||||
$app->afterBootstrapping(Illuminate\Foundation\Bootstrap\RegisterProviders::class,function(){
|
||||
$c=config('database.connections.'.config('database.default'));if($c['host']!=='127.0.0.1'||(int)$c['port']!==55441||!preg_match('/^classification_before_\d{8}_\d{6}_test$/D',$c['database']))throw new RuntimeException('Read-only setup must target restored clone');
|
||||
config(['session.driver'=>'array','cache.default'=>'array','inertia.ssr.enabled'=>false,'suitecrm.enabled'=>false,'investmoz_ai.enabled'=>false,'portal.notifications_enabled'=>false]);
|
||||
Illuminate\Support\Facades\DB::connection()->statement('SET default_transaction_read_only = on');
|
||||
});
|
||||
$kernel=$app->make(Illuminate\Contracts\Http\Kernel::class);$kernel->bootstrap();
|
||||
config(['inertia.ssr.enabled'=>false,'suitecrm.enabled'=>false,'investmoz_ai.enabled'=>false,'portal.notifications_enabled'=>false]);
|
||||
$db=Illuminate\Support\Facades\DB::connection();if($db->selectOne('SHOW default_transaction_read_only')->default_transaction_read_only!=='on')throw new RuntimeException('Read-only clone required');
|
||||
$actual=(array)$db->selectOne('SELECT current_database() AS database,inet_server_port() AS port');
|
||||
if($actual['database']!==$p['restore_target']['database']||(int)$actual['port']!==55441)throw new RuntimeException('Actual clone identity');
|
||||
$db->beginTransaction();$db->statement('SET TRANSACTION READ ONLY');$routes=[];
|
||||
try{
|
||||
foreach(['/up','/login','/oportunidades']as$path){$request=Illuminate\Http\Request::create('https://classification-restore.test'.$path,'GET');$response=$kernel->handle($request);$body=$response->getContent();file_put_contents($clone.'/response-'.str_replace('/','_',trim($path,'/')).'.html',$body);if($response->getStatusCode()!==200)throw new RuntimeException('Restored clone route failed');$routes[]=['method'=>'GET','path'=>$path,'status'=>200,'body_bytes'=>strlen($body),'body_sha256'=>hash('sha256',$body)];$kernel->terminate($request,$response);}
|
||||
$origin=(new ReflectionClass(App\Models\Opportunity::class))->getFileName();if(!str_starts_with(str_replace('\\','/',$origin),$clone.'/app/'))throw new RuntimeException('Application source must be the private restored clone');
|
||||
$proof=['at'=>gmdate('c'),'candidate'=>$p['candidate'],'restore_target'=>$actual,'application_base_is_private_clone'=>true,'source_and_build_from_fresh_backup'=>true,'shared_vendor_dependencies_unchanged'=>true,'DB_read_only'=>true,'kernel_bootstrap'=>'passed','HTTP_kernel_routes'=>$routes,'view_rendering_and_Vite_manifest'=>'passed','session_and_cache'=>'array in clone only','external_connectors_disabled'=>true,'database_changes'=>0,'active_changes'=>0,'accepted_QA_tests_repeated'=>false,'real_web_server_TLS_worker_boot_test'=>false];
|
||||
if(is_file(__DIR__.'/ARRANQUE-CLONE-RESTAURADO.json'))throw new RuntimeException('Preserve clone proof');file_put_contents(__DIR__.'/ARRANQUE-CLONE-RESTAURADO.json',json_encode($proof,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR).PHP_EOL);echo json_encode($proof,JSON_UNESCAPED_UNICODE).PHP_EOL;
|
||||
}finally{$db->rollBack();}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
ini_set('zend.exception_ignore_args','1');
|
||||
set_exception_handler(function(Throwable $e){fwrite(STDERR,'Data cache verification stopped: '.$e::class.' line '.$e->getLine().PHP_EOL);exit(1);});
|
||||
$root=dirname(__DIR__,2);$phase=$argv[1]??'';
|
||||
if(!in_array($phase,['before','after'],true)||!is_file($root.'/storage/framework/down'))throw new RuntimeException('Maintenance snapshot required');
|
||||
require $root.'/vendor/autoload.php';$app=require $root.'/bootstrap/app.php';(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
|
||||
$store=config('cache.default');$driver=config('cache.stores.'.$store.'.driver');$snapshot=['store'=>$store,'driver'=>$driver];
|
||||
if($driver==='database'){
|
||||
$connection=config('cache.stores.'.$store.'.connection')?:config('database.default');$c=config('database.connections.'.$connection);
|
||||
if($c['driver']!=='pgsql'||$c['database']!=='investemoz'||(int)$c['port']!==5432||!in_array($c['host'],['127.0.0.1','localhost'])||!empty($c['url']))throw new RuntimeException('Expected local data cache connection');
|
||||
$db=new PDO('pgsql:host='.$c['host'].';port=5432;dbname=investemoz',$c['username'],$c['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);$db->exec('BEGIN READ ONLY');
|
||||
$table=config('cache.stores.'.$store.'.table');if(!preg_match('/^[a-z_][a-z0-9_]*$/D',$table))throw new RuntimeException('Cache table guard');
|
||||
$rows=$db->query('SELECT row_to_json(t)::text FROM "'.$table.'" t ORDER BY row_to_json(t)::text')->fetchAll(PDO::FETCH_COLUMN);$snapshot['rows']=count($rows);$snapshot['sha256']=hash('sha256',implode("\n",$rows));$db->exec('ROLLBACK');
|
||||
}elseif($driver==='file'){
|
||||
$path=realpath(config('cache.stores.'.$store.'.path'));if(!$path||str_replace('\\','/',$path)!==$root.'/storage/framework/cache/data')throw new RuntimeException('Expected data cache path');$hashes=[];$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path,FilesystemIterator::SKIP_DOTS));foreach($it as$f)if($f->isFile())$hashes[str_replace('\\','/',substr($f->getPathname(),strlen($path)+1))]=hash_file('sha256',$f->getPathname());ksort($hashes);$snapshot['files']=$hashes;$snapshot['file_count']=count($hashes);
|
||||
}else{throw new RuntimeException('Cache backend requires targeted reconciliation');}
|
||||
$file=__DIR__.'/CACHE-DADOS-'.strtoupper($phase).'.json';if(is_file($file))throw new RuntimeException('Preserve cache snapshot');
|
||||
if($phase==='after'){$before=json_decode(file_get_contents(__DIR__.'/CACHE-DADOS-BEFORE.json'),true,512,JSON_THROW_ON_ERROR);if($snapshot!==$before)throw new RuntimeException('Data cache changed; do not claim preservation');}
|
||||
file_put_contents($file,json_encode($snapshot,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR).PHP_EOL);echo json_encode(['phase'=>$phase,'store'=>$store,'unchanged'=>$phase==='after','entries'=>$snapshot['rows']??$snapshot['file_count']]).PHP_EOL;
|
||||
@@ -0,0 +1,46 @@
|
||||
"""Normalize the operational narrative before attaching it; preserve prior artifacts."""
|
||||
from pathlib import Path
|
||||
import json,hashlib,csv,io,zipfile,datetime
|
||||
root=Path(__file__).resolve().parents[2];out=Path(__file__).resolve().parent
|
||||
sha=lambda b:hashlib.sha256(b).hexdigest()
|
||||
encode=lambda v:(json.dumps(v,ensure_ascii=False,indent=2)+'\n').encode('utf-8')
|
||||
archive=out/'historico/OPS-DOC00';archive.mkdir(parents=True,exist_ok=False)
|
||||
for name in ['INTERFACE-OPERACIONAL.json','RELATORIO-ENTREGA.md','RECIBO-FINAL.json','INTEGRIDADE-PROVAS.json','AUTORIZACAO-TEMPO.json','ATUALIZACAO-MESMA-MATRIZ.json']:(archive/name).write_bytes((out/name).read_bytes())
|
||||
ui=json.loads((out/'INTERFACE-OPERACIONAL.json').read_text('utf-8'));bad=ui['editor_observation_summary']
|
||||
summary='Editor no ativo: não demonstrado nesta conferência. O utilizador informou não ter acesso à conta de Promotora interna Aurora Chachuaio. A sessão efetiva Osmane Nala, conta 2, recebeu 403 em GET /minhas-oportunidades/create; não existe elevação operacional ativa. Os papéis Promotor/Validador dessa conta permanecem atribuídos; as funções de autorização v1 conferem exatamente com a versão anterior à entrega. Existem seis oportunidades legadas e nenhuma do workflow de promotor no ativo. A mensagem 403 genérica não expõe o motivo; o diagnóstico fica registado, sem alterar permissões, credenciais ou acrescentar uma correção fora do pacote autorizado. Mantêm-se as provas funcionais QA aceites do editor.'
|
||||
ui.update(editor_observation_summary=summary,user_reply='Não tenho acesso à conta de Aurora');(out/'INTERFACE-OPERACIONAL.json').write_bytes(encode(ui))
|
||||
report=(out/'RELATORIO-ENTREGA.md').read_text('utf-8');assert report.count(bad)==1;report=report.replace(bad,summary)
|
||||
old='Na comparação de leitura com o restauro fresco, todas as tabelas de negócio ficaram idênticas.'
|
||||
new='Na comparação de leitura imediatamente após a troca com o restauro fresco, todas as tabelas de negócio ficaram idênticas. Na conferência final, os registos de negócio e todo o histórico anterior permanecem preservados; foram acrescentados apenas dois eventos normais de auditoria das tentativas GET recusadas com 403, identificados em `PRESERVACAO-FINAL.json`. Esses eventos não foram apagados nem tratados como alteração de associações reais.'
|
||||
assert report.count(old)==1;report=report.replace(old,new);(out/'RELATORIO-ENTREGA.md').write_bytes(report.encode('utf-8'))
|
||||
a=json.loads((out/'AUTORIZACAO-TEMPO.json').read_text('utf-8'));a['user_statement']='A Tempo autoriza a disponibilizaçaõ';(out/'AUTORIZACAO-TEMPO.json').write_bytes(encode(a))
|
||||
matrix=root/'docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv';b=matrix.read_bytes();assert b.count(bad.encode())==8;matrix.write_bytes(b.replace(bad.encode(),summary.encode()))
|
||||
backlog=root/'docs/investmoz/v2/auditoria-portal/backlog.md';b=backlog.read_bytes();assert b.count(bad.encode())==1;backlog.write_bytes(b.replace(bad.encode(),summary.encode()))
|
||||
mp=json.loads((out/'ATUALIZACAO-MESMA-MATRIZ.json').read_text('utf-8'));mp['after_sha256']=sha(matrix.read_bytes());(out/'ATUALIZACAO-MESMA-MATRIZ.json').write_bytes(encode(mp))
|
||||
# Reconstruct the exact previous matrix to independently confirm all other bytes.
|
||||
csv.field_size_limit(10000000);text=matrix.read_bytes().decode('utf-8');lines=text.splitlines(keepends=True);reader=csv.reader(io.StringIO(text,newline=''));start=0;parts=[];cols=None;count=0
|
||||
oldrows=json.loads((out/'MATRIZ-ANTES.json').read_text('utf-8'));olds={next(iter(v.values())):v for v in oldrows}
|
||||
for values in reader:
|
||||
end=reader.line_num;raw=''.join(lines[start:end]);start=end
|
||||
if cols is None:cols=values.copy();cols[0]=cols[0].lstrip('\ufeff');parts.append(raw);continue
|
||||
count+=1
|
||||
if values[0] in olds:
|
||||
oldrow=olds[values[0]];now=dict(zip(cols,values));changed=[k for k in cols if oldrow[k]!=now[k]]
|
||||
assert set(changed)=={'Fundamento do estado atual','Evidências atuais verificadas','Critérios restantes atuais','Tipo de trabalho atual'}
|
||||
tmp=io.StringIO(newline='');csv.writer(tmp,lineterminator='\n').writerow([oldrow[c] for c in cols]);parts.append(tmp.getvalue())
|
||||
else:parts.append(raw)
|
||||
assert count==3402 and sha(''.join(parts).encode('utf-8'))==mp['before_sha256']
|
||||
r=json.loads((out/'RECIBO-FINAL.json').read_text('utf-8'));r['editor_observation_summary']=summary;r['matrix']=mp
|
||||
inventory=json.loads((out/'INTEGRIDADE-PROVAS.json').read_text('utf-8'));oldzip=root/'outputs'/r['zip']['name'];assert sha(oldzip.read_bytes())==r['zip']['sha256']
|
||||
with zipfile.ZipFile(oldzip) as z:payload={n:(z.read(n) if n.startswith('candidata/') else (out/n).read_bytes()) for n in inventory['files']}
|
||||
inventory['files']={n:{'sha256':sha(data),'bytes':len(data)} for n,data in sorted(payload.items())};inventory['operational_document_revision']='OPS-DOC01';inventory_bytes=encode(inventory);(out/'INTEGRIDADE-PROVAS.json').write_bytes(inventory_bytes)
|
||||
newzip=oldzip.with_name(oldzip.stem+'-doc01.zip');assert not newzip.exists()
|
||||
with zipfile.ZipFile(newzip,'w',zipfile.ZIP_DEFLATED,compresslevel=9) as z:
|
||||
for n,data in sorted(payload.items()):z.writestr(n,data)
|
||||
z.writestr('INTEGRIDADE-PROVAS.json',inventory_bytes)
|
||||
with zipfile.ZipFile(newzip) as z:
|
||||
assert z.testzip() is None and len(z.namelist())==len(payload)+1
|
||||
for n,data in payload.items():assert z.read(n)==data
|
||||
r['artifact_hashes']={n:sha(data) for n,data in payload.items() if not n.startswith('candidata/')};r['inventory_sha256']=sha(inventory_bytes);r['zip']={'name':newzip.name,'bytes':newzip.stat().st_size,'sha256':sha(newzip.read_bytes()),'entries':len(payload)+1,'all_entries_verified':True};r['operational_document_revision']='OPS-DOC01';r['operational_text_revised_at']=datetime.datetime.now(datetime.timezone.utc).isoformat();r['previous_operational_zip_preserved']={'name':oldzip.name,'sha256':sha(oldzip.read_bytes())};(out/'RECIBO-FINAL.json').write_bytes(encode(r))
|
||||
proof={'operational_document_revision':'OPS-DOC01','outer_entries':len(payload)+1,'all_entry_hashes_verified':True,'matrix_reconstructed_previous_hash_matches':True,'other_raw_matrix_rows_preserved':3394,'code_build_or_QA_changed':False,'documents':{n:sha((out/n).read_bytes()) for n in ['RELATORIO-ENTREGA.md','RECIBO-FINAL.json','MAPA-REVERSAO-EXECUCAO.json','ATIVO-CATALOGO.jpg']},'zip':r['zip']}
|
||||
(out/'VERIFICACAO-PACOTE-FINAL.json').write_bytes(encode(proof));print(json.dumps(proof,ensure_ascii=True))
|
||||
@@ -0,0 +1,83 @@
|
||||
from pathlib import Path
|
||||
import hashlib,json,zipfile,subprocess,datetime,os,shutil
|
||||
root=Path(__file__).resolve().parents[2];out=Path(__file__).resolve().parent
|
||||
release=root/'outputs/investmoz-classificacao-multidimensional-QA-20261015'
|
||||
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
m=json.loads((release/'MANIFESTO-ENTREGA.json').read_text('utf-8'))
|
||||
r=json.loads((release/'RECIBO-INTEGRIDADE.json').read_text('utf-8'))
|
||||
b=json.loads((out/'FRESH-BACKUP.json').read_text('utf-8'))
|
||||
c=json.loads((out/'ARRANQUE-CLONE-RESTAURADO.json').read_text('utf-8'))
|
||||
p=json.loads((out/'PREFLIGHT.json').read_text('utf-8'))
|
||||
assert all(x['candidate']==m['candidate'] for x in [r,b,c,p])
|
||||
assert b['restore_verified'] and b['files_verified'] and c['kernel_bootstrap']=='passed' and c['DB_read_only']
|
||||
assert b['target']['database']=='investemoz' and int(b['target']['port'])==5432
|
||||
assert (datetime.datetime.now(datetime.timezone.utc)-datetime.datetime.fromisoformat(b['at'])).total_seconds()<3600
|
||||
assert not (root/'storage/framework/down').exists() and not (out/'FONTES-COMPILACAO.json').exists()
|
||||
backup=Path(b['private_directory']);private=json.loads((backup/'backup-proof-private.json').read_text('utf-8'))
|
||||
assert sha(Path(private['dump_path']))==private['sha256'] and sha(Path(private['files_path']))==private['files_sha256']
|
||||
for s in m['sources']:
|
||||
f=root/s['path'];assert (sha(f) if f.is_file() else None)==s['previous_sha256'],s['path']
|
||||
for n,h in p['protected_files'].items():assert sha(root/n)==h,n
|
||||
for n,h in p['previous_build_files'].items():assert sha(root/'public/build'/n)==h,n
|
||||
archive=root/'outputs'/r['zip']['name'];assert sha(archive)==r['zip']['sha256']
|
||||
with zipfile.ZipFile(archive) as z:
|
||||
assert z.testzip() is None
|
||||
payload={x['path']:x for x in m['payload']}
|
||||
stage=backup/'candidate-staging';assert not stage.exists();stage.mkdir()
|
||||
for name in [*['fontes/'+x['path'] for x in m['sources']],*[x for x in payload if x.startswith('build/')],'reversao-compat/app/Services/OpportunityCanonicalContract.php']:
|
||||
data=z.read(name);assert hashlib.sha256(data).hexdigest()==payload[name]['sha256']
|
||||
f=stage/name;f.parent.mkdir(parents=True,exist_ok=True);f.write_bytes(data)
|
||||
build=[x for x in payload if x.startswith('build/')]
|
||||
for n in build:
|
||||
target=root/'public'/n
|
||||
assert not target.exists() or sha(target)==payload[n]['sha256'] or n in ['build/manifest.json','build/fonts-manifest.json'],'Asset collision: '+n
|
||||
php='C:/laragon/bin/php/php-8.5.11-Win32-vs17-x64/php.exe'
|
||||
def command(args,label):
|
||||
run=subprocess.run(args,cwd=root,capture_output=True)
|
||||
(backup/(label+'.log')).write_bytes(run.stdout+run.stderr)
|
||||
if run.returncode:raise RuntimeError('Operational command failed: '+label)
|
||||
def artisan(*args):command([php,'artisan',*args],'-'.join(args).replace(':','-').replace('/','_'))
|
||||
def put(src,dest):
|
||||
dest.parent.mkdir(parents=True,exist_ok=True);temp=dest.with_name(dest.name+'.classification-delivery.tmp');assert not temp.exists()
|
||||
shutil.copy2(src,temp);assert sha(src)==sha(temp);os.replace(temp,dest)
|
||||
receipt={'at':datetime.datetime.now(datetime.timezone.utc).isoformat(),'candidate':m['candidate'],'document_revision':'DOC01','authorization':p['authorization'],'maintenance_started':False,'maintenance_ended':False,'sources':{},'added_build_files':[],'build_files':{},'migrations':0,'flags_changed':0,'business_writes':0,'synthetic_data_imported':False,'accepted_QA_repeated':False,'backup_restore_verified':True}
|
||||
try:
|
||||
artisan('down','--retry=60');receipt['maintenance_started']=True
|
||||
assert (root/'storage/framework/down').exists()
|
||||
command([php,str(out/'cache-snapshot.php'),'before'],'cache-data-before')
|
||||
for s in m['sources']:
|
||||
put(stage/'fontes'/s['path'],root/s['path']);assert sha(root/s['path'])==s['candidate_sha256'];receipt['sources'][s['path']]=s['candidate_sha256']
|
||||
for n in sorted(build,key=lambda x:x=='build/manifest.json'):
|
||||
dest=root/'public'/n
|
||||
if not dest.exists():receipt['added_build_files'].append(n)
|
||||
put(stage/n,dest);assert sha(dest)==payload[n]['sha256'];receipt['build_files'][n]=payload[n]['sha256']
|
||||
for n,h in p['protected_files'].items():assert sha(root/n)==h,n
|
||||
for n in ['config:clear','route:clear','view:clear']:artisan(n)
|
||||
# Destination preflight has no config/route caches or view precompilation to rebuild.
|
||||
assert not b['cache_state']['configuration_cached'] and not b['cache_state']['routes_cached'] and not b['cache_state']['views_precompiled']
|
||||
receipt['cache_commands']=['config:clear','route:clear','view:clear']
|
||||
command([php,str(out/'cache-snapshot.php'),'after'],'cache-data-after');receipt['data_cache_unchanged_during_switch']=True
|
||||
command([php,'artisan','route:list','--json','--path=minhas-oportunidades'],'routes-after-switch')
|
||||
routes=json.loads((backup/'routes-after-switch.log').read_text('utf-8'))
|
||||
assert any(x['uri']=='minhas-oportunidades/{id}/classification' and x['method']=='GET|HEAD' for x in routes)
|
||||
assert any(x['uri']=='minhas-oportunidades/{id}/classification/review' and x['method']=='POST' for x in routes)
|
||||
artisan('up');receipt['maintenance_ended']=True
|
||||
assert not (root/'storage/framework/down').exists()
|
||||
receipt['result']='17 sources and 174 build files delivered; operational GET confirmation pending'
|
||||
except BaseException:
|
||||
# While maintenance has not ended, new fields cannot have been used by the web UI.
|
||||
# After up, retain compatibility even on recovery, so later operations are never discarded.
|
||||
for s in m['sources']:
|
||||
if s['previous_sha256'] is not None:
|
||||
src=backup/'files'/s['path']
|
||||
if receipt['maintenance_ended'] and s['path']=='app/Services/OpportunityCanonicalContract.php':src=stage/'reversao-compat'/s['path']
|
||||
put(src,root/s['path'])
|
||||
for s in m['sources']:
|
||||
f=root/s['path']
|
||||
if s['previous_sha256'] is None and f.is_file() and sha(f)==s['candidate_sha256']:f.unlink()
|
||||
for n in p['previous_build_files']:put(backup/'files/public/build'/n,root/'public/build'/n)
|
||||
for n in ['config:clear','route:clear','view:clear']:artisan(n)
|
||||
artisan('up');receipt['maintenance_ended']=True;receipt['result']='file switch reverted; database preserved'
|
||||
(out/'TROCA-REVERTIDA.json').write_text(json.dumps(receipt,ensure_ascii=False,indent=2)+'\n','utf-8');raise
|
||||
(out/'FONTES-COMPILACAO.json').write_text(json.dumps(receipt,ensure_ascii=False,indent=2)+'\n','utf-8')
|
||||
print(json.dumps({k:v for k,v in receipt.items() if k not in ['sources','build_files','added_build_files']},ensure_ascii=True))
|
||||
@@ -0,0 +1,65 @@
|
||||
from pathlib import Path
|
||||
import csv,io,json,hashlib,zipfile,datetime,ast
|
||||
root=Path(__file__).resolve().parents[2];out=Path(__file__).resolve().parent
|
||||
release=root/'outputs/investmoz-classificacao-multidimensional-QA-20261015'
|
||||
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
encode=lambda v:json.dumps(v,ensure_ascii=False,indent=2)+'\n'
|
||||
ui=json.loads((out/'INTERFACE-OPERACIONAL.json').read_text('utf-8'))
|
||||
assert ui.get('editor_observation_status') in ['observed','not_observed'],'Resolve or explicitly delimit the operational account handoff first'
|
||||
assert not (out/'RECIBO-FINAL.json').exists(),'Final receipt already exists; preserve history'
|
||||
m=json.loads((release/'MANIFESTO-ENTREGA.json').read_text('utf-8'))
|
||||
r=json.loads((release/'RECIBO-INTEGRIDADE.json').read_text('utf-8'))
|
||||
for s in m['sources']:assert sha(root/s['path'])==s['candidate_sha256']
|
||||
for f in m['payload']:
|
||||
if f['path'].startswith('build/'):assert sha(root/'public'/f['path'])==f['sha256']
|
||||
final=json.loads((out/'PRESERVACAO-FINAL.json').read_text('utf-8'));assert final['business_records_and_prior_history_preserved']
|
||||
delivery=json.loads((out/'FONTES-COMPILACAO.json').read_text('utf-8'))
|
||||
after=json.loads((out/'PRESERVACAO-AFTER.json').read_text('utf-8'))
|
||||
assert delivery['maintenance_ended'] and delivery['data_cache_unchanged_during_switch'] and after['business_tables_identical']
|
||||
assert not (root/'storage/framework/down').exists()
|
||||
report=out/'RELATORIO-ENTREGA.md'
|
||||
report.write_bytes(report.read_bytes()+('\n## Conferência autenticada do editor\n\n'+ui['editor_observation_summary']+'\n').encode('utf-8'))
|
||||
# Update only the same eight partial requirements; preserve every other raw record.
|
||||
ids={'M2-d0c06a75-0158','M2-d0c06a75-0029','RF-CLU-002','RF-CLU-003','RF-COR-003','MASTER-e1169a77-0043','MASTER-e1169a77-0062','OP-9f173ed3-0165'}
|
||||
matrix=root/'docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv'
|
||||
before=matrix.read_bytes();assert sha(matrix)=='77ca8f755dc4f0e31baeb734421bb12007571d60c3dc2da14ccac581725af6bc'
|
||||
text=before.decode('utf-8');lines=text.splitlines(keepends=True);items=[];start=0;csv.field_size_limit(10000000)
|
||||
reader=csv.reader(io.StringIO(text,newline=''))
|
||||
for values in reader:
|
||||
end=reader.line_num;items.append((values,''.join(lines[start:end])));start=end
|
||||
cols=items[0][0].copy();cols[0]=cols[0].lstrip('\ufeff');parts=[items[0][1]];old=[]
|
||||
remaining='Conferência operacional do editor observada sem gravação; ' if ui['editor_observation_status']=='observed' else 'Limitação operacional concreta: '+ui['editor_observation_summary']+'; '
|
||||
for values,raw in items[1:]:
|
||||
if values[0] not in ids:parts.append(raw);continue
|
||||
row=dict(zip(cols,values));old.append(row.copy())
|
||||
row['Fundamento do estado atual']+=' | 15/10/2026 — Tempo autorizou e foi disponibilizada a candidata classificacao-multidimensional-QA-64ab05e20b95 DOC01: 17 fontes/174 build, backup/restauro fresco, cache de dados preservada e reversão compatível. Recorte parcial; restantes limites conservados.'
|
||||
row['Evidências atuais verificadas']+=' | outputs/investmoz-classificacao-ativacao-20261015/RELATORIO-ENTREGA.md; RECIBO-FINAL.json; FRESH-BACKUP.json; ARRANQUE-CLONE-RESTAURADO.json; FONTES-COMPILACAO.json; HTTP-AFTER.json; PRESERVACAO-AFTER.json; INTERFACE-OPERACIONAL.json'
|
||||
prefix='Saldo deste incremento: decisão de disponibilização da candidata e execução operacional; limites do critério integral: '
|
||||
assert row['Critérios restantes atuais'].count(prefix)==1
|
||||
row['Critérios restantes atuais']=row['Critérios restantes atuais'].replace(prefix,'Disponibilização DOC01 executada. '+remaining+'limites do critério integral: ')
|
||||
row['Tipo de trabalho atual']='Incremento parcial disponibilizado; aceitação QA preservada e lacunas integrais delimitadas'
|
||||
tmp=io.StringIO(newline='');csv.writer(tmp,lineterminator='\n').writerow([row[c] for c in cols]);parts.append(tmp.getvalue())
|
||||
assert len(old)==8 and len(items)-1==3402
|
||||
after_bytes=''.join(parts).encode('utf-8');matrix.write_bytes(after_bytes)
|
||||
matrixproof={'before_sha256':hashlib.sha256(before).hexdigest(),'after_sha256':sha(matrix),'rows':3402,'changed_ids':sorted(ids),'other_raw_rows_preserved':3394,'accepted_items_reopened':0,'global_requirements_closed':0,'new_requirements':0,'same_existing_matrix':True}
|
||||
(out/'MATRIZ-ANTES.json').write_text(encode(old),'utf-8');(out/'ATUALIZACAO-MESMA-MATRIZ.json').write_text(encode(matrixproof),'utf-8')
|
||||
note='\n\n## 15/10/2026 — classificação multidimensional DOC01 disponibilizada\n\nA Tempo autorizou expressamente `classificacao-multidimensional-QA-64ab05e20b95`, pacote DOC01. Entregues 17 fontes (14 substituições e três novas) e 174 ficheiros de build, com hashes conferidos. Backup/restauro fresco: 295 tabelas, 31 sequências e 2.221 ficheiros; arranque do clone isolado conferido. Troca em manutenção, apenas config:clear/route:clear/view:clear; cache de dados idêntica durante a operação. HTTP/TLS/assets e seis oportunidades públicas preservados. Comparação de leitura sem alterações nas tabelas de negócio, configuração/flags/permissões, B, COUNTRY02, ficheiros privados, documentos e histórico. Sem migrations, dados QA, classificações reais ou repetição da auditoria aceite.\n\n'+ui['editor_observation_summary']+'\n\nReversão nominal preparada: 13 fontes anteriores mais contrato compatível após utilização, build fresco anterior e retirada por hash das três novas fontes após restauro das referências, sem restaurar base sobre dados posteriores. Provas e recibo: outputs/investmoz-classificacao-ativacao-20261015/. Mesmos oito requisitos recebem a prova operacional parcial; 3.394 outros registos brutos conservados. Continuam abertos /negocios, ficha integral de parques, referências económicas em falta, consolidação de duplicados e enquadramento Fintech completo. A estimativa anterior 1h30–3h era a previsão operacional da entrega, agora executada, não um saldo para repetir.\n'
|
||||
with (root/'docs/investmoz/v2/auditoria-portal/backlog.md').open('a',encoding='utf-8',newline='') as f:f.write(note)
|
||||
for name in ['preflight.py','deliver.py','revert-compatible.py','http-operacional.py']:ast.parse((out/name).read_text('utf-8'))
|
||||
safe_files=['AUTORIZACAO-TEMPO.json','PREFLIGHT.json','FRESH-BACKUP.json','ARRANQUE-CLONE-RESTAURADO.json','PRESERVACAO-BEFORE.json','PRESERVACAO-AFTER.json','PRESERVACAO-FINAL.json','RECUSA-403-REGRA-ANTERIOR.json','ATIVO-403.jpg','FONTES-COMPILACAO.json','CACHE-DADOS-BEFORE.json','CACHE-DADOS-AFTER.json','HTTP-BEFORE.json','HTTP-AFTER.json','INTERFACE-OPERACIONAL.json','MAPA-REVERSAO-EXECUCAO.json','RELATORIO-ENTREGA.md','ATUALIZACAO-MESMA-MATRIZ.json','ATIVO-CATALOGO.jpg','revert-compatible.py','deliver.py','preflight.py','fresh-backup.php','boot-restored-clone.php','cache-snapshot.php','verify-preservation.php','http-operacional.py']
|
||||
if (out/'ATIVO-EDITOR.jpg').exists():safe_files.append('ATIVO-EDITOR.jpg')
|
||||
payload={n:(out/n).read_bytes() for n in safe_files}
|
||||
candidate=root/'outputs'/r['zip']['name'];assert sha(candidate)==r['zip']['sha256']
|
||||
payload['candidata/'+candidate.name]=candidate.read_bytes()
|
||||
inventory={'candidate':m['candidate'],'document_revision':'DOC01','delivery_state':'deployed','files':{n:{'sha256':hashlib.sha256(data).hexdigest(),'bytes':len(data)} for n,data in sorted(payload.items())},'exclusions':'No database dump, backups of private data, credentials, sessions or configuration contents are attached.'}
|
||||
inventory_bytes=encode(inventory).encode('utf-8');(out/'INTEGRIDADE-PROVAS.json').write_bytes(inventory_bytes)
|
||||
zip_path=root/'outputs/classificacao-multidimensional-disponibilizado-20261015-64ab05e20b95.zip';assert not zip_path.exists()
|
||||
with zipfile.ZipFile(zip_path,'w',zipfile.ZIP_DEFLATED,compresslevel=9) as z:
|
||||
for name,data in sorted(payload.items()):z.writestr(name,data)
|
||||
z.writestr('INTEGRIDADE-PROVAS.json',inventory_bytes)
|
||||
with zipfile.ZipFile(zip_path) as z:
|
||||
assert z.testzip() is None and len(z.namelist())==len(payload)+1
|
||||
for name,data in payload.items():assert z.read(name)==data
|
||||
receipt={'at':datetime.datetime.now(datetime.timezone.utc).isoformat(),'candidate':m['candidate'],'document_revision':'DOC01','state':'deployed','target':'https://portal-investidor.test','candidate_zip_sha256':r['zip']['sha256'],'sources':17,'replacements':14,'new_sources':3,'build_files':174,'fresh_backup_restore_verified':True,'clone_kernel_boot_verified':True,'business_tables_compared':295,'business_tables_identical_immediately_after_switch':True,'business_records_and_prior_history_preserved_at_final':True,'expected_access_denial_audit_rows_added':len(final['expected_access_denial_audit_rows_added']),'data_cache_unchanged_during_switch':True,'B_COUNTRY02_permissions_content_history_preserved':True,'migrations_run':0,'real_association_writes':0,'synthetic_data_imported':False,'accepted_QA_repeated':False,'editor_observation_status':ui['editor_observation_status'],'editor_observation_summary':ui['editor_observation_summary'],'compatible_rollback_contract_sha256':m['rollback_compatibility_sha256'],'rollback_executed':False,'matrix':matrixproof,'artifact_hashes':{n:hashlib.sha256(data).hexdigest() for n,data in payload.items() if not n.startswith('candidata/')},'inventory_sha256':hashlib.sha256(inventory_bytes).hexdigest(),'zip':{'name':zip_path.name,'bytes':zip_path.stat().st_size,'sha256':sha(zip_path),'entries':len(payload)+1,'all_entries_verified':True},'remaining_global_gaps':['/negocios','full operational parks record','missing economic references','duplicate consolidation','complete specific Fintech regulation']}
|
||||
(out/'RECIBO-FINAL.json').write_text(encode(receipt),'utf-8')
|
||||
print(json.dumps({'state':receipt['state'],'editor':ui['editor_observation_status'],'zip':receipt['zip'],'receipt_sha256':sha(out/'RECIBO-FINAL.json'),'same_matrix_changed_rows':8,'other_raw_rows_preserved':3394},ensure_ascii=True))
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
ini_set('zend.exception_ignore_args','1');
|
||||
set_exception_handler(function(Throwable $e){fwrite(STDERR,'Fresh destination backup stopped: '.$e::class.' line '.$e->getLine().PHP_EOL);exit(1);});
|
||||
$root=dirname(__DIR__,2);$release=$root.'/outputs/investmoz-classificacao-multidimensional-QA-20261015';$manifest=json_decode(file_get_contents($release.'/MANIFESTO-ENTREGA.json'),true,512,JSON_THROW_ON_ERROR);if(($argv[1]??'')!=='--candidate='.$manifest['candidate'])throw new RuntimeException('Exact candidate argument required');require $root.'/vendor/autoload.php';$app=require $root.'/bootstrap/app.php';
|
||||
(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
|
||||
$c=config('database.connections.'.config('database.default'));
|
||||
if($c['driver']!=='pgsql'||!empty($c['url'])||!in_array($c['host'],['127.0.0.1','localhost'])||(int)$c['port']!==5432||$c['database']!=='investemoz')throw new RuntimeException('Active identity mismatch');
|
||||
$map=['source_operations'=>array_map(fn($p)=>['path'=>$p['path'],'active_before_sha256'=>$p['previous_sha256']],$manifest['sources'])];
|
||||
foreach($map['source_operations']as$op){$p=$root.'/'.$op['path'];if((is_file($p)?hash_file('sha256',$p):null)!==$op['active_before_sha256'])throw new RuntimeException('Source baseline changed; reconcile before delivery');}
|
||||
$cacheState=['configuration_cached'=>$app->configurationIsCached(),'routes_cached'=>is_file($app->getCachedRoutesPath()),'views_precompiled'=>false,'views_mode_evidence'=>'Previous installed delivery used view:clear only; views are compiled on request','configuration_path'=>$app->getCachedConfigPath(),'routes_path'=>$app->getCachedRoutesPath(),'compiled_views_path'=>config('view.compiled'),'data_cache_store'=>config('cache.default'),'data_cache_file_path'=>config('cache.stores.file.path')];
|
||||
$views=str_replace('\\','/',(string)realpath((string)$cacheState['compiled_views_path']));$data=str_replace('\\','/',(string)realpath((string)$cacheState['data_cache_file_path']));
|
||||
if($views!==str_replace('\\','/',$root).'/storage/framework/views'||($data&&($views===$data||str_starts_with($data,$views.'/'))))throw new RuntimeException('Compiled views must be exclusive and separate from data cache');
|
||||
if($cacheState['configuration_cached']||$cacheState['routes_cached']||$cacheState['views_precompiled'])throw new RuntimeException('Unexpected cache mode; reconcile destination before delivery');
|
||||
$stamp=gmdate('Ymd_His');$dir='C:/Users/macbook/.config/investmoz/classification-before-'.$stamp;
|
||||
if(is_dir($dir)||!mkdir($dir,0700,true))throw new RuntimeException('New backup directory required');
|
||||
$restore='classification_before_'.$stamp.'_test';
|
||||
if(!preg_match('/^classification_before_\d{8}_\d{6}_test$/D',$restore))throw new RuntimeException('Restore guard');
|
||||
$source=new PDO('pgsql:host='.$c['host'].';port=5432;dbname=investemoz',$c['username'],$c['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);$source->exec('BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY');$source->exec("SET LOCAL TIME ZONE 'UTC'");
|
||||
$run=function(array$args,string$password){$p=new Symfony\Component\Process\Process($args,null,['PGPASSWORD'=>$password]);$p->setTimeout(240);$p->run();if(!$p->isSuccessful())throw new RuntimeException('Backup or restore subprocess failed');};
|
||||
try{
|
||||
$identity=$source->query('SELECT current_database() AS database,inet_server_port() AS port')->fetch(PDO::FETCH_ASSOC);
|
||||
if($identity['database']!=='investemoz'||(int)$identity['port']!==5432)throw new RuntimeException('Actual active mismatch');
|
||||
$migration=$source->query("SELECT count(*) FROM migrations WHERE migration='2026_10_09_190000_prepare_investor_path'")->fetchColumn();
|
||||
$env=Dotenv\Dotenv::parse(file_get_contents($root.'/.env'));
|
||||
if(!filter_var($env['INVESTOR_PATH_ENABLED']??false,FILTER_VALIDATE_BOOL)||!filter_var($env['PORTAL_LEGACY_CONTENT_ENABLED']??false,FILTER_VALIDATE_BOOL))throw new RuntimeException('Both flags must remain enabled');
|
||||
$snapshot=$source->query('SELECT pg_export_snapshot()')->fetchColumn();$dump=$dir.'/destination.dump';$bin='C:/Program Files/PostgreSQL/17/bin/';
|
||||
$run([$bin.'pg_dump.exe','-h',$c['host'],'-p','5432','-U',$c['username'],'-d','investemoz','-Fc','--snapshot='.$snapshot,'-f',$dump],$c['password']);
|
||||
$admin=new PDO('pgsql:host=127.0.0.1;port=55441;dbname=postgres','postgres','',[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
|
||||
if((int)$admin->query('SELECT inet_server_port()')->fetchColumn()!==55441)throw new RuntimeException('QA restore identity');
|
||||
$admin->exec('CREATE DATABASE "'.$restore.'"');
|
||||
$run([$bin.'pg_restore.exe','-h','127.0.0.1','-p','55441','-U','postgres','-d',$restore,'--exit-on-error','--no-owner','--no-privileges',$dump],'');
|
||||
$clone=new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$restore,'postgres','',[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);$clone->exec('BEGIN READ ONLY');$clone->exec("SET LOCAL TIME ZONE 'UTC'");
|
||||
$tables=[];foreach($source->query("SELECT schemaname,tablename FROM pg_tables WHERE schemaname NOT LIKE 'pg_%' AND schemaname <> 'information_schema' ORDER BY schemaname,tablename")->fetchAll(PDO::FETCH_ASSOC)as$t){
|
||||
$name='"'.str_replace('"','""',$t['schemaname']).'"."'.str_replace('"','""',$t['tablename']).'"';$sql='SELECT row_to_json(t)::text FROM '.$name.' t ORDER BY row_to_json(t)::text';
|
||||
$a=$source->query($sql)->fetchAll(PDO::FETCH_COLUMN);$b=$clone->query($sql)->fetchAll(PDO::FETCH_COLUMN);if($a!==$b)throw new RuntimeException('Restored rows differ');$tables[$name]=['rows'=>count($a),'sha256'=>hash('sha256',implode("\n",$a))];
|
||||
}
|
||||
$sql="SELECT schemaname,sequencename,data_type,start_value,min_value,max_value,increment_by,cycle,cache_size,last_value FROM pg_sequences WHERE schemaname NOT LIKE 'pg_%' AND schemaname <> 'information_schema' ORDER BY schemaname,sequencename";
|
||||
$sequences=$source->query($sql)->fetchAll(PDO::FETCH_ASSOC);if($sequences!==$clone->query($sql)->fetchAll(PDO::FETCH_ASSOC))throw new RuntimeException('Sequence mismatch');
|
||||
$zip=new ZipArchive();$fileszip=$dir.'/destination-files.zip';if($zip->open($fileszip,ZipArchive::CREATE|ZipArchive::EXCL)!==true)throw new RuntimeException('Private files archive');
|
||||
$files=[];$copy=function(string$from,string$rel)use($dir,$zip,&$files){$to=$dir.'/files/'.$rel;$restored=$dir.'/file-restore/'.$rel;foreach([$to,$restored]as$p){if(!is_dir(dirname($p)))mkdir(dirname($p),0700,true);if(!copy($from,$p)||hash_file('sha256',$from)!==hash_file('sha256',$p))throw new RuntimeException('File restore mismatch');}$files[$rel]=hash_file('sha256',$from);$zip->addFile($to,$rel);};
|
||||
$baseline=json_decode(file_get_contents($release.'/ATIVO-FICHEIROS-ANTES.json'),true,512,JSON_THROW_ON_ERROR);
|
||||
foreach($baseline as$path=>$hash){if(!is_file($root.'/'.$path)||hash_file('sha256',$root.'/'.$path)!==$hash)throw new RuntimeException('Protected baseline differs');$copy($root.'/'.$path,$path);}
|
||||
foreach(['bootstrap','config']as$folder){$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root.'/'.$folder,FilesystemIterator::SKIP_DOTS));foreach($it as$f)if($f->isFile()){$rel=str_replace('\\','/',substr($f->getPathname(),strlen($root)+1));if(!isset($files[$rel]))$copy($f->getPathname(),$rel);}}
|
||||
foreach(['artisan','composer.json','package.json','tsconfig.json']as$n)$copy($root.'/'.$n,$n);
|
||||
foreach(['storage/app/public','storage/app/private/land-assistance','storage/app/private/opportunity-resources','storage/app/private/partnership-exchange','storage/app/private/partnerships','storage/app/private/portal-documents','storage/app/private/virtual-desk','storage/app/private/ai-documents']as$folder){if(!is_dir($root.'/'.$folder))continue;$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root.'/'.$folder,FilesystemIterator::SKIP_DOTS));foreach($it as$f)if($f->isFile()){$rel=str_replace('\\','/',substr($f->getPathname(),strlen($root)+1));if(!isset($files[$rel]))$copy($f->getPathname(),$rel);}}
|
||||
|
||||
$it=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($root.'/public/build',FilesystemIterator::SKIP_DOTS));foreach($it as$f)if($f->isFile())$copy($f->getPathname(),str_replace('\\','/',substr($f->getPathname(),strlen($root)+1)));
|
||||
foreach(['.env','config/inertia.php','config/investor-path.php','composer.lock','package-lock.json','bootstrap/app.php']as$n)$copy($root.'/'.$n,$n);
|
||||
$local=config('filesystems.disks.local.root');$docs=0;$unavailable=[];
|
||||
foreach($source->query('SELECT id,storage_key,status,deleted_at FROM documents WHERE storage_key IS NOT NULL ORDER BY id')->fetchAll(PDO::FETCH_ASSOC)as$d){
|
||||
$p=$local.'/'.$d['storage_key'];if(!is_file($p)){$unavailable[]=['id'=>$d['id'],'status'=>$d['status'],'deleted'=>$d['deleted_at']!==null];continue;}
|
||||
$copy($p,'storage-documents/'.$d['id'].'.stored');$docs++;
|
||||
}
|
||||
$zip->close();$clone->exec('ROLLBACK');
|
||||
$private=['verified_at'=>gmdate('c'),'target'=>$identity,'restore_target'=>['database'=>$restore,'port'=>55441],'dump_path'=>$dump,'sha256'=>hash_file('sha256',$dump),'files_path'=>$fileszip,'files_sha256'=>hash_file('sha256',$fileszip),'restore_verified'=>true,'files_verified'=>true,'tables'=>$tables,'sequence_count'=>count($sequences),'file_hashes'=>$files,'preexisting_unavailable_documents'=>$unavailable,'source_paths'=>$map['source_operations'],'cache_state'=>$cacheState,'B_path_flag_before'=>true,'legacy_reader_before'=>true,'190000_before'=>(int)$migration,'active_business_writes'=>0,'cache_state'=>$cacheState];
|
||||
file_put_contents($dir.'/backup-proof-private.json',json_encode($private,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR));
|
||||
$safe=['at'=>$private['verified_at'],'candidate'=>$manifest['candidate'],'target'=>$identity,'restore_target'=>$private['restore_target'],'restore_verified'=>true,'files_verified'=>true,'tables'=>count($tables),'sequences'=>count($sequences),'restored_table_hashes_equal'=>true,'private_directory'=>$dir,'dump_sha256'=>$private['sha256'],'files_sha256'=>$private['files_sha256'],'file_count'=>count($files),'document_files'=>$docs,'preexisting_unavailable_document_count'=>count($unavailable),'190000_before'=>(int)$migration,'cache_state'=>$cacheState,'B_path_flag_before'=>true,'legacy_reader_before'=>true,'active_business_writes'=>0,'cache_state'=>$cacheState];
|
||||
if(is_file(__DIR__.'/FRESH-BACKUP.json'))throw new RuntimeException('Preserve receipt');
|
||||
file_put_contents(__DIR__.'/FRESH-BACKUP.json',json_encode($safe,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR).PHP_EOL);echo json_encode($safe,JSON_UNESCAPED_UNICODE).PHP_EOL;
|
||||
}finally{$source->exec('ROLLBACK');}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"before_sha256": "77ca8f755dc4f0e31baeb734421bb12007571d60c3dc2da14ccac581725af6bc",
|
||||
"after_sha256": "0d305a63915e2e7ce18051e5981b3773b2ef9c7d5e411adaa93f2898b2730a78",
|
||||
"rows": 3402,
|
||||
"changed_ids": [
|
||||
"M2-d0c06a75-0029",
|
||||
"M2-d0c06a75-0158",
|
||||
"MASTER-e1169a77-0043",
|
||||
"MASTER-e1169a77-0062",
|
||||
"OP-9f173ed3-0165",
|
||||
"RF-CLU-002",
|
||||
"RF-CLU-003",
|
||||
"RF-COR-003"
|
||||
],
|
||||
"other_raw_rows_preserved": 3394,
|
||||
"accepted_items_reopened": 0,
|
||||
"global_requirements_closed": 0,
|
||||
"new_requirements": 0,
|
||||
"same_existing_matrix": true
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"at": "2026-10-15T20:31:04.143730+00:00",
|
||||
"origin": "Express user decision by Tempo in current conversation",
|
||||
"user_statement": "A Tempo autoriza a disponibiliza?a?",
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"document_revision": "DOC01",
|
||||
"candidate_zip_sha256": "334d8ef2e47848a3c30cf526ae4d394004f112288cdddbcf635f06a1be1e0bc6",
|
||||
"candidate_receipt_sha256": "5e6fc4e3661de95c18e3192dfe3f68c048a5e676b0df44485a0a0650ab032505",
|
||||
"authorized": "17 sources and coherent build; fresh backup/isolated restore; compatible reversal; preserve data cache, B, COUNTRY02, permissions, contents and history",
|
||||
"excluded": "migrations, QA fixtures/synthetic classifications, real association changes, repeated accepted QA or unrelated functionality",
|
||||
"remaining_global_gaps": [
|
||||
"/negocios",
|
||||
"full operational parks record",
|
||||
"missing economic references",
|
||||
"duplicate consolidation",
|
||||
"complete specific Fintech regulation"
|
||||
]
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"document_revision": "DOC01",
|
||||
"delivery_state": "deployed",
|
||||
"files": {
|
||||
"ARRANQUE-CLONE-RESTAURADO.json": {
|
||||
"sha256": "37537022e4c4708ca024c3ee42b6f9c48e3c7192aaf9079c6e82e35f303c7cbc",
|
||||
"bytes": 1462
|
||||
},
|
||||
"ATIVO-403.jpg": {
|
||||
"sha256": "0dce0a45f89cf0603bcbdd50f5b3a848892ab43a418d88019c89b7885aec4c41",
|
||||
"bytes": 16447
|
||||
},
|
||||
"ATIVO-CATALOGO.jpg": {
|
||||
"sha256": "a2ca71cbdcf69f73af5a031f30609a7087c6cab7c93dbbb50aab308672e47157",
|
||||
"bytes": 138849
|
||||
},
|
||||
"ATUALIZACAO-MESMA-MATRIZ.json": {
|
||||
"sha256": "cfa70a286e24dfc5993e0ddae87c4f08c0c943da0cc4e118c0f819611a9768a8",
|
||||
"bytes": 577
|
||||
},
|
||||
"AUTORIZACAO-TEMPO.json": {
|
||||
"sha256": "138ad861eaa8020c81db9d40e71533cefcf9d3ff165a36e09ff5e8ded05b12ae",
|
||||
"bytes": 993
|
||||
},
|
||||
"CACHE-DADOS-AFTER.json": {
|
||||
"sha256": "495b64153961a283ca4c3e0c76ed2b60867fefed41d40d3a1ab9940b6eb753ff",
|
||||
"bytes": 153
|
||||
},
|
||||
"CACHE-DADOS-BEFORE.json": {
|
||||
"sha256": "495b64153961a283ca4c3e0c76ed2b60867fefed41d40d3a1ab9940b6eb753ff",
|
||||
"bytes": 153
|
||||
},
|
||||
"FONTES-COMPILACAO.json": {
|
||||
"sha256": "232e5096c367d1ab33a7d69090768d4f38aa4c2988946f0fc761bdb555fbea0a",
|
||||
"bytes": 27932
|
||||
},
|
||||
"FRESH-BACKUP.json": {
|
||||
"sha256": "4bdbbebc05d65ad29a2a9820525a0c657f5d9bd27f7aec4adf7b617f0cd2bbd8",
|
||||
"bytes": 1632
|
||||
},
|
||||
"HTTP-AFTER.json": {
|
||||
"sha256": "252eb29d4c51d4f981c6c9d05b250bb7d91cb794368f16480bd02ab0e3873aab",
|
||||
"bytes": 2353
|
||||
},
|
||||
"HTTP-BEFORE.json": {
|
||||
"sha256": "b1e6c52d1aae2a7e8d812600041255aa3955de8145f1de21894b0332ad15a1e0",
|
||||
"bytes": 2355
|
||||
},
|
||||
"INTERFACE-OPERACIONAL.json": {
|
||||
"sha256": "d466ac405ed3aa7a646789473009a75fb01e63a649425f2d50d754caf88b7064",
|
||||
"bytes": 1504
|
||||
},
|
||||
"MAPA-REVERSAO-EXECUCAO.json": {
|
||||
"sha256": "354bef29bc68d55e27dcede121b3b652a519b2aa6db692380a6639da99496d90",
|
||||
"bytes": 6136
|
||||
},
|
||||
"PREFLIGHT.json": {
|
||||
"sha256": "c743d9c52a3b888dc09c90ab14bec24df898dcc99345da49846b99fc31cbf2e6",
|
||||
"bytes": 117600
|
||||
},
|
||||
"PRESERVACAO-AFTER.json": {
|
||||
"sha256": "6bb5138bd2e455a82a2dc81fc77aedc1889eaa4dde9b438f42599ccb78802393",
|
||||
"bytes": 110702
|
||||
},
|
||||
"PRESERVACAO-BEFORE.json": {
|
||||
"sha256": "cec49616a751e2cd7f349444a0529881ad9ad35f0903eca38bd9271fcd2a6779",
|
||||
"bytes": 110699
|
||||
},
|
||||
"PRESERVACAO-FINAL.json": {
|
||||
"sha256": "a56251c65b8987cabec9be5e36dc90afeec474cc15f85e81a4dda46ecaa8d2bd",
|
||||
"bytes": 111243
|
||||
},
|
||||
"RECUSA-403-REGRA-ANTERIOR.json": {
|
||||
"sha256": "d6911c2d7ac36eff2b8173a823de2de0cc32f79e5c3d914ee1e28146d1d2988e",
|
||||
"bytes": 958
|
||||
},
|
||||
"RELATORIO-ENTREGA.md": {
|
||||
"sha256": "e362292b554d0650e2b0b2e5e26dab47bcaf65233409cb065c0a464a59244c7b",
|
||||
"bytes": 6638
|
||||
},
|
||||
"boot-restored-clone.php": {
|
||||
"sha256": "159aff4bcb2d346c8242ae20c1bdb569bb7c5d8d3d70dbdfea8071a1f9de9484",
|
||||
"bytes": 6502
|
||||
},
|
||||
"cache-snapshot.php": {
|
||||
"sha256": "46c8e18eb07b628f69619a0ca1a1c5a769b0321b2c364308241d1da3fc9f4aab",
|
||||
"bytes": 2944
|
||||
},
|
||||
"candidata/classificacao-multidimensional-QA-64ab05e20b95-doc01.zip": {
|
||||
"sha256": "334d8ef2e47848a3c30cf526ae4d394004f112288cdddbcf635f06a1be1e0bc6",
|
||||
"bytes": 1756371
|
||||
},
|
||||
"deliver.py": {
|
||||
"sha256": "c13b0d3c2f7221fc624f38275183ab6bd42677dbc53473c2755d46077f5417bf",
|
||||
"bytes": 6605
|
||||
},
|
||||
"fresh-backup.php": {
|
||||
"sha256": "3e77fb785ac149a6260ccf91a88f1f7f7e9b21b9d500d27f48325f40ee88c08c",
|
||||
"bytes": 10662
|
||||
},
|
||||
"http-operacional.py": {
|
||||
"sha256": "cd86488f65d2a7bb8a3449f4ab5d4fa7d703c049a04909631a9fbd7fda94e2e2",
|
||||
"bytes": 2885
|
||||
},
|
||||
"preflight.py": {
|
||||
"sha256": "55f90f5d633dfdc9131813f8c872d200e4e19e0c6b5ce1ed1bae4491f7799677",
|
||||
"bytes": 3328
|
||||
},
|
||||
"revert-compatible.py": {
|
||||
"sha256": "2b133f546293d6f38a2fa85cbe7b22a13f29906e5399a4205fdff6bbf4f07ecf",
|
||||
"bytes": 3879
|
||||
},
|
||||
"verify-preservation.php": {
|
||||
"sha256": "e8e1faad3335bd271b583fd48d5f78c9874be6b1267623c1d2c33bab7a064c64",
|
||||
"bytes": 6311
|
||||
}
|
||||
},
|
||||
"exclusions": "No database dump, backups of private data, credentials, sessions or configuration contents are attached."
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"target": "https://portal-investidor.test",
|
||||
"catalogue_visible": true,
|
||||
"catalogue_screenshot": "ATIVO-CATALOGO.jpg",
|
||||
"classification_filter_labels_visible": true,
|
||||
"observed_session": "Osmane Nala",
|
||||
"review_queue_records": 0,
|
||||
"editor_in_authorized_operational_session": "not observed: operational login unavailable; current superuser session has no active elevation",
|
||||
"user_reply": "N?o tenho acesso ? conta de Aurora",
|
||||
"business_saves": 0,
|
||||
"accepted_QA_repeated": false,
|
||||
"at": "2026-10-15T20:37:26.422282+00:00",
|
||||
"editor_observation_status": "not_observed",
|
||||
"editor_observation_summary": "Editor no ativo: n?o demonstrado nesta confer?ncia. O utilizador informou n?o ter acesso ? conta de Promotora interna Aurora Chachuaio. A sess?o efetiva Osmane Nala, conta 2, recebeu 403 em GET /minhas-oportunidades/create; n?o existe eleva??o operacional ativa. Os pap?is Promotor/Validador dessa conta permanecem atribu?dos; as fun??es de autoriza??o v1 conferem exatamente com a vers?o anterior ? entrega. Existem seis oportunidades legadas e nenhuma do workflow de promotor no ativo. A mensagem 403 gen?rica n?o exp?e o motivo; o diagn?stico fica registado, sem alterar permiss?es, credenciais ou acrescentar uma corre??o fora do pacote autorizado. Mant?m-se as provas funcionais QA aceites do editor.",
|
||||
"denial_evidence": "RECUSA-403-REGRA-ANTERIOR.json",
|
||||
"denial_screenshot": "ATIVO-403.jpg"
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"at": "2026-10-15T20:37:28.898094+00:00",
|
||||
"candidate": "classificacao-multidimensional-QA-64ab05e20b95",
|
||||
"document_revision": "DOC01",
|
||||
"state": "deployed",
|
||||
"target": "https://portal-investidor.test",
|
||||
"candidate_zip_sha256": "334d8ef2e47848a3c30cf526ae4d394004f112288cdddbcf635f06a1be1e0bc6",
|
||||
"sources": 17,
|
||||
"replacements": 14,
|
||||
"new_sources": 3,
|
||||
"build_files": 174,
|
||||
"fresh_backup_restore_verified": true,
|
||||
"clone_kernel_boot_verified": true,
|
||||
"business_tables_compared": 295,
|
||||
"business_tables_identical_immediately_after_switch": true,
|
||||
"business_records_and_prior_history_preserved_at_final": true,
|
||||
"expected_access_denial_audit_rows_added": 2,
|
||||
"data_cache_unchanged_during_switch": true,
|
||||
"B_COUNTRY02_permissions_content_history_preserved": true,
|
||||
"migrations_run": 0,
|
||||
"real_association_writes": 0,
|
||||
"synthetic_data_imported": false,
|
||||
"accepted_QA_repeated": false,
|
||||
"editor_observation_status": "not_observed",
|
||||
"editor_observation_summary": "Editor no ativo: n?o demonstrado nesta confer?ncia. O utilizador informou n?o ter acesso ? conta de Promotora interna Aurora Chachuaio. A sess?o efetiva Osmane Nala, conta 2, recebeu 403 em GET /minhas-oportunidades/create; n?o existe eleva??o operacional ativa. Os pap?is Promotor/Validador dessa conta permanecem atribu?dos; as fun??es de autoriza??o v1 conferem exatamente com a vers?o anterior ? entrega. Existem seis oportunidades legadas e nenhuma do workflow de promotor no ativo. A mensagem 403 gen?rica n?o exp?e o motivo; o diagn?stico fica registado, sem alterar permiss?es, credenciais ou acrescentar uma corre??o fora do pacote autorizado. Mant?m-se as provas funcionais QA aceites do editor.",
|
||||
"compatible_rollback_contract_sha256": "6023295d57063b6054662515eb837930ac4bffa642744433499dd0b1912f5107",
|
||||
"rollback_executed": false,
|
||||
"matrix": {
|
||||
"before_sha256": "77ca8f755dc4f0e31baeb734421bb12007571d60c3dc2da14ccac581725af6bc",
|
||||
"after_sha256": "0d305a63915e2e7ce18051e5981b3773b2ef9c7d5e411adaa93f2898b2730a78",
|
||||
"rows": 3402,
|
||||
"changed_ids": [
|
||||
"M2-d0c06a75-0029",
|
||||
"M2-d0c06a75-0158",
|
||||
"MASTER-e1169a77-0043",
|
||||
"MASTER-e1169a77-0062",
|
||||
"OP-9f173ed3-0165",
|
||||
"RF-CLU-002",
|
||||
"RF-CLU-003",
|
||||
"RF-COR-003"
|
||||
],
|
||||
"other_raw_rows_preserved": 3394,
|
||||
"accepted_items_reopened": 0,
|
||||
"global_requirements_closed": 0,
|
||||
"new_requirements": 0,
|
||||
"same_existing_matrix": true
|
||||
},
|
||||
"artifact_hashes": {
|
||||
"AUTORIZACAO-TEMPO.json": "138ad861eaa8020c81db9d40e71533cefcf9d3ff165a36e09ff5e8ded05b12ae",
|
||||
"PREFLIGHT.json": "c743d9c52a3b888dc09c90ab14bec24df898dcc99345da49846b99fc31cbf2e6",
|
||||
"FRESH-BACKUP.json": "4bdbbebc05d65ad29a2a9820525a0c657f5d9bd27f7aec4adf7b617f0cd2bbd8",
|
||||
"ARRANQUE-CLONE-RESTAURADO.json": "37537022e4c4708ca024c3ee42b6f9c48e3c7192aaf9079c6e82e35f303c7cbc",
|
||||
"PRESERVACAO-BEFORE.json": "cec49616a751e2cd7f349444a0529881ad9ad35f0903eca38bd9271fcd2a6779",
|
||||
"PRESERVACAO-AFTER.json": "6bb5138bd2e455a82a2dc81fc77aedc1889eaa4dde9b438f42599ccb78802393",
|
||||
"PRESERVACAO-FINAL.json": "a56251c65b8987cabec9be5e36dc90afeec474cc15f85e81a4dda46ecaa8d2bd",
|
||||
"RECUSA-403-REGRA-ANTERIOR.json": "d6911c2d7ac36eff2b8173a823de2de0cc32f79e5c3d914ee1e28146d1d2988e",
|
||||
"ATIVO-403.jpg": "0dce0a45f89cf0603bcbdd50f5b3a848892ab43a418d88019c89b7885aec4c41",
|
||||
"FONTES-COMPILACAO.json": "232e5096c367d1ab33a7d69090768d4f38aa4c2988946f0fc761bdb555fbea0a",
|
||||
"CACHE-DADOS-BEFORE.json": "495b64153961a283ca4c3e0c76ed2b60867fefed41d40d3a1ab9940b6eb753ff",
|
||||
"CACHE-DADOS-AFTER.json": "495b64153961a283ca4c3e0c76ed2b60867fefed41d40d3a1ab9940b6eb753ff",
|
||||
"HTTP-BEFORE.json": "b1e6c52d1aae2a7e8d812600041255aa3955de8145f1de21894b0332ad15a1e0",
|
||||
"HTTP-AFTER.json": "252eb29d4c51d4f981c6c9d05b250bb7d91cb794368f16480bd02ab0e3873aab",
|
||||
"INTERFACE-OPERACIONAL.json": "d466ac405ed3aa7a646789473009a75fb01e63a649425f2d50d754caf88b7064",
|
||||
"MAPA-REVERSAO-EXECUCAO.json": "354bef29bc68d55e27dcede121b3b652a519b2aa6db692380a6639da99496d90",
|
||||
"RELATORIO-ENTREGA.md": "e362292b554d0650e2b0b2e5e26dab47bcaf65233409cb065c0a464a59244c7b",
|
||||
"ATUALIZACAO-MESMA-MATRIZ.json": "cfa70a286e24dfc5993e0ddae87c4f08c0c943da0cc4e118c0f819611a9768a8",
|
||||
"ATIVO-CATALOGO.jpg": "a2ca71cbdcf69f73af5a031f30609a7087c6cab7c93dbbb50aab308672e47157",
|
||||
"revert-compatible.py": "2b133f546293d6f38a2fa85cbe7b22a13f29906e5399a4205fdff6bbf4f07ecf",
|
||||
"deliver.py": "c13b0d3c2f7221fc624f38275183ab6bd42677dbc53473c2755d46077f5417bf",
|
||||
"preflight.py": "55f90f5d633dfdc9131813f8c872d200e4e19e0c6b5ce1ed1bae4491f7799677",
|
||||
"fresh-backup.php": "3e77fb785ac149a6260ccf91a88f1f7f7e9b21b9d500d27f48325f40ee88c08c",
|
||||
"boot-restored-clone.php": "159aff4bcb2d346c8242ae20c1bdb569bb7c5d8d3d70dbdfea8071a1f9de9484",
|
||||
"cache-snapshot.php": "46c8e18eb07b628f69619a0ca1a1c5a769b0321b2c364308241d1da3fc9f4aab",
|
||||
"verify-preservation.php": "e8e1faad3335bd271b583fd48d5f78c9874be6b1267623c1d2c33bab7a064c64",
|
||||
"http-operacional.py": "cd86488f65d2a7bb8a3449f4ab5d4fa7d703c049a04909631a9fbd7fda94e2e2"
|
||||
},
|
||||
"inventory_sha256": "2d8dc3b349bdd165ad50fd0ae8ec7862fca4ffe94065250a87e123f7c5c13802",
|
||||
"zip": {
|
||||
"name": "classificacao-multidimensional-disponibilizado-20261015-64ab05e20b95.zip",
|
||||
"bytes": 1968996,
|
||||
"sha256": "d2fc6b5adace2358dd78cd964a02aba6f0c45d306c8228a1a72e76682163f455",
|
||||
"entries": 29,
|
||||
"all_entries_verified": true
|
||||
},
|
||||
"remaining_global_gaps": [
|
||||
"/negocios",
|
||||
"full operational parks record",
|
||||
"missing economic references",
|
||||
"duplicate consolidation",
|
||||
"complete specific Fintech regulation"
|
||||
]
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
# Classificação multidimensional — disponibilização DOC01
|
||||
|
||||
Entregue no destino `https://portal-investidor.test` a candidata `classificacao-multidimensional-QA-64ab05e20b95`, após autorização expressa da Tempo nesta conversa. O pacote DOC01 aprovado permanece imutável: SHA-256 `334d8ef2e47848a3c30cf526ae4d394004f112288cdddbcf635f06a1be1e0bc6`.
|
||||
|
||||
Foram substituídas 14 fontes e acrescentadas três, com os 174 ficheiros da compilação correspondente conferidos por hash. O preflight confirmou os hashes anteriores, as três ausências e os 1.899 ficheiros protegidos da preparação. Não foram executadas migrations, importações, publicações editoriais, mudanças de flags, permissões ou associações reais. As provas funcionais QA aceites foram reutilizadas; não se repetiu a auditoria.
|
||||
|
||||
## Recuperação preparada junto da execução
|
||||
|
||||
O backup fresco foi restaurado exclusivamente na base isolada `classification_before_20261015_202406_test`, porta 55441, separado do destino `investemoz`, porta 5432. Foram conferidos os conteúdos de 295 tabelas, 31 sequências e 2.221 ficheiros copiados/restaurados, incluindo fontes/build, configuração, ficheiros privados geridos e 29 documentos. Não havia documentos indisponíveis nessa fotografia. Os dumps, configuração e cópias integrais permanecem apenas no armazenamento privado local; não integram o anexo de revisão.
|
||||
|
||||
Hashes do backup: dump `7e7bd1b582d25d446dbfce8b4fbb399602caf0b8d4dc503a21e9515f63b57aaf`; arquivo de ficheiros `1232b8cf3a0d32f97d7231f6b5504362cbd2b3b24bc0cd13bc82728a02b39629`. O recibo `FRESH-BACKUP.json` identifica a localização privada para recuperação.
|
||||
|
||||
O clone de fontes e build restaurados arrancou pelo kernel Laravel e respondeu com HTTP 200 a `/up`, `/login` e `/oportunidades`, com conexão ao clone protegida contra escrita, cache/sessões em memória e conectores externos desabilitados apenas no clone. Esta prova é de kernel/contrato/renderização; não constitui ensaio de um segundo servidor TLS ou de workers. Uma primeira tentativa operacional foi interrompida pela guarda porque o valor de sessão de leitura exclusiva não estava ativo; a tentativa válida aplicou explicitamente essa proteção na conexão isolada, sem enfraquecer a guarda ou alterar o destino.
|
||||
|
||||
## Troca e conferência operacional
|
||||
|
||||
A troca decorreu em manutenção, com saída antes da consulta pela interface. Foram executados exclusivamente `config:clear`, `route:clear` e `view:clear`. O destino não usava cache de configuração ou rotas nem pré-compilação de vistas na sua entrega anterior, pelo que esses modos não foram introduzidos. A cache de dados usa a base de dados; os seus registos ficaram idênticos nas fotografias tomadas antes e depois da troca e dos comandos. Não foi executado `optimize:clear` nem `cache:clear`.
|
||||
|
||||
As duas rotas de classificação constam do código em execução. A conferência HTTP do destino validou o certificado e nome TLS, `/up`, catálogo público sem sessão e quatro assets de entrada servidos com os hashes locais. As mesmas seis oportunidades públicas e a primeira página conservaram identificadores, títulos e slugs. Os novos filtros foram observados no navegador do destino, sem gravar nem classificar anúncios. A captura `ATIVO-CATALOGO.jpg` mostra essa apresentação; observar o ativo não repete a aceitação funcional QA.
|
||||
|
||||
Na comparação de leitura com o restauro fresco, todas as tabelas de negócio ficaram idênticas. Sessões, cache, locks e filas são identificadas separadamente como tabelas técnicas; a preservação da cache durante a troca tem prova própria. Foram conferidos os 17 hashes entregues, os 174 hashes do build, sete ficheiros de configuração protegidos, os outros 1.827 ficheiros protegidos não abrangidos pela troca, 281 ficheiros privados/públicos geridos e os 29 documentos originais. A instalação 190000 já existente e as flags de B e do leitor permaneceram iguais. Não foi alterado COUNTRY02, o conteúdo publicado ou o histórico.
|
||||
|
||||
## Reversão após utilização
|
||||
|
||||
O mapa `MAPA-REVERSAO-EXECUCAO.json` distingue cada fonte. Após gravação dos campos novos, repor **13 fontes anteriores e o contrato compatível**, com SHA-256 `6023295d57063b6054662515eb837930ac4bffa642744433499dd0b1912f5107`; não repor cegamente os 14 originais. Esse contrato conserva `enterprise_size`, as relações e os dados já gravados, mantendo decisões, publicação e auditoria.
|
||||
|
||||
Restaurar o build anterior completo a partir do backup fresco, repor as referências antes de retirar por hash as três fontes novas e limpar apenas configuração, rotas e vistas. Os assets anteriores foram mantidos. Não restaurar uma fotografia antiga da base sobre operações posteriores, apagar JSON, renumerar registos ou executar down de migrations. A ação preparada `revert-compatible.py --candidate=classificacao-multidimensional-QA-64ab05e20b95` recusa ficheiros entretanto alterados e preserva os dados; não foi executada. Mantém-se a prova QA anterior de compatibilidade, sem novo ensaio funcional de reversão no ativo.
|
||||
|
||||
## Limites mantidos
|
||||
|
||||
O incremento cobre o cadastro canónico Opportunity e `/oportunidades`. Continuam abertos na mesma matriz: anúncios UUID de `/negocios`, ficha operacional integral dos parques, referências económicas em falta, similaridade/consolidação de duplicados e regulação Fintech específica completa. A entrega parcial não encerra essas cláusulas nem reabre B, COUNTRY02 ou as aceitações anteriores.
|
||||
|
||||
As restrições de âmbito, preservação e ausência de migrations/dados sintéticos derivam da autorização expressa da Tempo. Papéis, MFA e independência mantêm as políticas aprovadas. Guardas de hash, manutenção e contrato compatível são escolhas técnicas de execução, sem novos papéis ou exigências organizacionais.
|
||||
|
||||
## Conferência autenticada do editor
|
||||
|
||||
Editor no ativo: n?o demonstrado nesta confer?ncia. O utilizador informou n?o ter acesso ? conta de Promotora interna Aurora Chachuaio. A sess?o efetiva Osmane Nala, conta 2, recebeu 403 em GET /minhas-oportunidades/create; n?o existe eleva??o operacional ativa. Os pap?is Promotor/Validador dessa conta permanecem atribu?dos; as fun??es de autoriza??o v1 conferem exatamente com a vers?o anterior ? entrega. Existem seis oportunidades legadas e nenhuma do workflow de promotor no ativo. A mensagem 403 gen?rica n?o exp?e o motivo; o diagn?stico fica registado, sem alterar permiss?es, credenciais ou acrescentar uma corre??o fora do pacote autorizado. Mant?m-se as provas funcionais QA aceites do editor.
|
||||
@@ -0,0 +1,32 @@
|
||||
from pathlib import Path
|
||||
import urllib.request,urllib.error,urllib.parse,ssl,json,hashlib,datetime,sys
|
||||
from html.parser import HTMLParser
|
||||
root=Path(__file__).resolve().parents[2];out=Path(__file__).resolve().parent
|
||||
phase=sys.argv[1];assert phase in ['before','after']
|
||||
base='https://portal-investidor.test'
|
||||
ctx=ssl.create_default_context(cafile='C:/Users/macbook/.config/investmoz/tls/portal-investidor.test-fullchain.pem')
|
||||
class Parser(HTMLParser):
|
||||
def __init__(self):super().__init__();self.on=False;self.data=[];self.assets=[]
|
||||
def handle_starttag(self,t,a):
|
||||
a=dict(a)
|
||||
if t=='script' and a.get('type')=='application/json':self.on=True
|
||||
if t=='script' and a.get('type')=='module' and a.get('src'):self.assets.append(a['src'])
|
||||
if t=='link' and a.get('rel')=='stylesheet' and '/build/' in a.get('href',''):self.assets.append(a['href'])
|
||||
def handle_endtag(self,t):
|
||||
if t=='script':self.on=False
|
||||
def handle_data(self,d):
|
||||
if self.on:self.data.append(d)
|
||||
with urllib.request.urlopen(base+'/up',context=ctx,timeout=30) as response:assert response.status==200
|
||||
with urllib.request.urlopen(urllib.request.Request(base+'/oportunidades',headers={'Accept':'text/html'}),context=ctx,timeout=30) as response:
|
||||
assert response.status==200;p=Parser();p.feed(response.read().decode('utf-8'));v=json.loads(''.join(p.data))
|
||||
assert v['component']=='investment/catalogue' and v['props']['auth']['user'] is None
|
||||
result=v['props']['results'];public={'total':result['total'],'first_page':[{'id':x['id'],'slug':x['slug'],'title':x['title']} for x in result['data']]}
|
||||
assets=[]
|
||||
for url in p.assets:
|
||||
path=urllib.parse.urlsplit(url).path;assert path.startswith('/build/')
|
||||
with urllib.request.urlopen(base+path,context=ctx,timeout=30) as response:
|
||||
assert response.status==200;h=hashlib.sha256(response.read()).hexdigest();assert h==hashlib.sha256((root/'public'/path.lstrip('/')).read_bytes()).hexdigest();assets.append({'path':path,'status':200,'sha256':h})
|
||||
if phase=='after':assert public==json.loads((out/'HTTP-BEFORE.json').read_text('utf-8'))['public_catalogue']
|
||||
proof={'at':datetime.datetime.now(datetime.timezone.utc).isoformat(),'candidate':'classificacao-multidimensional-QA-64ab05e20b95','phase':phase,'TLS_certificate_and_hostname_verified':True,'checks':[{'method':'GET','path':'/up','status':200},{'method':'GET','path':'/oportunidades','status':200,'anonymous':True}],'public_catalogue':public,'served_entry_assets':assets,'public_catalogue_preserved':phase=='after','business_writes':0,'functional_QA_repeated':False}
|
||||
file=out/('HTTP-'+phase.upper()+'.json');assert not file.exists();file.write_text(json.dumps(proof,ensure_ascii=False,indent=2)+'\n','utf-8')
|
||||
print(json.dumps({'phase':phase,'operational_GETs':2,'served_assets_verified':len(assets),'public_total':public['total'],'catalogue_preserved':phase=='after'}))
|
||||
@@ -0,0 +1,36 @@
|
||||
from pathlib import Path, PurePosixPath
|
||||
import hashlib, json, zipfile, datetime
|
||||
root=Path(__file__).resolve().parents[2]
|
||||
release=root/'outputs/investmoz-classificacao-multidimensional-QA-20261015'
|
||||
out=Path(__file__).resolve().parent
|
||||
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
r=json.loads((release/'RECIBO-INTEGRIDADE.json').read_text('utf-8'))
|
||||
assert r['candidate']=='classificacao-multidimensional-QA-64ab05e20b95' and r['document_revision']=='DOC01'
|
||||
assert sha(release/'RECIBO-INTEGRIDADE.json')=='5e6fc4e3661de95c18e3192dfe3f68c048a5e676b0df44485a0a0650ab032505'
|
||||
archive=root/'outputs'/r['zip']['name']
|
||||
assert sha(archive)==r['zip']['sha256']=='334d8ef2e47848a3c30cf526ae4d394004f112288cdddbcf635f06a1be1e0bc6'
|
||||
assert archive.stat().st_size==r['zip']['bytes']
|
||||
with zipfile.ZipFile(archive) as z:
|
||||
assert z.testzip() is None
|
||||
assert len(z.namelist())==len(set(z.namelist()))==234
|
||||
manifest_bytes=z.read('MANIFESTO-ENTREGA.json')
|
||||
assert hashlib.sha256(manifest_bytes).hexdigest()==r['manifest_sha256']
|
||||
assert manifest_bytes==(release/'MANIFESTO-ENTREGA.json').read_bytes()
|
||||
m=json.loads(manifest_bytes)
|
||||
for p in m['payload']:
|
||||
assert not PurePosixPath(p['path']).is_absolute() and '..' not in PurePosixPath(p['path']).parts
|
||||
b=z.read(p['path']);assert hashlib.sha256(b).hexdigest()==p['sha256'] and len(b)==p['bytes']
|
||||
for name,h in r['documents'].items():assert sha(release/name)==h
|
||||
assert len(m['sources'])==17 and sum(x['operation']=='replace' for x in m['sources'])==14
|
||||
for s in m['sources']:
|
||||
p=root/s['path'];assert (sha(p) if p.is_file() else None)==s['previous_sha256'], 'Source diverged: '+s['path']
|
||||
assert hashlib.sha256(z.read('fontes/'+s['path'])).hexdigest()==s['candidate_sha256']
|
||||
assert sha(root/'public/build/manifest.json')==m['previous_build_manifest_sha256']
|
||||
baseline=json.loads((release/'ATIVO-FICHEIROS-ANTES.json').read_text('utf-8'))
|
||||
for n,h in baseline.items():assert (root/n).is_file() and sha(root/n)==h,'Protected source/build diverged: '+n
|
||||
assert not (root/'public/hot').exists() and not (root/'storage/framework/down').exists()
|
||||
protected=['.env','composer.lock','package-lock.json','bootstrap/app.php','config/inertia.php','config/portal.php','config/investor-path.php']
|
||||
record={'at':datetime.datetime.now(datetime.timezone.utc).isoformat(),'candidate':m['candidate'],'document_revision':'DOC01','authorization':'Tempo: A Tempo autoriza a disponibilizaçaõ (current conversation)','receipt_sha256':sha(release/'RECIBO-INTEGRIDADE.json'),'archive_sha256':sha(archive),'manifest_sha256':r['manifest_sha256'],'payload_hashes_verified':len(m['payload']),'previous_sources_verified':14,'new_paths_absent':3,'protected_baseline_files_verified':len(baseline),'protected_files':{n:sha(root/n) for n in protected},'previous_build_files':{p.relative_to(root/'public/build').as_posix():sha(p) for p in (root/'public/build').rglob('*') if p.is_file()},'matrix_sha256':sha(root/'docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv'),'active_business_writes':0}
|
||||
assert not (out/'PREFLIGHT.json').exists()
|
||||
(out/'PREFLIGHT.json').write_text(json.dumps(record,ensure_ascii=False,indent=2)+'\n','utf-8')
|
||||
print(json.dumps({k:v for k,v in record.items() if k not in ['protected_files','previous_build_files']},ensure_ascii=True))
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Prepared recovery action. Not executed by the delivery; never modifies database rows."""
|
||||
from pathlib import Path
|
||||
import hashlib,json,shutil,os,subprocess,sys,datetime
|
||||
root=Path(__file__).resolve().parents[2];out=Path(__file__).resolve().parent
|
||||
release=root/'outputs/investmoz-classificacao-multidimensional-QA-20261015'
|
||||
m=json.loads((release/'MANIFESTO-ENTREGA.json').read_text('utf-8'))
|
||||
assert sys.argv[1:]==['--candidate='+m['candidate']]
|
||||
b=json.loads((out/'FRESH-BACKUP.json').read_text('utf-8'));pre=json.loads((out/'PREFLIGHT.json').read_text('utf-8'))
|
||||
delivery=json.loads((out/'FONTES-COMPILACAO.json').read_text('utf-8'))
|
||||
assert b['restore_verified'] and b['files_verified'] and delivery['maintenance_ended']
|
||||
backup=Path(b['private_directory']);sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
contract='app/Services/OpportunityCanonicalContract.php'
|
||||
compat=backup/'candidate-staging/reversao-compat'/contract
|
||||
assert sha(compat)==m['rollback_compatibility_sha256']=='6023295d57063b6054662515eb837930ac4bffa642744433499dd0b1912f5107'
|
||||
for s in m['sources']:
|
||||
assert sha(root/s['path'])==s['candidate_sha256'],'Source has changed since delivery; reconcile: '+s['path']
|
||||
if s['previous_sha256'] is not None:assert sha(backup/'files'/s['path'])==s['previous_sha256']
|
||||
for n,h in delivery['build_files'].items():assert sha(root/'public'/n)==h,'Build changed since delivery'
|
||||
for n,h in pre['previous_build_files'].items():assert sha(backup/'files/public/build'/n)==h
|
||||
assert not (root/'storage/framework/down').exists()
|
||||
recovery=backup/('reversal-'+datetime.datetime.now(datetime.timezone.utc).strftime('%Y%m%d_%H%M%S'));recovery.mkdir(exist_ok=False)
|
||||
for n in [*[x['path'] for x in m['sources']],'public/build/manifest.json','public/build/fonts-manifest.json']:
|
||||
p=recovery/n;p.parent.mkdir(parents=True,exist_ok=True);shutil.copy2(root/n,p)
|
||||
php='C:/laragon/bin/php/php-8.5.11-Win32-vs17-x64/php.exe'
|
||||
def artisan(*args):
|
||||
run=subprocess.run([php,'artisan',*args],cwd=root,capture_output=True)
|
||||
(recovery/('-'.join(args).replace(':','-')+'.log')).write_bytes(run.stdout+run.stderr)
|
||||
if run.returncode:raise RuntimeError('Recovery command failed; keep maintenance: '+args[0])
|
||||
def put(src,dest):
|
||||
dest.parent.mkdir(parents=True,exist_ok=True);temp=dest.with_name(dest.name+'.classification-reversal.tmp');assert not temp.exists();shutil.copy2(src,temp);assert sha(src)==sha(temp);os.replace(temp,dest)
|
||||
artisan('down','--retry=60')
|
||||
assert (root/'storage/framework/down').exists()
|
||||
for s in m['sources']:
|
||||
if s['previous_sha256'] is not None:put(compat if s['path']==contract else backup/'files'/s['path'],root/s['path'])
|
||||
for n in sorted(pre['previous_build_files'],key=lambda x:x=='manifest.json'):put(backup/'files/public/build'/n,root/'public/build'/n)
|
||||
for s in m['sources']:
|
||||
if s['previous_sha256'] is None:
|
||||
f=root/s['path'];assert f.is_relative_to(root) and sha(f)==s['candidate_sha256'];f.unlink()
|
||||
for cmd in ['config:clear','route:clear','view:clear']:artisan(cmd)
|
||||
assert sha(root/contract)==m['rollback_compatibility_sha256']
|
||||
for n,h in pre['previous_build_files'].items():assert sha(root/'public/build'/n)==h
|
||||
artisan('up');assert not (root/'storage/framework/down').exists()
|
||||
proof={'at':datetime.datetime.now(datetime.timezone.utc).isoformat(),'candidate':m['candidate'],'result':'13 previous sources plus compatible contract and previous build restored','compatible_contract_sha256':sha(root/contract),'new_sources_removed_by_exact_hash':3,'data_cache_clear':False,'database_restore_or_writes':False,'preserved':'enterprise_size, relations, classification decisions, publication and audit history','current_code_copy':str(recovery),'operational_GET_confirmation_required':True}
|
||||
(recovery/'REVERSAO-EXECUTADA.json').write_text(json.dumps(proof,ensure_ascii=False,indent=2)+'\n','utf-8')
|
||||
print(json.dumps(proof,ensure_ascii=True))
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
ini_set('zend.exception_ignore_args','1');
|
||||
set_exception_handler(function(Throwable $e){fwrite(STDERR,'Preservation verification stopped: '.$e::class.' line '.$e->getLine().PHP_EOL);exit(1);});
|
||||
$root=dirname(__DIR__,2);$phase=$argv[1]??'';if(!in_array($phase,['final'],true))throw new RuntimeException('Explicit phase');
|
||||
require $root.'/vendor/autoload.php';$app=require $root.'/bootstrap/app.php';(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
|
||||
$c=config('database.connections.'.config('database.default'));if($c['database']!=='investemoz'||(int)$c['port']!==5432||!in_array($c['host'],['127.0.0.1','localhost'])||!empty($c['url']))throw new RuntimeException('Active identity');
|
||||
$b=json_decode(file_get_contents(__DIR__.'/FRESH-BACKUP.json'),true,512,JSON_THROW_ON_ERROR);$cloneName=$b['restore_target']['database'];if(!preg_match('/^classification_before_\d{8}_\d{6}_test$/D',$cloneName))throw new RuntimeException('Clone guard');
|
||||
$active=new PDO('pgsql:host='.$c['host'].';port=5432;dbname=investemoz',$c['username'],$c['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);$clone=new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$cloneName,'postgres','',[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
|
||||
foreach([$active,$clone]as$db){$db->exec('BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY');$db->exec("SET LOCAL TIME ZONE 'UTC'");}
|
||||
try{
|
||||
$technical=['sessions','cache','cache_locks','jobs','failed_jobs'];$tables=[];$differences=[];$allowedAudit=[];$businessIdentical=true;
|
||||
foreach($clone->query("SELECT schemaname,tablename FROM pg_tables WHERE schemaname NOT LIKE 'pg_%' AND schemaname <> 'information_schema' ORDER BY schemaname,tablename")->fetchAll(PDO::FETCH_ASSOC)as$t){$n=$t['tablename'];$q='"'.str_replace('"','""',$t['schemaname']).'"."'.str_replace('"','""',$n).'"';$sql='SELECT row_to_json(t)::text FROM '.$q.' t ORDER BY row_to_json(t)::text';$before=$clone->query($sql)->fetchAll(PDO::FETCH_COLUMN);$after=$active->query($sql)->fetchAll(PDO::FETCH_COLUMN);$technicalTable=in_array($n,$technical,true);if($before!==$after&&!$technicalTable){$businessIdentical=false;$missing=array_values(array_diff($before,$after));$added=array_values(array_diff($after,$before));$expected=$n==='audit_events'&&!$missing&&count($added)>0;foreach($added as$line){$event=json_decode($line,true);$data=$event['after_data']??[];if(is_string($data))$data=json_decode($data,true);if(($event['source_system']??'')!=='portal-profiles-v1'||($event['action']??'')!=='request_denied'||($data['path']??'')!=='minhas-oportunidades/create'||($data['method']??'')!=='GET'||(int)($data['status']??0)!==403||(int)($event['actor_user_id']??0)!==2)$expected=false;}if($expected){foreach($added as$line){$e=json_decode($line,true);$allowedAudit[]=['id'=>$e['id'],'actor_user_id'=>$e['actor_user_id'],'action'=>$e['action'],'occurred_at'=>$e['occurred_at']];}}else $differences[]=$q;}$tables[$q]=['before_rows'=>count($before),'after_rows'=>count($after),'identical'=>$before===$after,'technical'=>$technicalTable,'before_sha256'=>hash('sha256',implode("\n",$before)),'after_sha256'=>hash('sha256',implode("\n",$after))];}
|
||||
$release=$root.'/outputs/investmoz-classificacao-multidimensional-QA-20261015';$m=json_decode(file_get_contents($release.'/MANIFESTO-ENTREGA.json'),true);$pre=json_decode(file_get_contents(__DIR__.'/PREFLIGHT.json'),true);
|
||||
foreach($pre['protected_files']as$n=>$h)if(hash_file('sha256',$root.'/'.$n)!==$h)throw new RuntimeException('Protected config changed');
|
||||
$baseline=json_decode(file_get_contents($release.'/ATIVO-FICHEIROS-ANTES.json'),true);$allowed=$phase==='final'?array_column($m['sources'],'path'):[];
|
||||
if($phase==='final')foreach($m['payload']as$f)if(str_starts_with($f['path'],'build/'))$allowed[]='public/'.$f['path'];
|
||||
$protected=0;foreach($baseline as$n=>$h){if(in_array($n,$allowed,true))continue;if(!is_file($root.'/'.$n)||hash_file('sha256',$root.'/'.$n)!==$h)throw new RuntimeException('Protected source or asset changed');$protected++;}
|
||||
foreach($m['sources']as$s){$f=$root.'/'.$s['path'];$expected=$phase==='final'?$s['candidate_sha256']:$s['previous_sha256'];if((is_file($f)?hash_file('sha256',$f):null)!==$expected)throw new RuntimeException('Source mismatch');}
|
||||
if($phase==='final')foreach($m['payload']as$f)if(str_starts_with($f['path'],'build/')&&hash_file('sha256',$root.'/public/'.$f['path'])!==$f['sha256'])throw new RuntimeException('Build mismatch');
|
||||
$private=json_decode(file_get_contents($b['private_directory'].'/backup-proof-private.json'),true);$verified=0;
|
||||
foreach($private['file_hashes']as$n=>$h){if(!str_starts_with($n,'storage/app/'))continue;if(!is_file($root.'/'.$n)||hash_file('sha256',$root.'/'.$n)!==$h)throw new RuntimeException('Managed private/public file changed');$verified++;}
|
||||
$documents=0;$preexistingMissing=0;$disk=config('filesystems.disks.local.root');foreach($clone->query('SELECT id,storage_key FROM documents WHERE storage_key IS NOT NULL')->fetchAll(PDO::FETCH_ASSOC)as$d){$key='storage-documents/'.$d['id'].'.stored';if(!isset($private['file_hashes'][$key])){$preexistingMissing++;continue;}if(!is_file($disk.'/'.$d['storage_key'])||hash_file('sha256',$disk.'/'.$d['storage_key'])!==$private['file_hashes'][$key])throw new RuntimeException('Original document bytes changed');$documents++;}
|
||||
$migration=(int)$active->query("SELECT count(*) FROM migrations WHERE migration='2026_10_09_190000_prepare_investor_path'")->fetchColumn();$env=Dotenv\Dotenv::parse(file_get_contents($root.'/.env'));if($migration!==1||!filter_var($env['INVESTOR_PATH_ENABLED']??false,FILTER_VALIDATE_BOOL)||!filter_var($env['PORTAL_LEGACY_CONTENT_ENABLED']??false,FILTER_VALIDATE_BOOL))throw new RuntimeException('B or flags changed');
|
||||
$proof=['at'=>gmdate('c'),'candidate'=>$m['candidate'],'phase'=>$phase,'read_only'=>true,'fresh_restore_comparison'=>$b['restore_target'],'tables_compared'=>count($tables),'business_tables_identical'=>$businessIdentical,'business_records_and_prior_history_preserved'=>!$differences,'expected_access_denial_audit_rows_added'=>$allowedAudit,'business_table_differences'=>$differences,'technical_tables_excluded_from_business_comparison'=>$technical,'protected_config_files_unchanged'=>count($pre['protected_files']),'protected_source_build_files_unchanged'=>$protected,'source_hashes_verified'=>17,'candidate_build_hashes_verified'=>$phase==='final'?count(array_filter($m['payload'],fn($f)=>str_starts_with($f['path'],'build/'))):0,'managed_private_public_files_verified'=>$verified,'original_documents_verified'=>$documents,'preexisting_unavailable_document_count'=>$preexistingMissing,'B_190000_count'=>$migration,'flags_unchanged'=>true,'migrations_run'=>0,'business_writes'=>0,'functional_acceptance_repeated'=>false,'tables'=>$tables];
|
||||
$file=__DIR__.'/PRESERVACAO-'.strtoupper($phase).'.json';if(is_file($file))throw new RuntimeException('Preserve proof');file_put_contents($file,json_encode($proof,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR).PHP_EOL);echo json_encode(array_diff_key($proof,array_flip(['tables'])),JSON_UNESCAPED_UNICODE).PHP_EOL;if($differences)exit(2);
|
||||
}finally{foreach([$active,$clone]as$db)$db->exec('ROLLBACK');}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
ini_set('zend.exception_ignore_args','1');
|
||||
set_exception_handler(function(Throwable $e){fwrite(STDERR,'Preservation verification stopped: '.$e::class.' line '.$e->getLine().PHP_EOL);exit(1);});
|
||||
$root=dirname(__DIR__,2);$phase=$argv[1]??'';if(!in_array($phase,['before','after'],true))throw new RuntimeException('Explicit phase');
|
||||
require $root.'/vendor/autoload.php';$app=require $root.'/bootstrap/app.php';(new Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables)->bootstrap($app);(new Illuminate\Foundation\Bootstrap\LoadConfiguration)->bootstrap($app);
|
||||
$c=config('database.connections.'.config('database.default'));if($c['database']!=='investemoz'||(int)$c['port']!==5432||!in_array($c['host'],['127.0.0.1','localhost'])||!empty($c['url']))throw new RuntimeException('Active identity');
|
||||
$b=json_decode(file_get_contents(__DIR__.'/FRESH-BACKUP.json'),true,512,JSON_THROW_ON_ERROR);$cloneName=$b['restore_target']['database'];if(!preg_match('/^classification_before_\d{8}_\d{6}_test$/D',$cloneName))throw new RuntimeException('Clone guard');
|
||||
$active=new PDO('pgsql:host='.$c['host'].';port=5432;dbname=investemoz',$c['username'],$c['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);$clone=new PDO('pgsql:host=127.0.0.1;port=55441;dbname='.$cloneName,'postgres','',[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
|
||||
foreach([$active,$clone]as$db){$db->exec('BEGIN ISOLATION LEVEL REPEATABLE READ READ ONLY');$db->exec("SET LOCAL TIME ZONE 'UTC'");}
|
||||
try{
|
||||
$technical=['sessions','cache','cache_locks','jobs','failed_jobs'];$tables=[];$differences=[];
|
||||
foreach($clone->query("SELECT schemaname,tablename FROM pg_tables WHERE schemaname NOT LIKE 'pg_%' AND schemaname <> 'information_schema' ORDER BY schemaname,tablename")->fetchAll(PDO::FETCH_ASSOC)as$t){$n=$t['tablename'];$q='"'.str_replace('"','""',$t['schemaname']).'"."'.str_replace('"','""',$n).'"';$sql='SELECT row_to_json(t)::text FROM '.$q.' t ORDER BY row_to_json(t)::text';$before=$clone->query($sql)->fetchAll(PDO::FETCH_COLUMN);$after=$active->query($sql)->fetchAll(PDO::FETCH_COLUMN);$technicalTable=in_array($n,$technical,true);if($before!==$after&&!$technicalTable)$differences[]=$q;$tables[$q]=['before_rows'=>count($before),'after_rows'=>count($after),'identical'=>$before===$after,'technical'=>$technicalTable,'before_sha256'=>hash('sha256',implode("\n",$before)),'after_sha256'=>hash('sha256',implode("\n",$after))];}
|
||||
$release=$root.'/outputs/investmoz-classificacao-multidimensional-QA-20261015';$m=json_decode(file_get_contents($release.'/MANIFESTO-ENTREGA.json'),true);$pre=json_decode(file_get_contents(__DIR__.'/PREFLIGHT.json'),true);
|
||||
foreach($pre['protected_files']as$n=>$h)if(hash_file('sha256',$root.'/'.$n)!==$h)throw new RuntimeException('Protected config changed');
|
||||
$baseline=json_decode(file_get_contents($release.'/ATIVO-FICHEIROS-ANTES.json'),true);$allowed=$phase==='after'?array_column($m['sources'],'path'):[];
|
||||
if($phase==='after')foreach($m['payload']as$f)if(str_starts_with($f['path'],'build/'))$allowed[]='public/'.$f['path'];
|
||||
$protected=0;foreach($baseline as$n=>$h){if(in_array($n,$allowed,true))continue;if(!is_file($root.'/'.$n)||hash_file('sha256',$root.'/'.$n)!==$h)throw new RuntimeException('Protected source or asset changed');$protected++;}
|
||||
foreach($m['sources']as$s){$f=$root.'/'.$s['path'];$expected=$phase==='after'?$s['candidate_sha256']:$s['previous_sha256'];if((is_file($f)?hash_file('sha256',$f):null)!==$expected)throw new RuntimeException('Source mismatch');}
|
||||
if($phase==='after')foreach($m['payload']as$f)if(str_starts_with($f['path'],'build/')&&hash_file('sha256',$root.'/public/'.$f['path'])!==$f['sha256'])throw new RuntimeException('Build mismatch');
|
||||
$private=json_decode(file_get_contents($b['private_directory'].'/backup-proof-private.json'),true);$verified=0;
|
||||
foreach($private['file_hashes']as$n=>$h){if(!str_starts_with($n,'storage/app/'))continue;if(!is_file($root.'/'.$n)||hash_file('sha256',$root.'/'.$n)!==$h)throw new RuntimeException('Managed private/public file changed');$verified++;}
|
||||
$documents=0;$preexistingMissing=0;$disk=config('filesystems.disks.local.root');foreach($clone->query('SELECT id,storage_key FROM documents WHERE storage_key IS NOT NULL')->fetchAll(PDO::FETCH_ASSOC)as$d){$key='storage-documents/'.$d['id'].'.stored';if(!isset($private['file_hashes'][$key])){$preexistingMissing++;continue;}if(!is_file($disk.'/'.$d['storage_key'])||hash_file('sha256',$disk.'/'.$d['storage_key'])!==$private['file_hashes'][$key])throw new RuntimeException('Original document bytes changed');$documents++;}
|
||||
$migration=(int)$active->query("SELECT count(*) FROM migrations WHERE migration='2026_10_09_190000_prepare_investor_path'")->fetchColumn();$env=Dotenv\Dotenv::parse(file_get_contents($root.'/.env'));if($migration!==1||!filter_var($env['INVESTOR_PATH_ENABLED']??false,FILTER_VALIDATE_BOOL)||!filter_var($env['PORTAL_LEGACY_CONTENT_ENABLED']??false,FILTER_VALIDATE_BOOL))throw new RuntimeException('B or flags changed');
|
||||
$proof=['at'=>gmdate('c'),'candidate'=>$m['candidate'],'phase'=>$phase,'read_only'=>true,'fresh_restore_comparison'=>$b['restore_target'],'tables_compared'=>count($tables),'business_tables_identical'=>!$differences,'business_table_differences'=>$differences,'technical_tables_excluded_from_business_comparison'=>$technical,'protected_config_files_unchanged'=>count($pre['protected_files']),'protected_source_build_files_unchanged'=>$protected,'source_hashes_verified'=>17,'candidate_build_hashes_verified'=>$phase==='after'?count(array_filter($m['payload'],fn($f)=>str_starts_with($f['path'],'build/'))):0,'managed_private_public_files_verified'=>$verified,'original_documents_verified'=>$documents,'preexisting_unavailable_document_count'=>$preexistingMissing,'B_190000_count'=>$migration,'flags_unchanged'=>true,'migrations_run'=>0,'business_writes'=>0,'functional_acceptance_repeated'=>false,'tables'=>$tables];
|
||||
$file=__DIR__.'/PRESERVACAO-'.strtoupper($phase).'.json';if(is_file($file))throw new RuntimeException('Preserve proof');file_put_contents($file,json_encode($proof,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR).PHP_EOL);echo json_encode(array_diff_key($proof,array_flip(['tables'])),JSON_UNESCAPED_UNICODE).PHP_EOL;if($differences)exit(2);
|
||||
}finally{foreach([$active,$clone]as$db)$db->exec('ROLLBACK');}
|
||||
+1901
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"before_sha256": "8676eb357665174964206f2f0a8b2e12499b17382ce8958569ded24c3f80386c",
|
||||
"after_sha256": "77ca8f755dc4f0e31baeb734421bb12007571d60c3dc2da14ccac581725af6bc",
|
||||
"rows": 3402,
|
||||
"changed_ids": [
|
||||
"M2-d0c06a75-0158",
|
||||
"M2-d0c06a75-0029",
|
||||
"RF-CLU-002",
|
||||
"RF-CLU-003",
|
||||
"RF-COR-003",
|
||||
"MASTER-e1169a77-0043",
|
||||
"MASTER-e1169a77-0062",
|
||||
"OP-9f173ed3-0165"
|
||||
],
|
||||
"other_raw_rows_preserved": 3394,
|
||||
"new_requirements": 0,
|
||||
"accepted_closed_items_reopened": 0,
|
||||
"active_application_changed": false,
|
||||
"global_requirements_closed_by_partial_delta": false
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"record_id": 7,
|
||||
"reference": "INV-MZ-GEN-4792200729732927",
|
||||
"chain_id": "48ef40dd-8553-43e1-b858-ea212db66bea",
|
||||
"relations": 9,
|
||||
"target": {
|
||||
"database": "classification_20261015_test",
|
||||
"port": 55441
|
||||
},
|
||||
"synthetic_only": true
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"result": "passed",
|
||||
"checks": {
|
||||
"nine_simultaneous_relations": true,
|
||||
"four_dimensions": true,
|
||||
"all_preliminary": true,
|
||||
"promoter_cannot_review_UI_metadata": true,
|
||||
"preliminary_save_without_editorial_transition": true,
|
||||
"repeated_save_no_relationship_duplicates": true,
|
||||
"new_session_recovers_all_values": true,
|
||||
"outsider_read_403": true,
|
||||
"outsider_edit_403": true,
|
||||
"author_self_confirmation_403": true,
|
||||
"outsider_confirmation_403": true,
|
||||
"reviewer_cannot_edit_promoter_draft": true,
|
||||
"duplicate_relation_422": true,
|
||||
"client_certification_422": true,
|
||||
"invalid_reference_visible_422_not_500": true,
|
||||
"benefit_grant_without_act_422": true,
|
||||
"independent_confirmation_200": true,
|
||||
"one_confirmation_other_eight_preliminary": true,
|
||||
"rejection_recorded": true,
|
||||
"confirmation_after_reasoned_rejection": true,
|
||||
"revocation_recorded": true,
|
||||
"new_reasoned_confirmation_preserves_history": true,
|
||||
"stale_decision_409": true,
|
||||
"incomplete_evidence_preliminary_save": true,
|
||||
"incomplete_evidence_confirmation_422": true,
|
||||
"restore_original_relation_content": true,
|
||||
"public_fixture_explicitly_not_editorial_retest": true,
|
||||
"public_detail_API_200": true,
|
||||
"public_eight_relations_excludes_reserved": true,
|
||||
"benefit_not_presented_available": true,
|
||||
"documents_authors_private": true,
|
||||
"combined_filters_AND_across_relations": true,
|
||||
"restricted_opportunity_excluded": true,
|
||||
"listing_HTTP200": true,
|
||||
"promoter_login": true,
|
||||
"reviewer_login": true,
|
||||
"reviewer_MFA_completed": true,
|
||||
"map_count_matches_catalogue": true,
|
||||
"mismatched_confirmation_zero": true,
|
||||
"draft_correction_save": true,
|
||||
"corrected_relation_not_automatically_confirmed": true,
|
||||
"private_draft_correction_not_public": true,
|
||||
"revoke_previous_published_version_after_draft_correction": true,
|
||||
"revoked_relation_removed_from_filter": true
|
||||
},
|
||||
"count": 44,
|
||||
"record_id": 7,
|
||||
"public_fixture": {
|
||||
"synthetic_public_fixture": true,
|
||||
"observed_editorial_transition": false,
|
||||
"record_id": 7,
|
||||
"slug": "inv-mz-gen-4792200729732927",
|
||||
"restricted_fixture_id": 8
|
||||
},
|
||||
"editorial_workflow_retested": false,
|
||||
"active_changes": 0
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"provenance": "Observed prior execution reached map response shape assertion. Test field corrected from total to existing matched_count. No application map change.",
|
||||
"assertions_completed": [
|
||||
"nine_simultaneous_relations",
|
||||
"four_dimensions",
|
||||
"all_preliminary",
|
||||
"promoter_cannot_review_UI_metadata",
|
||||
"preliminary_save_without_editorial_transition",
|
||||
"repeated_save_no_relationship_duplicates",
|
||||
"new_session_recovers_all_values",
|
||||
"outsider_read_403",
|
||||
"outsider_edit_403",
|
||||
"author_self_confirmation_403",
|
||||
"outsider_confirmation_403",
|
||||
"reviewer_cannot_edit_promoter_draft",
|
||||
"duplicate_relation_422",
|
||||
"client_certification_422",
|
||||
"invalid_reference_visible_422_not_500",
|
||||
"benefit_grant_without_act_422",
|
||||
"independent_confirmation_200",
|
||||
"one_confirmation_other_eight_preliminary",
|
||||
"rejection_recorded",
|
||||
"confirmation_after_reasoned_rejection",
|
||||
"revocation_recorded",
|
||||
"new_reasoned_confirmation_preserves_history",
|
||||
"stale_decision_409",
|
||||
"incomplete_evidence_preliminary_save",
|
||||
"incomplete_evidence_confirmation_422",
|
||||
"restore_original_relation_content",
|
||||
"public_fixture_explicitly_not_editorial_retest",
|
||||
"public_detail_API_200",
|
||||
"public_eight_relations_excludes_reserved",
|
||||
"benefit_not_presented_available",
|
||||
"documents_authors_private",
|
||||
"combined_filters_AND_across_relations",
|
||||
"restricted_opportunity_excluded",
|
||||
"listing_HTTP200"
|
||||
],
|
||||
"public_fixture_prepared": true
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"viewport_mobile": {
|
||||
"component_width": 309,
|
||||
"scroll_width": 309,
|
||||
"width": 390
|
||||
},
|
||||
"invalid_reference_preserved": true,
|
||||
"error_message": "Identificador de referência inválido.",
|
||||
"keyboard_next_label": "Finalidade",
|
||||
"error_focus": {
|
||||
"description": "canonical.relations.0.related_id-error",
|
||||
"index": "0",
|
||||
"invalid": "true"
|
||||
},
|
||||
"public_four_dimensions": true,
|
||||
"private_marker_absent": true,
|
||||
"public_benefit_not_inferred": true,
|
||||
"viewport_override_reset": true,
|
||||
"result": "passed"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# Pacote exclusivamente para revisão
|
||||
|
||||
Candidata `classificacao-multidimensional-QA-64ab05e20b95`. Preparação QA autorizada; disponibilização ativa não autorizada.
|
||||
|
||||
`fontes/`: as 17 fontes propostas. `build/`: compilação correspondente. `reversao-anterior/`: 14 fontes anteriores para comparação; o build anterior deve vir do backup fresco da janela. `reversao-compat/`: contrato anterior com aceitação do campo opcional já utilizado. `documentos/`: âmbito, limites e proposta única. `provas/`: resultados e roteiros guardados de QA, que não são componentes de instalação.
|
||||
|
||||
Não instalar documentação/roteiros/fixtures nem transportar base, .env, sessões ou credenciais. Não executar as provas contra o ativo. Conferir todos os hashes com o manifesto e a autorização nominal antes de qualquer troca. A disponibilidade da biblioteca, a confirmação de associação, o workflow editorial e atos externos permanecem independentes.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+28
@@ -0,0 +1,28 @@
|
||||
# Procedimento proposto — classificação multidimensional
|
||||
|
||||
Candidata: `classificacao-multidimensional-QA-64ab05e20b95`.
|
||||
|
||||
**Preparado, não autorizado para o ativo.** O manifesto/recibo identificam a revisão exata e distinguem 14 fontes anteriores e três ausências. Não transportar fixtures, bases, `.env`, sessões, credenciais, bootstrap QA, vendor/node_modules ou classificações sintéticas.
|
||||
|
||||
1. Com autorização expressa da candidata concreta, conferir o destino `portal-investidor.test`, sem a porta QA, e a identidade da base ativa esperada. Comparar as 14 fontes e o build com os hashes anteriores do manifesto e confirmar as três ausências. Se divergirem, parar a troca e reconciliar somente a divergência; nunca sobrescrever trabalho posterior sem avaliação.
|
||||
2. Preparar backup fresco, consistente, da base, fontes/build, ficheiros privados e configuração. Restaurar em clone isolado `*_test`, conferir tabelas/sequências/ficheiros e arranque. Usar o procedimento de backup/restauro já instalado; não chamar migrations ou dados seed. Guardar os hashes e o mapa de versões do destino. Esse backup será próximo da execução, não o clone QA desta preparação.
|
||||
3. Registar início da janela, confirmar ausência de alterações concorrentes e entrar em manutenção pelo procedimento existente. Entregar as 17 fontes e a compilação **coerente completa** identificada no recibo. Sem migrations, instalação de catálogos, importação/publicação de recursos ou mudança de flags. A decisão de associação continua a usar a sessão autenticada normal; nenhum ator é simulado no ativo.
|
||||
4. Com a aplicação ainda em manutenção, usar o PHP e a raiz do destino confirmados no preflight. Registar antes da troca se o destino usa cache de configuração, cache de rotas e pré-compilação de vistas, e os respetivos caminhos efetivos. Executar separadamente `php artisan config:clear`, `php artisan route:clear` e `php artisan view:clear`; confirmar que o caminho de vistas compiladas é exclusivo de vistas e não contém a cache de dados. Recriar apenas os caches que já eram usados: `php artisan config:cache`, depois `php artisan route:cache` e/ou `php artisan view:cache`, conforme o registo do destino; onde não eram usados, manter a geração normal sob pedido. Conferir o resultado de cada comando; em caso de erro, manter a manutenção e aplicar a reversão correspondente. **Preservar a cache de dados: não executar `optimize:clear`, `cache:clear` nem uma otimização global.** Confirmar PHP e dependências existentes. Sair da manutenção antes de qualquer conferência pela interface autenticada. Não existe etapa de instalador nesta candidata.
|
||||
5. Conferir arranque/rotas/assets e consulta pública anterior; conferir a disponibilidade do novo editor com a conta já autorizada, sem gravar/classificar anúncio real, criar fixture ou repetir transições aceites. B, COUNTRY02, publicações, permissões e dados conservam-se. Emissão de recibo com hashes entregues, backup/restauro e eventuais diferenças observadas. Novas relações reais/publicações exigem a ação operacional normal do responsável e o workflow já aprovado.
|
||||
|
||||
## Reversão sem perda de dados utilizados
|
||||
|
||||
- Antes de nova utilização, se só houve troca de ficheiros, restaurar as 14 fontes anteriores e o build fresco anterior; retirar os três ficheiros novos somente se ainda tiverem os hashes entregues e deixarem de ser referenciados. Não tocar em dados.
|
||||
- **Depois de qualquer gravação que contenha os campos novos, a simples restauração integral do contrato anterior não basta:** rejeitaria `enterprise_size`. Nesse caso restaurar as 13 fontes anteriores restantes e usar `reversao-compat/app/Services/OpportunityCanonicalContract.php`, identificado por hash no manifesto. É o contrato anterior com aceitação do único campo raiz opcional já gravado. A coleção anterior `relations` já aceita os objetos preservados; o workflow JSON conserva decisões, publicação e histórico. Não ativa a interface, endpoints de confirmação, papéis ou benefícios novos.
|
||||
- Restaurar o build anterior completo, sem deixar o HTML/manifest novo a apontar para chunks ausentes. Retirar as três novas fontes por hash somente após restauro das referências. Guardar cópia dos ficheiros retirados no backup da janela. Ainda em manutenção, repetir a limpeza específica de configuração, rotas e vistas do passo 4 e reconstruir apenas os caches usados no destino antes da janela. Preservar a cache de dados; só sair da manutenção após sucesso e conferência do arranque com o contrato adequado ao estado dos dados.
|
||||
- Manter `management_draft`, `workflow_context`, identidades dos itens, decisões e auditoria. Nenhuma renumeração, limpeza de JSON, fusão ou `migrate:rollback/down`. O código anterior deixa de apresentar a funcionalidade; os dados continuam recuperáveis. Eventual republicação pelo workflow anterior pode conservar a projeção anterior no histórico de publicação, sem a apagar.
|
||||
- Restaurar a base inteira só se não houve utilização posterior e a reconciliação confirmar ausência de dados novos; depois de utilização, preferir reversão de código compatível e reconciliação nominal. Não perder operações posteriores para recuperar uma fotografia antiga.
|
||||
- A compatibilidade acima foi demonstrada no clone QA com seis verificações, incluindo arranque e gravação transacional do payload já utilizado; o registo ficou exatamente igual após rollback da transação de prova. Não foi feito ensaio HTTP/visual integral da reversão.
|
||||
|
||||
## Origem das restrições
|
||||
|
||||
QA/ativo separados, preservação de B/COUNTRY02/dados e decisão futura da disponibilização: instrução expressa da Tempo. Papéis, MFA e independência: política v1 anterior aprovada. Hash/ETag, contrato aditivo, projeção congelada e compatibilidade de reversão: escolhas técnicas para executar o pedido, sem criar exigência organizacional nova. A ausência de fonte/citação impede anunciar confirmação desta associação; não impede guardar preparação nem revoga a fonte oficial aceite.
|
||||
|
||||
## Revisão documental DOC01 — 15/10/2026
|
||||
|
||||
Substituída a limpeza global por comandos específicos de configuração, rotas e vistas, com preservação da cache de dados e aplicação também à reversão. A inspeção do código Laravel instalado confirmou que `optimize:clear` inclui `cache:clear`; nenhum comando Artisan foi executado nesta revisão. Mantêm-se as 17 fontes, a compilação, o contrato de compatibilidade após utilização e as provas QA anteriores. A estimativa permanece 45–90 + 20–40 + 25–50 = **90–180 minutos (1h30–3h)**. `/negocios`, ficha operacional integral dos parques, referências económicas em falta, consolidação de duplicados e regulação Fintech completa continuam abertos na matriz. Não há autorização de disponibilização no ativo. A versão documental anterior permanece arquivada em DOC00.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Proposta única à Tempo — classificação multidimensional
|
||||
|
||||
Candidata: `classificacao-multidimensional-QA-64ab05e20b95`.
|
||||
|
||||
**Decisão pedida sobre o pacote e recibo anexos; nenhuma ativação autorizada por esta preparação.**
|
||||
|
||||
Disponibilizar a candidata identificada no manifesto/recibo: **17 fontes (14 substituições e três novas), compilação correspondente e contrato de reversão compatível**. O delta permite múltiplas associações territoriais, produtivas, regulatórias e económicas no cadastro canónico existente, evidência/decisão por relação e consulta/filtros públicos pela projeção editorial aprovada. Nenhuma migration, categoria, papel, flag, importação, publicação de artigo, nova regra fiscal ou alteração de classificações reais integra a execução operacional.
|
||||
|
||||
Executar com backup/restauro fresco, preflight nominal, troca em manutenção e reversão descrita em `PROCEDIMENTO-E-REVERSAO.md`. Preservar B, COUNTRY02, biblioteca, Fintech, cinco fases/19 etapas, dados e histórico. Não repetir a auditoria dos 12 critérios. Não transportar testes/atores/credenciais ou dados QA.
|
||||
|
||||
A Tempo deve avaliar expressamente estes limites do recorte: implementação em `Opportunity`/`/minhas-oportunidades`/`/oportunidades`; sem migração automática dos anúncios UUID de `/negocios`; sem ficha operacional integral de contratos/lotes/custos/capacidade de parques; sem inventar referências económicas ausentes ou completar o enquadramento regulatório Fintech; deduplicação de candidatos por título exato, sem fusão; filtros dinâmicos sem ensaio de carga. A publicação sintética prova a projeção nova e não repete a transição editorial; a reversão foi verificada por arranque/contrato/gravação transacional, sem percurso HTTP/visual integral.
|
||||
|
||||
O recibo liga as fontes, documentação, provas e ZIP; a verificação local não implica que a Tempo tenha inspecionado o ZIP ou aceite a interface. A autorização futura pode aceitar este recorte ou pedir complemento nominal, sem reabrir B ou descartar as confirmações já aceites.
|
||||
|
||||
Saldo operacional estimado após decisão: **1h30–3h**, incluindo backup/restauro fresco, troca e conferência operacional. A estimativa anterior 8–13 h pertencia à preparação QA; não é saldo repetido nem medição de trabalho realizado.
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"synthetic_public_fixture": true,
|
||||
"observed_editorial_transition": false,
|
||||
"record_id": 7,
|
||||
"slug": "inv-mz-gen-4792200729732927",
|
||||
"restricted_fixture_id": 8
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 165 KiB |
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"database": "classification_20261015_test",
|
||||
"host": "127.0.0.1",
|
||||
"port": 55441,
|
||||
"source": "C:\\Users\\macbook\\.config\\investmoz\\classificacao-QA-20261015\\source",
|
||||
"url": "http://127.0.0.1:18519",
|
||||
"dump_sha256": "76394f3c07cd70c3932df267bd49a083f4d5e6e1126cd09e7b1ad5b803713012",
|
||||
"active_source_count": 1899,
|
||||
"active_changed": false
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user