chore: remove one-shot F4 patch workflow
This commit is contained in:
@@ -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
|
|
||||||
Reference in New Issue
Block a user