chore: remove one-shot F4 patch workflow

This commit is contained in:
2026-09-08 15:07:03 -03:00
parent 844c1a950f
commit fcd64d5f43
@@ -1,107 +0,0 @@
name: F4 one-shot pre-merge corrections
on:
push:
branches:
- feature/f4-backend-saneamiento-documental
permissions:
contents: write
jobs:
patch:
if: github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: feature/f4-backend-saneamiento-documental
- name: Apply audited F4 corrections
run: |
python - <<'PY'
from pathlib import Path
def replace_once(path: str, old: str, new: str) -> None:
file = Path(path)
text = file.read_text()
count = text.count(old)
if count != 1:
raise SystemExit(f"{path}: expected exactly one match, got {count}")
file.write_text(text.replace(old, new))
# 1) Physical DB default must match the active F4 report lifecycle.
migration = 'api-v3/src/database/migrations/1790000600000-f4-align-document-lifecycle-constraints.ts'
replace_once(
migration,
""" await queryRunner.query(`\n ALTER TABLE inspection_reports\n ADD CONSTRAINT chk_inspection_reports_status CHECK (\n status IN ('WORKING','OFFICIALIZED','FROZEN','CANCELLED')\n )\n `);\n\n await queryRunner.query(`\n ALTER TABLE inspection_acts\n""",
""" await queryRunner.query(`\n ALTER TABLE inspection_reports\n ADD CONSTRAINT chk_inspection_reports_status CHECK (\n status IN ('WORKING','OFFICIALIZED','FROZEN','CANCELLED')\n )\n `);\n await queryRunner.query(`\n ALTER TABLE inspection_reports\n ALTER COLUMN status SET DEFAULT 'WORKING'\n `);\n\n await queryRunner.query(`\n ALTER TABLE inspection_acts\n""",
)
replace_once(
migration,
""" await queryRunner.query(`\n UPDATE inspection_reports\n SET status='FROZEN'\n WHERE status IN ('WORKING','OFFICIALIZED')\n `);\n await queryRunner.query(`\n ALTER TABLE inspection_reports\n DROP CONSTRAINT IF EXISTS chk_inspection_reports_status\n""",
""" await queryRunner.query(`\n UPDATE inspection_reports\n SET status='FROZEN'\n WHERE status IN ('WORKING','OFFICIALIZED')\n `);\n await queryRunner.query(`\n ALTER TABLE inspection_reports\n ALTER COLUMN status SET DEFAULT 'FROZEN'\n `);\n await queryRunner.query(`\n ALTER TABLE inspection_reports\n DROP CONSTRAINT IF EXISTS chk_inspection_reports_status\n""",
)
# 2) A documented company absence is a terminal manifestation: it must not strand a LOCKED Act.
closing = 'api-v3/src/inspection-closing/inspection-closing.service.ts'
replace_once(
closing,
""" const companyOutcomes = signatures.filter((item) =>\n item.signerType === InspectionActSignerType.COMPANY_RESPONSIBLE,\n );\n if (companyOutcomes.length !== 1) {\n throw new ConflictException({\n code: 'INSPECTION_ACT_COMPANY_OUTCOME_REQUIRED',\n message: 'Debe existir exactamente una firma, disidencia o negativa del responsable de la empresa',\n });\n }\n const companyOutcome = companyOutcomes[0];\n if (companyOutcome.status === InspectionActSignatureStatus.ABSENT) {\n throw new ConflictException({\n code: 'INSPECTION_ACT_COMPANY_MANIFESTATION_PENDING',\n message: 'La ausencia no reemplaza la firma o negativa; la manifestación de la empresa sigue pendiente',\n });\n }\n\n const serverSealedAt = new Date();\n""",
""" const companyOutcomes = signatures.filter((item) =>\n item.signerType === InspectionActSignerType.COMPANY_RESPONSIBLE,\n );\n if (companyOutcomes.length !== 1) {\n throw new ConflictException({\n code: 'INSPECTION_ACT_COMPANY_OUTCOME_REQUIRED',\n message: 'Debe existir exactamente una firma, disidencia, negativa o ausencia documentada del responsable de la empresa',\n });\n }\n\n const serverSealedAt = new Date();\n""",
)
# 3) Legacy administrative follow-up remains available, but F4 SEALED Acts must be visible.
admin = 'api-v3/src/act-administration/act-administration.service.ts'
replace_once(
admin,
"WHERE ia.status IN ('CLOSED', 'RECTIFIED')",
"WHERE ia.status IN ('SEALED', 'CLOSED', 'RECTIFIED')",
)
replace_once(
admin,
"if (!['CLOSED', 'RECTIFIED'].includes(act.status)) throw new BadRequestException({ code: 'ACT_ADMIN_REQUIRES_CLOSED', message: 'El seguimiento administrativo comienza cuando el Acta está cerrada.' });",
"if (!['SEALED', 'CLOSED', 'RECTIFIED'].includes(act.status)) throw new BadRequestException({ code: 'ACT_ADMIN_REQUIRES_SEALED', message: 'El seguimiento administrativo comienza cuando el Acta está sellada.' });",
)
briefing = 'api-v3/src/act-administration/field-briefing.service.ts'
replace_once(
briefing,
"WHERE act.status IN ('CLOSED', 'RECTIFIED')",
"WHERE act.status IN ('SEALED', 'CLOSED', 'RECTIFIED')",
)
page = 'web-v2/src/pages/ActAdministrationPage.tsx'
replace_once(
page,
"El plazo y la respuesta de la empresa se gestionan sobre el Acta completa. Los hallazgos quedan dentro de su expediente.",
"El plazo y la respuesta de la empresa se gestionan sobre el Acta completa. GEDO no activa el vencimiento por sí solo; el plazo se define cuando corresponda. Los hallazgos quedan dentro de su expediente.",
)
# 4) Regression contracts for the three audited pre-merge gaps.
test_path = Path('api-v3/test/unit/f4-premerge-review-contract.test.ts')
if test_path.exists():
raise SystemExit(f'{test_path}: file already exists')
test_path.write_text("""import assert from 'node:assert/strict';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport test from 'node:test';\n\nconst root = process.cwd();\nconst read = (relative: string) => fs.readFileSync(path.join(root, relative), 'utf8');\n\nconst migration = read('src/database/migrations/1790000600000-f4-align-document-lifecycle-constraints.ts');\nconst closing = read('src/inspection-closing/inspection-closing.service.ts');\nconst administration = read('src/act-administration/act-administration.service.ts');\nconst briefing = read('src/act-administration/field-briefing.service.ts');\n\ntest('F4 report status default is WORKING physically and rollback restores FROZEN', () => {\n const up = migration.slice(migration.indexOf(' public async up('), migration.indexOf(' public async down('));\n const down = migration.slice(migration.indexOf(' public async down('));\n assert.match(up, /ALTER COLUMN status SET DEFAULT 'WORKING'/);\n assert.match(down, /ALTER COLUMN status SET DEFAULT 'FROZEN'/);\n});\n\ntest('F4 allows a documented company absence to satisfy the terminal manifestation required for sealing', () => {\n const closeStart = closing.indexOf(' async close(');\n const closeEnd = closing.indexOf(' async signatureContent(', closeStart);\n const close = closing.slice(closeStart, closeEnd);\n assert.match(close, /companyOutcomes\.length !== 1/);\n assert.match(close, /ausencia documentada/);\n assert.doesNotMatch(close, /INSPECTION_ACT_COMPANY_MANIFESTATION_PENDING/);\n assert.doesNotMatch(close, /companyOutcome\.status === InspectionActSignatureStatus\.ABSENT/);\n});\n\ntest('F4 SEALED Acts remain visible in administrative follow-up and field briefing', () => {\n assert.match(administration, /WHERE ia\.status IN \('SEALED', 'CLOSED', 'RECTIFIED'\)/);\n assert.match(administration, /\['SEALED', 'CLOSED', 'RECTIFIED'\]\.includes\(act\.status\)/);\n assert.match(briefing, /WHERE act\.status IN \('SEALED', 'CLOSED', 'RECTIFIED'\)/);\n});\n""")
PY
git diff --check
- name: Commit audited corrections
run: |
set -Eeuo pipefail
if git diff --quiet; then
echo 'No changes produced; refusing silent success.'
exit 1
fi
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add \
api-v3/src/database/migrations/1790000600000-f4-align-document-lifecycle-constraints.ts \
api-v3/src/inspection-closing/inspection-closing.service.ts \
api-v3/src/act-administration/act-administration.service.ts \
api-v3/src/act-administration/field-briefing.service.ts \
api-v3/test/unit/f4-premerge-review-contract.test.ts \
web-v2/src/pages/ActAdministrationPage.tsx
git commit -m 'fix: close F4 pre-merge review gaps'
git push origin HEAD:feature/f4-backend-saneamiento-documental