feat: add workforce evidence and sourced economic context map layers
This commit is contained in:
@@ -538,11 +538,12 @@ class InvestmentCatalogue
|
||||
}
|
||||
$public = app(ProactiveInvestment::class)->publicData($record);
|
||||
$evidence = array_values(array_filter(StructuredData::collectionItems($public['evidence'] ?? []),
|
||||
fn ($proof) => in_array($proof['category'] ?? null, ['resource', 'infrastructure'], true) && ($proof['purpose'] ?? null) === 'local'));
|
||||
fn ($proof) => in_array($proof['category'] ?? null, ['resource', 'infrastructure', 'workforce', 'activity', 'supply', 'demand'], true) && ($proof['purpose'] ?? null) === 'local'));
|
||||
if ($evidence !== []) {
|
||||
$thematic[] = ['id' => $record->id, 'title' => $record->title, 'url' => $properties['url'], 'location' => $properties['location'],
|
||||
'state' => $public['state'] ?? 'hypothesis', 'limitations' => $public['limitations'] ?? null,
|
||||
'evidence' => array_map(fn ($proof) => array_intersect_key($proof, array_flip(['id', 'category', 'statement', 'source', 'locator', 'period', 'scope', 'coverage', 'verified_on'])), $evidence)];
|
||||
'evidence' => array_map(fn ($proof) => [...array_intersect_key($proof, array_flip(['id', 'statement', 'source', 'locator', 'period', 'scope', 'coverage', 'verified_on'])),
|
||||
'source_category' => $proof['category'], 'category' => in_array($proof['category'], ['activity', 'supply', 'demand'], true) ? 'economic_potential' : $proof['category']], $evidence)];
|
||||
}
|
||||
$sites = collect($points->get($record->id) ?? []);
|
||||
if ($sites->isNotEmpty()) {
|
||||
|
||||
@@ -33,7 +33,7 @@ final class ProactiveInvestment
|
||||
'proactive.evidence.*.observation_id' => 'sometimes|nullable|string|size:64',
|
||||
'proactive.supply_comparisons' => 'sometimes|array|max:40',
|
||||
'proactive.evidence.*.id' => 'required|uuid|distinct',
|
||||
'proactive.evidence.*.category' => 'required|in:activity,resource,infrastructure,supply,demand',
|
||||
'proactive.evidence.*.category' => 'required|in:activity,resource,infrastructure,supply,demand,workforce',
|
||||
'proactive.evidence.*.purpose' => 'required|in:local,methodology',
|
||||
'proactive.evidence.*.access' => 'required|in:internal,public',
|
||||
'proactive.evidence.*.document_id' => 'nullable|uuid',
|
||||
|
||||
@@ -2243,3 +2243,18 @@ Delta aprovado: oito testes de BD/438 asserções (quatro novos e quatro de filt
|
||||
Conferência visual no Edge exclusivamente em `127.0.0.2:18644`, base `main_visual_20261104_test`: duas fixtures claramente sintéticas criadas apenas em QA, uma por categoria; nenhuma coordenada/geometria criada. Hash de todas as oportunidades anteriores idêntico antes/depois. Alternância entre ambas conserva pesquisa provincial e duas fichas gerais; cada camada mostra a sua ficha, fonte/período/âmbito/limites e ausência de ponto. Infra-estruturas recuperada após recarregar. Recibo: `docs/investmoz/unification/thematic-map-local-20261104.json`; inventário, hashes, DOM e capturas em `outputs/thematic-map-20261104/`. Demonstração sintética não constitui cobertura económica factual ou publicação de dados reais.
|
||||
|
||||
**ACT-02 permanece parcial.** Cobertura factual de recursos/infra-estruturas no destino, georreferenciação própria quando documentada, mão-de-obra, potencial económico quantitativo, restantes fontes temáticas e lacunas cartográficas continuam pendentes. Não se inferem estas camadas de descrições nem do número de oportunidades. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, alteração activa, migração, publicação automática ou alteração de permissões/serviços.
|
||||
|
||||
|
||||
### 04/11/2026 — ACT-20261029-02: mão-de-obra documentada e contexto económico
|
||||
|
||||
Incremento qualitativo na main local sobre `21ebad73`, reutilizando mapa, evidências, síntese publicada, divulgação expressa e fontes/períodos existentes. Inventário na cópia QA: duas evidências públicas locais de actividade anteriores (fichas sintéticas 350/383), nenhuma de mão-de-obra/oferta/procura; recursos/infra-estruturas da demonstração anterior conservados. As declarações labour_demands/training_capacities têm acesso EducationAccess interno; emprego/indicadores financeiros canónicos não fazem parte da publicProjection. Observações de zonas conservam divulgação/unidades/metodologia próprias. Não foram expostas nem agregadas essas fontes privadas por existir revisão interna. As fontes oficiais aceites e as decisões de divulgação anteriores não foram reabertas.
|
||||
|
||||
Acrescentada categoria explícita Mão-de-obra no editor e validação da evidência existente, sem migração ou reclassificação automática dos textos anteriores. Guardar, recuperar, pré-visualizar e confirmar publicação usam o percurso existente. A camada económica reutiliza apenas evidências públicas locais de actividade/oferta/procura, mantendo `source_category` original, facto, fonte, localizador, período, verificação, âmbito, cobertura e limitações. Agrupá-las para consulta é uma escolha de apresentação, não aprovação de viabilidade nem índice de potencial.
|
||||
|
||||
Ambas as opções entram no selector do mapa único; a escolha é recuperada na sessão. Recursos/infra-estruturas, geometrias públicas, filtros territoriais, fichas sem ponto e contagens anteriores mantêm-se. Nenhuma posição é criada ou atribuída ao recurso/mão-de-obra. Necessidade ou qualificação não equivale a trabalhador disponível; previsão de emprego não é emprego efectivo. Contexto económico não calcula retorno, score ou viabilidade. Períodos/fontes incompatíveis permanecem separados, sem totais ou zero presumido.
|
||||
|
||||
Delta aprovado: sete testes de BD/77 asserções (cinco do mapa, incluindo o novo caso; dois de publicação, um novo e um de acesso/fonte privada já existente), 22 testes frontend, PHPStan sem erros, tipos, Pint, lint e build QA aprovados. Teste do percurso: criar evidência workforce → recuperar → confirmar pela publicação existente → consultar mapa → alterar rascunho privado sem substituir a categoria/fonte públicas. Testes mantêm metodologia/internos fora do mapa, categorias originais, períodos distintos e ausência de quantidades/índices inferidos. Não se repetiu a bateria geral aceite.
|
||||
|
||||
Conferência visual no Edge exclusivamente na QA `127.0.0.2:18644`/`main_visual_20261104_test`: contexto económico reutiliza a evidência de actividade já publicada da ficha 383, sintética e explicitamente identificada. Mão-de-obra usa uma única fixture nova, também sintética; escolha e fonte recuperadas após recarregar. Nenhuma coordenada/geometria criada; hash de todas as oportunidades anteriores idêntico antes/depois. Conferidos 36 artefactos dos três recibos anteriores, todos com SHA256 inalterado. Recibo: `docs/investmoz/unification/workforce-economic-map-local-20261104.json`; inventário, DOM, capturas e hashes em `outputs/workforce-economic-map-20261104/`.
|
||||
|
||||
**ACT-02 permanece parcial.** Cobertura factual laboral/económica, séries, unidades e metodologia quantitativa comparável, georreferenciação própria documentada e cobertura cartográfica continuam pendentes. A demonstração sintética não mede oferta laboral nem potencial regional real. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, migração, publicação automática, escrita activa, alteração de permissões ou reinício de serviços.
|
||||
|
||||
@@ -9139,3 +9139,18 @@ Delta aprovado: oito testes de BD/438 asserções (quatro novos e quatro de filt
|
||||
Conferência visual no Edge exclusivamente em `127.0.0.2:18644`, base `main_visual_20261104_test`: duas fixtures claramente sintéticas criadas apenas em QA, uma por categoria; nenhuma coordenada/geometria criada. Hash de todas as oportunidades anteriores idêntico antes/depois. Alternância entre ambas conserva pesquisa provincial e duas fichas gerais; cada camada mostra a sua ficha, fonte/período/âmbito/limites e ausência de ponto. Infra-estruturas recuperada após recarregar. Recibo: `docs/investmoz/unification/thematic-map-local-20261104.json`; inventário, hashes, DOM e capturas em `outputs/thematic-map-20261104/`. Demonstração sintética não constitui cobertura económica factual ou publicação de dados reais.
|
||||
|
||||
**ACT-02 permanece parcial.** Cobertura factual de recursos/infra-estruturas no destino, georreferenciação própria quando documentada, mão-de-obra, potencial económico quantitativo, restantes fontes temáticas e lacunas cartográficas continuam pendentes. Não se inferem estas camadas de descrições nem do número de oportunidades. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, alteração activa, migração, publicação automática ou alteração de permissões/serviços.
|
||||
|
||||
|
||||
### 04/11/2026 — ACT-20261029-02: mão-de-obra documentada e contexto económico
|
||||
|
||||
Incremento qualitativo na main local sobre `21ebad73`, reutilizando mapa, evidências, síntese publicada, divulgação expressa e fontes/períodos existentes. Inventário na cópia QA: duas evidências públicas locais de actividade anteriores (fichas sintéticas 350/383), nenhuma de mão-de-obra/oferta/procura; recursos/infra-estruturas da demonstração anterior conservados. As declarações labour_demands/training_capacities têm acesso EducationAccess interno; emprego/indicadores financeiros canónicos não fazem parte da publicProjection. Observações de zonas conservam divulgação/unidades/metodologia próprias. Não foram expostas nem agregadas essas fontes privadas por existir revisão interna. As fontes oficiais aceites e as decisões de divulgação anteriores não foram reabertas.
|
||||
|
||||
Acrescentada categoria explícita Mão-de-obra no editor e validação da evidência existente, sem migração ou reclassificação automática dos textos anteriores. Guardar, recuperar, pré-visualizar e confirmar publicação usam o percurso existente. A camada económica reutiliza apenas evidências públicas locais de actividade/oferta/procura, mantendo `source_category` original, facto, fonte, localizador, período, verificação, âmbito, cobertura e limitações. Agrupá-las para consulta é uma escolha de apresentação, não aprovação de viabilidade nem índice de potencial.
|
||||
|
||||
Ambas as opções entram no selector do mapa único; a escolha é recuperada na sessão. Recursos/infra-estruturas, geometrias públicas, filtros territoriais, fichas sem ponto e contagens anteriores mantêm-se. Nenhuma posição é criada ou atribuída ao recurso/mão-de-obra. Necessidade ou qualificação não equivale a trabalhador disponível; previsão de emprego não é emprego efectivo. Contexto económico não calcula retorno, score ou viabilidade. Períodos/fontes incompatíveis permanecem separados, sem totais ou zero presumido.
|
||||
|
||||
Delta aprovado: sete testes de BD/77 asserções (cinco do mapa, incluindo o novo caso; dois de publicação, um novo e um de acesso/fonte privada já existente), 22 testes frontend, PHPStan sem erros, tipos, Pint, lint e build QA aprovados. Teste do percurso: criar evidência workforce → recuperar → confirmar pela publicação existente → consultar mapa → alterar rascunho privado sem substituir a categoria/fonte públicas. Testes mantêm metodologia/internos fora do mapa, categorias originais, períodos distintos e ausência de quantidades/índices inferidos. Não se repetiu a bateria geral aceite.
|
||||
|
||||
Conferência visual no Edge exclusivamente na QA `127.0.0.2:18644`/`main_visual_20261104_test`: contexto económico reutiliza a evidência de actividade já publicada da ficha 383, sintética e explicitamente identificada. Mão-de-obra usa uma única fixture nova, também sintética; escolha e fonte recuperadas após recarregar. Nenhuma coordenada/geometria criada; hash de todas as oportunidades anteriores idêntico antes/depois. Conferidos 36 artefactos dos três recibos anteriores, todos com SHA256 inalterado. Recibo: `docs/investmoz/unification/workforce-economic-map-local-20261104.json`; inventário, DOM, capturas e hashes em `outputs/workforce-economic-map-20261104/`.
|
||||
|
||||
**ACT-02 permanece parcial.** Cobertura factual laboral/económica, séries, unidades e metodologia quantitativa comparável, georreferenciação própria documentada e cobertura cartográfica continuam pendentes. A demonstração sintética não mede oferta laboral nem potencial regional real. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, migração, publicação automática, escrita activa, alteração de permissões ou reinício de serviços.
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
{
|
||||
"date": "2026-11-04",
|
||||
"base_commit": "21ebad73",
|
||||
"requirement": "ACT-20261029-02; V2-07/V2-10",
|
||||
"scope": "Incremento qualitativo de mão-de-obra e contexto do potencial económico; main local",
|
||||
"source_inventory": {
|
||||
"database": "main_visual_20261104_test",
|
||||
"public_local_evidence": {
|
||||
"resource": 1,
|
||||
"infrastructure": 1,
|
||||
"workforce": 0,
|
||||
"activity": 2,
|
||||
"supply": 0,
|
||||
"demand": 0
|
||||
},
|
||||
"private_sources_not_disclosed": [
|
||||
"labour_demands/training_capacities: EducationAccess authorization",
|
||||
"canonical employment and financial payloads: not part of publicProjection",
|
||||
"zone observations: separate disclosure/units/methodology; not automatically mixed with opportunity evidence"
|
||||
],
|
||||
"existing_economic_sources": [
|
||||
{
|
||||
"opportunity_id": 383,
|
||||
"title": "SYNTHETIC QA — ideia de apoio em Cahora Bassa",
|
||||
"category": "activity",
|
||||
"source": "SYNTHETIC QA exemplar público da interface",
|
||||
"period": "2026 — cenário sintético",
|
||||
"scope": "Cahora Bassa — referência distrital existente"
|
||||
},
|
||||
{
|
||||
"opportunity_id": 350,
|
||||
"title": "SYNTHETIC QA — ideia de apoio em Cahora Bassa",
|
||||
"category": "activity",
|
||||
"source": "SYNTHETIC QA exemplar público da interface",
|
||||
"period": "2026 — cenário sintético",
|
||||
"scope": "Cahora Bassa — referência distrital existente"
|
||||
}
|
||||
]
|
||||
},
|
||||
"implementation": [
|
||||
"Categoria workforce no editor/validação existentes; mesmos campos de fonte, período, âmbito e divulgação expressa.",
|
||||
"Mapeamento de activity/supply/demand já públicos para a camada economic_potential, conservando source_category e cada fonte/período.",
|
||||
"Apenas evidência publicada, seleccionada e de propósito local; rascunhos privados e metodologia excluídos.",
|
||||
"Escolha de ambas as novas camadas recuperável na sessão; pontos/áreas limitados aos locais existentes das oportunidades.",
|
||||
"Sem unidades, quantidades, disponibilidade laboral, índices ou retorno calculados a partir dos textos; sem agregação de períodos/fontes incompatíveis."
|
||||
],
|
||||
"existing_private_sources": [
|
||||
"EducationAccess protege labour_demands/training_capacities; revisão interna não é publicação.",
|
||||
"OpportunityCanonicalContract::publicProjection não divulga emprego/indicadores financeiros privados.",
|
||||
"Observações de zonas conservam divulgação, unidades e metodologia próprias; não foram automaticamente misturadas."
|
||||
],
|
||||
"contract": {
|
||||
"route": "GET /api/v1/investment/map",
|
||||
"field": "thematic_records.evidence",
|
||||
"new_categories": [
|
||||
"workforce",
|
||||
"economic_potential"
|
||||
],
|
||||
"source_category": "categoria original explícita; recursos/infra-estruturas mantêm categoria anterior",
|
||||
"version_compatibility": "Campos/fichas/históricos anteriores conservados; adição de categoria no rascunho existente, sem migração"
|
||||
},
|
||||
"checks": {
|
||||
"database_tests": 7,
|
||||
"database_assertions": 77,
|
||||
"map_tests": 5,
|
||||
"publication_tests": 2,
|
||||
"frontend_tests": 22,
|
||||
"phpstan_errors": 0,
|
||||
"types": "passed",
|
||||
"pint": "passed",
|
||||
"lint": "passed",
|
||||
"qa_build": "passed; avisos de fonte opcional e dimensão de chunks"
|
||||
},
|
||||
"visual": {
|
||||
"url_base": "http://127.0.0.2:18644",
|
||||
"database": "main_visual_20261104_test",
|
||||
"economic_existing_opportunity_id": 383,
|
||||
"economic_source_reused": "Evidência de actividade já pública, explicitamente sintética no snapshot QA; original preservado.",
|
||||
"new_workforce_fixture_ids": [
|
||||
534
|
||||
],
|
||||
"workforce_recovered_after_reload": true,
|
||||
"new_coordinates": false,
|
||||
"new_geometry": false,
|
||||
"existing_opportunities_sha256": "90aaee1f9e47bb7793e18746fb1f6935bfb0a21329deca9c569707fadd2c04c6"
|
||||
},
|
||||
"preservation": {
|
||||
"prior_artifact_hashes_verified_unchanged": 36,
|
||||
"accepted_full_database_tests_preserved_not_reexecuted": 1325,
|
||||
"previous_pending_items_retained": true
|
||||
},
|
||||
"pending": [
|
||||
"Cobertura factual laboral e económica real, séries comparáveis, unidades e metodologia quantitativa permanecem pendentes.",
|
||||
"A camada económica é contexto documental, sem classificação de viabilidade ou score regional.",
|
||||
"Procura de trabalho, formação, empregos previstos e trabalhadores disponíveis não são intercambiáveis.",
|
||||
"Conferência remota, aceitação da equipa e cobertura cartográfica permanecem pendentes; ACT-02/V2-07/V2-10 não encerrados."
|
||||
],
|
||||
"safety": {
|
||||
"push": false,
|
||||
"active_database_changed": false,
|
||||
"migration": false,
|
||||
"permissions_changed": false,
|
||||
"automatic_publication": false,
|
||||
"services_restarted": false
|
||||
},
|
||||
"proofs": {
|
||||
"outputs/workforce-economic-map-20261104/source-inventory-before-fixtures.json": {
|
||||
"sha256": "cd8a8943bf86778e041cc3f2ced51467d44e6e83147c8a8215024a27431d2964",
|
||||
"bytes": 1313
|
||||
},
|
||||
"outputs/workforce-economic-map-20261104/fixture-receipt.json": {
|
||||
"sha256": "7d680fed74a70d4367f1a7d8e0af60a0b7c5e5f89bc3ff4a17be5e119d294dc0",
|
||||
"bytes": 405
|
||||
},
|
||||
"outputs/workforce-economic-map-20261104/existing-economic-context.jpg": {
|
||||
"sha256": "6f81b29cbefad611b035fe26324d4b876d5dd5a9499a6fbd8ee75e8b4416aec5",
|
||||
"bytes": 157445
|
||||
},
|
||||
"outputs/workforce-economic-map-20261104/existing-economic-context.dom.txt": {
|
||||
"sha256": "1eb2687e9a3e73f4b3ed9808a9328930c54ca08dd6270e7d2e7bff1cfbef7227",
|
||||
"bytes": 20535
|
||||
},
|
||||
"outputs/workforce-economic-map-20261104/workforce-reopened.jpg": {
|
||||
"sha256": "b4c919ca4bfc344cd4feb5adcbe4a483d241d549d75450ee62a8b3854ccc6f34",
|
||||
"bytes": 161166
|
||||
},
|
||||
"outputs/workforce-economic-map-20261104/workforce-reopened.dom.txt": {
|
||||
"sha256": "01c6081409ea36d88e01d1c8b9af558eb497e68b596fe8be1b45cdec437c7515",
|
||||
"bytes": 13566
|
||||
},
|
||||
"outputs/main-db-qa-20261104/workforce-economic-map.log": {
|
||||
"sha256": "c6fb7cddb76a2589f3c41dc3d144b0387573417ddd9afcff96f331b801f53c0f",
|
||||
"bytes": 94
|
||||
},
|
||||
"outputs/main-db-qa-20261104/workforce-economic-map.junit.xml": {
|
||||
"sha256": "5824abb4aaa07c37e9420802d82a8ed08c4cd1babc76c337043016eb098f37ec",
|
||||
"bytes": 2374
|
||||
},
|
||||
"outputs/main-db-qa-20261104/workforce-publication.log": {
|
||||
"sha256": "3b0cb219fb68177a1a026ac7c076fe0da81f40c20aa6a8415a54866a08895c9d",
|
||||
"bytes": 95
|
||||
},
|
||||
"outputs/main-db-qa-20261104/workforce-publication.junit.xml": {
|
||||
"sha256": "7ad274166f6520990241a82530c51ac662540907bcc831c83889190176a80eaf",
|
||||
"bytes": 958
|
||||
},
|
||||
"outputs/main-db-qa-20261104/workforce-economic-frontend.log": {
|
||||
"sha256": "02dc96a1acd6887ac3fdc282562e8e5579e05bcf29283330effdf5689619ee09",
|
||||
"bytes": 2811
|
||||
},
|
||||
"outputs/main-db-qa-20261104/workforce-economic-phpstan.log": {
|
||||
"sha256": "1997495ca8f04c2ec09798d55607d1a2f85e3338b772f258666465bf658032d2",
|
||||
"bytes": 49
|
||||
},
|
||||
"outputs/main-db-qa-20261104/workforce-economic-types.log": {
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"bytes": 0
|
||||
},
|
||||
"outputs/main-db-qa-20261104/workforce-economic-lint.log": {
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"bytes": 0
|
||||
},
|
||||
"outputs/main-db-qa-20261104/workforce-economic-build.log": {
|
||||
"sha256": "ec0f15282f2dfe3c3c8dbe349773a88adbd87efba7e26332cd55c34b8f21bf25",
|
||||
"bytes": 31606
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3447,3 +3447,18 @@ Delta aprovado: oito testes de BD/438 asserções (quatro novos e quatro de filt
|
||||
Conferência visual no Edge exclusivamente em `127.0.0.2:18644`, base `main_visual_20261104_test`: duas fixtures claramente sintéticas criadas apenas em QA, uma por categoria; nenhuma coordenada/geometria criada. Hash de todas as oportunidades anteriores idêntico antes/depois. Alternância entre ambas conserva pesquisa provincial e duas fichas gerais; cada camada mostra a sua ficha, fonte/período/âmbito/limites e ausência de ponto. Infra-estruturas recuperada após recarregar. Recibo: `docs/investmoz/unification/thematic-map-local-20261104.json`; inventário, hashes, DOM e capturas em `outputs/thematic-map-20261104/`. Demonstração sintética não constitui cobertura económica factual ou publicação de dados reais.
|
||||
|
||||
**ACT-02 permanece parcial.** Cobertura factual de recursos/infra-estruturas no destino, georreferenciação própria quando documentada, mão-de-obra, potencial económico quantitativo, restantes fontes temáticas e lacunas cartográficas continuam pendentes. Não se inferem estas camadas de descrições nem do número de oportunidades. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, alteração activa, migração, publicação automática ou alteração de permissões/serviços.
|
||||
|
||||
|
||||
### 04/11/2026 — ACT-20261029-02: mão-de-obra documentada e contexto económico
|
||||
|
||||
Incremento qualitativo na main local sobre `21ebad73`, reutilizando mapa, evidências, síntese publicada, divulgação expressa e fontes/períodos existentes. Inventário na cópia QA: duas evidências públicas locais de actividade anteriores (fichas sintéticas 350/383), nenhuma de mão-de-obra/oferta/procura; recursos/infra-estruturas da demonstração anterior conservados. As declarações labour_demands/training_capacities têm acesso EducationAccess interno; emprego/indicadores financeiros canónicos não fazem parte da publicProjection. Observações de zonas conservam divulgação/unidades/metodologia próprias. Não foram expostas nem agregadas essas fontes privadas por existir revisão interna. As fontes oficiais aceites e as decisões de divulgação anteriores não foram reabertas.
|
||||
|
||||
Acrescentada categoria explícita Mão-de-obra no editor e validação da evidência existente, sem migração ou reclassificação automática dos textos anteriores. Guardar, recuperar, pré-visualizar e confirmar publicação usam o percurso existente. A camada económica reutiliza apenas evidências públicas locais de actividade/oferta/procura, mantendo `source_category` original, facto, fonte, localizador, período, verificação, âmbito, cobertura e limitações. Agrupá-las para consulta é uma escolha de apresentação, não aprovação de viabilidade nem índice de potencial.
|
||||
|
||||
Ambas as opções entram no selector do mapa único; a escolha é recuperada na sessão. Recursos/infra-estruturas, geometrias públicas, filtros territoriais, fichas sem ponto e contagens anteriores mantêm-se. Nenhuma posição é criada ou atribuída ao recurso/mão-de-obra. Necessidade ou qualificação não equivale a trabalhador disponível; previsão de emprego não é emprego efectivo. Contexto económico não calcula retorno, score ou viabilidade. Períodos/fontes incompatíveis permanecem separados, sem totais ou zero presumido.
|
||||
|
||||
Delta aprovado: sete testes de BD/77 asserções (cinco do mapa, incluindo o novo caso; dois de publicação, um novo e um de acesso/fonte privada já existente), 22 testes frontend, PHPStan sem erros, tipos, Pint, lint e build QA aprovados. Teste do percurso: criar evidência workforce → recuperar → confirmar pela publicação existente → consultar mapa → alterar rascunho privado sem substituir a categoria/fonte públicas. Testes mantêm metodologia/internos fora do mapa, categorias originais, períodos distintos e ausência de quantidades/índices inferidos. Não se repetiu a bateria geral aceite.
|
||||
|
||||
Conferência visual no Edge exclusivamente na QA `127.0.0.2:18644`/`main_visual_20261104_test`: contexto económico reutiliza a evidência de actividade já publicada da ficha 383, sintética e explicitamente identificada. Mão-de-obra usa uma única fixture nova, também sintética; escolha e fonte recuperadas após recarregar. Nenhuma coordenada/geometria criada; hash de todas as oportunidades anteriores idêntico antes/depois. Conferidos 36 artefactos dos três recibos anteriores, todos com SHA256 inalterado. Recibo: `docs/investmoz/unification/workforce-economic-map-local-20261104.json`; inventário, DOM, capturas e hashes em `outputs/workforce-economic-map-20261104/`.
|
||||
|
||||
**ACT-02 permanece parcial.** Cobertura factual laboral/económica, séries, unidades e metodologia quantitativa comparável, georreferenciação própria documentada e cobertura cartográfica continuam pendentes. A demonstração sintética não mede oferta laboral nem potencial regional real. Mantêm-se conferência remota e aceitação da equipa; V2-07/V2-10 não encerrados. Sem push, migração, publicação automática, escrita activa, alteração de permissões ou reinício de serviços.
|
||||
|
||||
@@ -399,6 +399,8 @@ export function ProactiveInvestmentEditor({
|
||||
infrastructure: 'Infra-estrutura',
|
||||
supply: 'Oferta',
|
||||
demand: 'Procura',
|
||||
workforce:
|
||||
'Mão-de-obra — evidência documentada',
|
||||
},
|
||||
(v) => change({ category: v }),
|
||||
)}
|
||||
|
||||
@@ -14,7 +14,12 @@ export type ThematicMapRecord = {
|
||||
limitations: string | null;
|
||||
evidence: {
|
||||
id: string;
|
||||
category: 'resource' | 'infrastructure';
|
||||
category:
|
||||
| 'resource'
|
||||
| 'infrastructure'
|
||||
| 'workforce'
|
||||
| 'economic_potential';
|
||||
source_category?: string;
|
||||
statement?: string | null;
|
||||
source?: string | null;
|
||||
locator?: string | null;
|
||||
@@ -27,6 +32,16 @@ export type ThematicMapRecord = {
|
||||
const labels = {
|
||||
resource: 'Recursos documentados',
|
||||
infrastructure: 'Infra-estruturas documentadas',
|
||||
workforce: 'Mão-de-obra documentada',
|
||||
economic_potential: 'Potencial económico — contexto documentado',
|
||||
};
|
||||
const sourceLabels: Record<string, string> = {
|
||||
activity: 'Actividade',
|
||||
supply: 'Oferta',
|
||||
demand: 'Procura',
|
||||
workforce: 'Mão-de-obra',
|
||||
resource: 'Recurso',
|
||||
infrastructure: 'Infra-estrutura',
|
||||
};
|
||||
const value = (text?: string | null) => text?.trim() || 'Não indicado';
|
||||
|
||||
@@ -49,8 +64,7 @@ export default function ThematicInvestmentMap({
|
||||
const saved = window.sessionStorage.getItem(
|
||||
'investmoz-map-theme-v1',
|
||||
);
|
||||
if (saved === 'resource' || saved === 'infrastructure')
|
||||
setTheme(saved);
|
||||
if (saved && Object.hasOwn(labels, saved)) setTheme(saved);
|
||||
} catch {
|
||||
// The server and first client render use the same default layer.
|
||||
}
|
||||
@@ -129,9 +143,12 @@ export default function ThematicInvestmentMap({
|
||||
pesquisa geral mantém os seus filtros e resultados.
|
||||
</p>
|
||||
<p>
|
||||
Mão-de-obra e potencial económico: sem camada quantitativa
|
||||
nesta consulta; não são inferidos de descrições ou do número
|
||||
de oportunidades.
|
||||
Mão-de-obra: a evidência pode descrever necessidades ou
|
||||
qualificações; não mede trabalhadores disponíveis. Potencial
|
||||
económico: contexto de actividade, oferta e procura, sem
|
||||
índice, previsão de retorno ou viabilidade calculados.
|
||||
Fontes e períodos não são agregados como se fossem
|
||||
comparáveis.
|
||||
</p>
|
||||
{truncated && (
|
||||
<p role="note">
|
||||
@@ -152,13 +169,14 @@ export default function ThematicInvestmentMap({
|
||||
).length
|
||||
}{' '}
|
||||
sem ponto público utilizável. Ausência de evidência
|
||||
não significa ausência do recurso.
|
||||
não significa ausência de recursos ou actividade
|
||||
económica.
|
||||
</p>
|
||||
{selected.length === 0 && (
|
||||
<p>
|
||||
Sem evidência pública local de recursos ou
|
||||
infra-estruturas para esta camada e estes
|
||||
filtros. Não foram criadas posições no mapa.
|
||||
Sem evidência pública local para esta camada e
|
||||
estes filtros. Não foram criadas posições no
|
||||
mapa.
|
||||
</p>
|
||||
)}
|
||||
{selected.length > 0 && (
|
||||
@@ -207,6 +225,15 @@ export default function ThematicInvestmentMap({
|
||||
<p className="font-semibold">
|
||||
{labels[proof.category]}
|
||||
</p>
|
||||
{proof.source_category && (
|
||||
<p>
|
||||
Categoria de origem:{' '}
|
||||
{sourceLabels[
|
||||
proof
|
||||
.source_category
|
||||
] ?? 'Não indicada'}
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
{value(proof.statement)}
|
||||
</p>
|
||||
|
||||
@@ -55,15 +55,34 @@ class InvestmentThematicMapTest extends TestCase
|
||||
$record = $this->record($prefix, [$this->proof(), $this->proof('infrastructure'), $this->proof('resource', 'methodology'), $this->proof('demand')]);
|
||||
$before = $record->fresh()->getRawOriginal('workflow_context');
|
||||
$response = $this->getJson($this->url($prefix))->assertOk()->assertJsonPath('matched_count', 1)
|
||||
->assertJsonPath('thematic_records.0.id', $record->id)->assertJsonCount(2, 'thematic_records.0.evidence')
|
||||
->assertJsonPath('thematic_records.0.id', $record->id)->assertJsonCount(3, 'thematic_records.0.evidence')
|
||||
->assertJsonPath('thematic_records.0.evidence.0.source', 'Synthetic public source')
|
||||
->assertJsonPath('thematic_records.0.evidence.0.period', '2026')
|
||||
->assertJsonPath('thematic_records.0.evidence.0.scope', 'Synthetic district')
|
||||
->assertJsonPath('thematic_records.0.evidence.2.category', 'economic_potential')
|
||||
->assertJsonPath('thematic_records.0.evidence.2.source_category', 'demand')
|
||||
->assertJsonPath('thematic_records.0.state', 'hypothesis')->assertJsonCount(0, 'features')->assertJsonCount(1, 'unlocated');
|
||||
$this->assertStringNotContainsString('PRIVATE-DRAFT-MUST-NOT-LEAK', $response->getContent());
|
||||
$this->assertSame($before, $record->fresh()->getRawOriginal('workflow_context'));
|
||||
}
|
||||
|
||||
public function test_workforce_is_explicit_and_economic_context_preserves_each_source_without_inferred_totals(): void
|
||||
{
|
||||
$prefix = 'THEME-'.Str::uuid();
|
||||
$this->record($prefix, [$this->proof('workforce'), $this->proof('activity'), $this->proof('supply'), $this->proof('demand'), $this->proof('workforce', 'methodology')]);
|
||||
$r = $this->getJson($this->url($prefix))->assertOk()->assertJsonCount(4, 'thematic_records.0.evidence')
|
||||
->assertJsonPath('thematic_records.0.evidence.0.category', 'workforce')
|
||||
->assertJsonPath('thematic_records.0.evidence.0.source_category', 'workforce')
|
||||
->assertJsonPath('thematic_records.0.state', 'hypothesis')->assertJsonCount(0, 'features')->json('thematic_records.0');
|
||||
foreach (['activity', 'supply', 'demand'] as $i => $source) {
|
||||
$this->assertSame('economic_potential', $r['evidence'][$i + 1]['category']);
|
||||
$this->assertSame($source, $r['evidence'][$i + 1]['source_category']);
|
||||
$this->assertSame('2026', $r['evidence'][$i + 1]['period']);
|
||||
}
|
||||
$this->assertArrayNotHasKey('available_workers', $r);
|
||||
$this->assertArrayNotHasKey('potential_score', $r);
|
||||
}
|
||||
|
||||
public function test_unpublished_future_restricted_and_unselected_private_evidence_are_not_disclosed(): void
|
||||
{
|
||||
$prefix = 'THEME-'.Str::uuid();
|
||||
|
||||
@@ -62,6 +62,26 @@ final class ProactiveInvestmentTest extends TestCase
|
||||
return $input;
|
||||
}
|
||||
|
||||
public function test_workforce_evidence_saves_recovers_and_requires_existing_explicit_publication(): void
|
||||
{
|
||||
$input = F::input();
|
||||
$input['proactive']['evidence'][0]['category'] = 'workforce';
|
||||
$id = $this->postJson('/minhas-oportunidades/drafts', $input)->assertCreated()->json('id');
|
||||
$o = Opportunity::findOrFail($id);
|
||||
$analysis = app(OpportunityManagement::class)->values($o)['proactive'];
|
||||
$this->assertSame('workforce', $analysis['evidence'][0]['category']);
|
||||
$this->assertNull(app(ProactiveInvestment::class)->publicData($o));
|
||||
$this->publish($o);
|
||||
$this->getJson('/api/v1/investment/map?opportunity_id='.$id)->assertOk()
|
||||
->assertJsonPath('thematic_records.0.evidence.0.category', 'workforce')
|
||||
->assertJsonPath('thematic_records.0.evidence.0.source', $analysis['evidence'][0]['source'])
|
||||
->assertJsonCount(1, 'thematic_records.0.evidence')->assertJsonCount(0, 'features');
|
||||
$analysis['evidence'][0]['category'] = 'demand';
|
||||
$this->putJson('/minhas-oportunidades/'.$id.'/draft', ['etag' => app(OpportunityManagement::class)->etag($o->fresh()), 'proactive' => $analysis,
|
||||
'reason' => 'SYNTHETIC QA later private changes must not replace the published workforce source'])->assertOk();
|
||||
$this->getJson('/api/v1/investment/map?opportunity_id='.$id)->assertOk()->assertJsonPath('thematic_records.0.evidence.0.category', 'workforce');
|
||||
}
|
||||
|
||||
public function test_legacy_records_without_analysis_add_no_publication_lookup(): void
|
||||
{
|
||||
$o = new Opportunity;
|
||||
|
||||
@@ -137,7 +137,7 @@ test('default preserves every opportunity and one map, with sourced thematic evi
|
||||
'Partial coverage',
|
||||
'2026-10-01',
|
||||
'não representam a posição exacta',
|
||||
'não são inferidos',
|
||||
'sem índice',
|
||||
])
|
||||
assert.ok(html.includes(text), text);
|
||||
assert.match(html, /2 fichas com evidência temática pública/);
|
||||
@@ -216,7 +216,7 @@ test('changing query data never retains previous evidence; loading and incomplet
|
||||
);
|
||||
assert.match(html, /Sem evidência pública local/);
|
||||
assert.match(html, /A resposta está limitada/);
|
||||
assert.match(html, /não significa ausência do recurso/);
|
||||
assert.match(html, /não significa ausência de recursos/);
|
||||
});
|
||||
|
||||
test('theme selection survives reload in the tab and unavailable or invalid storage does not break the map', () => {
|
||||
@@ -276,3 +276,63 @@ test('theme selection survives reload in the tab and unavailable or invalid stor
|
||||
else globalThis.window = previous;
|
||||
}
|
||||
});
|
||||
|
||||
test('workforce and economic context preserve source categories and incompatible periods without inferred totals or borrowed points', () => {
|
||||
const Component = setup();
|
||||
const extra = [
|
||||
{
|
||||
...records[0],
|
||||
id: 4,
|
||||
title: 'Workforce evidence',
|
||||
evidence: [{ ...proof('workforce'), source_category: 'workforce' }],
|
||||
},
|
||||
{
|
||||
...records[1],
|
||||
id: 5,
|
||||
title: 'Economic context',
|
||||
evidence: [
|
||||
{
|
||||
...proof('economic_potential'),
|
||||
id: 'supply',
|
||||
source_category: 'supply',
|
||||
period: '2023',
|
||||
},
|
||||
{
|
||||
...proof('economic_potential'),
|
||||
id: 'demand',
|
||||
source_category: 'demand',
|
||||
period: '2026',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const data = { ...props, records: [...records, ...extra] };
|
||||
flat(Component(data))
|
||||
.find((node) => node.type === 'select')
|
||||
.props.onChange({ target: { value: 'workforce' } });
|
||||
let tree = Component(data);
|
||||
assert.deepEqual(
|
||||
flat(tree).find((node) => node.type === Map).props.points,
|
||||
[],
|
||||
);
|
||||
let html = renderToStaticMarkup(tree);
|
||||
assert.match(html, /Workforce evidence/);
|
||||
assert.match(html, /Categoria de origem: Mão-de-obra/);
|
||||
assert.match(html, /não mede trabalhadores disponíveis/);
|
||||
flat(tree)
|
||||
.find((node) => node.type === 'select')
|
||||
.props.onChange({ target: { value: 'economic_potential' } });
|
||||
tree = Component(data);
|
||||
html = renderToStaticMarkup(tree);
|
||||
assert.match(html, /Economic context/);
|
||||
assert.match(html, /Categoria de origem: Oferta/);
|
||||
assert.match(html, /Categoria de origem: Procura/);
|
||||
assert.match(html, /2023/);
|
||||
assert.match(html, /2026/);
|
||||
assert.match(html, /sem índice, previsão de retorno ou viabilidade/);
|
||||
assert.doesNotMatch(html, /Workforce evidence/);
|
||||
assert.deepEqual(
|
||||
flat(tree).find((node) => node.type === Map).props.points,
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user