diff --git a/.github/workflows/f6-1-finish-scope-fix.yml b/.github/workflows/f6-1-finish-scope-fix.yml new file mode 100644 index 0000000..f079acf --- /dev/null +++ b/.github/workflows/f6-1-finish-scope-fix.yml @@ -0,0 +1,68 @@ +name: F6.1 finish inspection scope fix + +on: + push: + branches: + - 'hotfix/f6-1-inspection-planning-hierarchy' + paths: + - '.github/workflows/f6-1-finish-scope-fix.yml' + +permissions: + contents: write + +jobs: + apply: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: hotfix/f6-1-inspection-planning-hierarchy + fetch-depth: 0 + + - name: Remove final legacy ownership gate + run: | + python - <<'PY' + from pathlib import Path + p = Path('api-v3/src/inspection-visits/inspection-visits.service.ts') + text = p.read_text() + before = ''' await this.validatePlanningContext(manager, visit.operationalAreaId, visit.operatorCompanyId);''' + after = ''' await this.validatePlanningContext(\n manager,\n visit.operationalAreaId,\n visit.operatorCompanyId,\n visit.plannedStartAt,\n );''' + if text.count(before) != 1: + raise SystemExit(f'validatePlan current-time gate: expected 1, got {text.count(before)}') + text = text.replace(before, after) + + before = ''' await this.assertCurrentAssetsInScope(manager, visit.id, visit.scopeAssetId);\n await this.assertCurrentAssetsMatchContext(\n manager,\n visit.id,\n visit.operationalAreaId,\n visit.operatorCompanyId,\n );''' + after = ''' // F6.1: Inventory membership is physical (Yacimiento scope).\n // Company is temporal Area context and must never be reconstructed from\n // assets.operator_company_id, which is only a creation/historical snapshot.\n await this.assertCurrentAssetsInScope(manager, visit.id, visit.scopeAssetId);''' + if text.count(before) != 1: + raise SystemExit(f'validatePlan snapshot ownership gate: expected 1, got {text.count(before)}') + text = text.replace(before, after) + + # Remove now-dead helpers so future code cannot accidentally reuse snapshot ownership. + start = text.find(' private async assertAssetsMatchContext(') + end = text.find(' private async appendAssetEvent(', start) + if start < 0 or end < 0: + raise SystemExit('legacy snapshot helper block not found') + text = text[:start] + text[end:] + + p.write_text(text) + Path('.github/workflows/f6-1-finish-scope-fix.yml').unlink() + PY + + - name: Sanity checks + run: | + set -Eeuo pipefail + grep -Fq 'visit.plannedStartAt,' api-v3/src/inspection-visits/inspection-visits.service.ts + ! grep -Fq 'assertAssetsMatchContext' api-v3/src/inspection-visits/inspection-visits.service.ts + ! grep -Fq 'assertCurrentAssetsMatchContext' api-v3/src/inspection-visits/inspection-visits.service.ts + # No runtime ownership filter by the historical Inventory snapshot remains in this service. + ! grep -Fq 'asset.operator_company_id IS DISTINCT FROM' api-v3/src/inspection-visits/inspection-visits.service.ts + + - name: Commit final scope fix + run: | + set -Eeuo pipefail + git config user.name 'github-actions[bot]' + git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + git add api-v3/src/inspection-visits/inspection-visits.service.ts .github/workflows/f6-1-finish-scope-fix.yml + git diff --cached --check + git commit -m 'fix(F6.1): validate planned context without snapshot ownership' + git push origin HEAD:hotfix/f6-1-inspection-planning-hierarchy