F6.1 · cierre de presentación y barrera de release (#34)

Cierra F6.1 como candidata verificable de presentación: metadata WEB alineada, contratos transversales de aceptación, Android CI/RC endurecida con lint/tests/builds/checksum, correcciones de carreras de permisos GPS y cámara opcional, auditoría de dependencias productivas y parches de runtime, más documentación de release y recorrido de demo.
This commit is contained in:
2026-09-09 18:35:28 -03:00
committed by GitHub
parent e549a44ae5
commit 509bc0cde1
17 changed files with 478 additions and 75 deletions
+8 -8
View File
@@ -1,12 +1,12 @@
{
"name": "dhv2-api",
"version": "0.20.0-2",
"version": "0.29.0-1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "dhv2-api",
"version": "0.20.0-2",
"version": "0.29.0-1",
"license": "UNLICENSED",
"dependencies": {
"@nestjs/common": "^11.0.0",
@@ -4166,9 +4166,9 @@
"license": "MIT"
},
"node_modules/multer": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/multer/-/multer-2.2.0.tgz",
"integrity": "sha512-6rdyFg2kLrMh9Jee7/BMPuV9lEAd7lLW2YUpF9/YxR7njyoUwwQ0ZPh3TaIY50Sw6vlyD2HW3wGOkTS4P79xrQ==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/multer/-/multer-2.3.0.tgz",
"integrity": "sha512-cjNbm3sttszgZeGfJR124D+jFEfkXCVAsoPBmFn9X7UxmDSFHWqE2CoEj0vrmSpuAFnqWR1Szcm9QTsiHr60Xw==",
"license": "MIT",
"dependencies": {
"append-field": "^1.0.0",
@@ -4666,9 +4666,9 @@
}
},
"node_modules/qs": {
"version": "6.15.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz",
"integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==",
"version": "6.16.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz",
"integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==",
"license": "BSD-3-Clause",
"dependencies": {
"es-define-property": "^1.0.1",
+5 -1
View File
@@ -42,5 +42,9 @@
"ts-node": "^10.9.2",
"tsx": "^4.20.6",
"typescript": "^5.9.0"
},
"overrides": {
"multer": "2.3.0",
"qs": "6.16.0"
}
}
}
@@ -0,0 +1,66 @@
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import test from 'node:test';
const api = (path: string) => readFileSync(resolve(process.cwd(), path), 'utf8');
const web = (path: string) => readFileSync(resolve(process.cwd(), '..', 'web-v2', path), 'utf8');
const android = (path: string) => readFileSync(resolve(process.cwd(), '..', 'android-app', path), 'utf8');
test('F6.1 presentation metadata keeps the visible WEB version aligned with package metadata', () => {
const pkg = JSON.parse(web('package.json')) as { version: string };
const version = web('src/config/version.ts');
const visibleVersion = version.match(/APP_VERSION\s*=\s*'([^']+)'/)?.[1];
assert.equal(visibleVersion, pkg.version);
assert.match(version, /APP_PHASE\s*=\s*'F6\.1 · Contexto operativo ÁreaOperadora consolidado'/);
});
test('F6.1 presentation keeps Relevamientos retired from WEB navigation and routes', () => {
const app = web('src/app/App.tsx');
const layout = web('src/layout/AppLayout.tsx');
assert.doesNotMatch(app, /relevamientos/i);
assert.doesNotMatch(layout, /relevamientos/i);
assert.match(layout, /label: 'Inspecciones'/);
assert.match(layout, /label: 'Inventarios'/);
});
test('F6.1 presentation keeps the complete Inspector profile and documentary-copy explanation visible', () => {
const user = web('src/pages/UserDetailPage.tsx');
const delivery = api('src/inspection-reports/inspection-document-delivery.service.ts');
for (const field of ['dni', 'phone', 'jobTitle', 'employeeNumber']) {
assert.match(user, new RegExp(`name="${field}"`));
}
assert.match(user, /email es obligatorio para un Inspector/i);
assert.match(user, /la documentación se enviará también/i);
assert.match(delivery, /recipientKind:'INSPECTOR'/);
assert.match(delivery, /documentKind:'ACT_PDF'/);
assert.match(delivery, /documentKind:'REPORT_WORD'/);
});
test('F6.1 presentation keeps Android start, Otro and chronological merge flows wired to the canonical API', () => {
const mobileApi = android('app/src/main/java/com/korexlabs/dhinspeccion/data/DhMobile.kt');
const overview = android('app/src/main/java/com/korexlabs/dhinspeccion/ui/F3VisitRoot.kt');
const viewModel = android('app/src/main/java/com/korexlabs/dhinspeccion/MainViewModel.kt');
assert.match(mobileApi, /inspection-visits\/\{id\}\/start/);
assert.match(mobileApi, /field-inventory\/\{assetId\}\/merge/);
assert.match(overview, /"Iniciar inspección"/);
assert.match(overview, /Otro \/ no catalogado/);
assert.match(viewModel, /repository\.startVisit\(id\)/);
assert.match(viewModel, /selectedFieldAsset = repository\.selectFieldAsset\(visitId, result\.canonical\.id\)/);
assert.match(viewModel, /la historia de \$\{result\.source\.code\} permanece trazable/);
});
test('F6.1 presentation keeps catalog merge append-only for emitted findings', () => {
const merge = api('src/inspection-findings/finding-catalog-merge.service.ts');
const resolver = api('src/inspection-findings/f3-finding-catalog-resolver.service.ts');
assert.match(merge, /los Hallazgos emitidos nunca se reescriben/);
assert.match(merge, /historicalFindingsRewritten: false/);
assert.match(merge, /historyPolicy: 'EMITTED_FINDINGS_PRESERVED'/);
assert.match(resolver, /code: 'OTHER'/);
assert.match(resolver, /label: 'OTROS'/);
});