Repository navigation
fix(db): make draft_admin_integrity safely re-enable-able, keep flag OFF (#2993) - #2999
Merged
Merged
Conversation
…t enabled (#2993) Adds scripts/patch-draft-cascade-constraints.cjs which enumerates all *_drafts.hdbtable files emitted by `npx cds build --production` and injects a FOREIGN KEY ... ON DELETE CASCADE clause for the DraftAdministrativeData_DraftUUID column so HANA can enforce cascade- delete of orphaned draft rows. Wired into the MTA before-all builder (prod gen tree only; QA tree emits zero draft tables). The draft_admin_integrity flag remains false in package.json — this task only makes the constraints deployable. Verified: patched 46 / skipped 0 against a real production build.
… cascade patch (#2993) Two review findings: - Comma now trails PRIMARY KEY(ID) line (trailing-comma style) rather than appearing as a bare leading comma on the separator line. Fixed by trimEnd()ing the body slice so the comma attaches to the last element. - Idempotency regex tightened from /ON DELETE CASCADE/i to a pattern that keys on DraftAdministrativeData_DraftUUID + ON DELETE CASCADE (cross-paren match via [\s\S]*?) so a different column's cascade clause cannot be mistaken for our injection. New test: 'comma trails the previous line — no leading-comma style' asserts PRIMARY KEY(ID), immediately precedes FOREIGN KEY. 5/5 tests pass; real build: patched 46 / skipped 0.
Critical fix: local column in FK clause changed from quoted mixed-case
("DraftAdministrativeData_DraftUUID") to quoted UPPERCASE
("DRAFTADMINISTRATIVEDATA_DRAFTUUID"). The column is declared bare
(unquoted) in the generated .hdbtable, so HANA folds it to uppercase;
a quoted mixed-case reference is case-sensitive and would not resolve.
Confirmed by srv/lib/draft-integrity-preflight.js:93,100 and
scripts/cleanup-draft-orphans.cjs:55 both using the uppercase name.
Idempotency regex updated to match the uppercase token.
Test updated: FK-match assertion now requires "DRAFTADMINISTRATIVEDATA_DRAFTUUID"
(exact uppercase, not /i on the column name) and adds a regression guard
that fails on the mixed-case quoted form.
Docs corrected across runbook, spec, and plan: inline FK is ENFORCED
(NOT VALIDATED is an ALTER TABLE affordance only), so orphan sweep must
come BEFORE deploying the constraint-bearing build. Runbook reordered:
Step 1 = sweep, Step 2 = deploy (with enforced-FK precondition noted).
All "NOT VALIDATED / no pre-clean needed" claims removed.
Real build: patched 46 / skipped 0; PRIMARY KEY(ID), FOREIGN KEY
("DRAFTADMINISTRATIVEDATA_DRAFTUUID") ... ON DELETE CASCADE confirmed.
5/5 tests pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2993.
What & why
#2909 enabled
cds.fiori.draft_admin_integrity: truewithout the requiredON DELETE CASCADEconstraints on theADMINSERVICE_*_DRAFTStables → orphaned child draft rows → PROD outage (2026-11-02). #2992 disabled the flag; #2994 swept orphans.This PR does not re-enable the flag. Per decision (another outage is unacceptable), it proves re-enabling is safe and keeps the flag OFF — delivering the artifacts and the gate so a future flip is a documented, verified step rather than a leap.
The flag stays
falseinpackage.json(bothcds.fioriand[development]blocks).Changes
scripts/patch-draft-cascade-constraints.cjs+ unit test, wired into.deploy/mta.yamlbefore-all).cds buildalready emits the 46AdminService.*_drafts.hdbtablewith theDraftAdministrativeData_DraftUUIDcolumn but no cascade clause — this appendsFOREIGN KEY ("DRAFTADMINISTRATIVEDATA_DRAFTUUID") REFERENCES "DRAFT_DRAFTADMINISTRATIVEDATA"("DRAFTUUID") ON DELETE CASCADEto each, prodgen/dbtree only (QA emits no draft tables). Idempotent; fails loud if zero draft tables found; skips tables lacking the FK column.test/admin-drafts-cascade-gate.test.js). Mission draftEdit→discard leaves zero child draft rows, asserted via the service-layer.draftsaccessor on SQLite — correct whether deletion comes from today's app-level reconcile or a future DB cascade. This is the re-enable gate.docs/developers/operations/draft-integrity-reenable.md+ CLAUDE.md pointer): sweep orphans → deploy constraints → preflightverified (N/N)→ gate green → flip flag → redeploy.The constraint patch runs on every MTA build. So the next deploy of this branch starts shipping the enforced cascade FK to HANA even with the flag off. This is intended (the FK is inert at the runtime level until the flag flips) — but the FK is ENFORCED (an inline FK inside
COLUMN TABLE (...)cannot beNOT VALIDATED), so orphaned draft rows must be swept BEFORE the constraint-bearing build deploys or HANA will reject the deploy. The runbook sequences the sweep first. It's a real DB-schema change on next deploy, not a no-op — coordinate deploy timing accordingly.Testing
npx vitest run test/unit/patch-draft-cascade-constraints.test.js test/admin-drafts-cascade-gate.test.js test/admin-drafts-discard-reconcile.test.js→ 10/10 green. Real-build spot check confirms the uppercase FK lands inAdminService.Missions_drafts.hdbtable.🤖 Generated with Claude Code