# Approval Submit Performance Learnings

## 2026-07-14: Entry-criteria relationship lookup fanout

- Environment: formal staging, deployed L0 `964150890e86fccbea8268621bb76ea5551fb90f`; Env Inspection runs `29301885764` and serial rerun `29303048735`.
- Workload: approval submit with multiple active process definitions whose entry criteria dereference the same related record.
- Evidence: both runs reached the 30-second CloudFront timeout before a `ProcessInstance` row was committed.
- Profile: `ResolveSubmitEligibility` evaluates process definitions in order; each cross-object criterion invokes `QueryWithFilter` for the same foreign-key target again.
- Change under test: memoize related-record reads only within one eligibility resolution, keyed by related object and record ID; do not cache failures or share state across requests.
- Validation: the regression fixture first observed three related-record reads for three candidates; with the scoped cache it selects the same final process definition after one related-record read.
- Next check: merge and deploy the L0 fix, then rerun the staging Quote approval inspection cases.

## 2026-08-27: Repeated broad target reads during one approval execution

- Evidence source: test2 full-inspection follow-up in issue #4620; the isolated Quote approval slice produced 156 `v_quote` reads, at least 104 broad projections, and about 59.7 seconds of TiDB service time, dominated by repeated compilation of the same wide query shape.
- Current-tree model: Approval independently reread the same business record for existence, lock-rule evaluation, ordered FieldUpdate planning, lookup resolution, replay idempotency, and response hydration. The Records query stack already supported exact selected-root projections, but Approval did not expose or use that capability for internal system reads.
- Change under test: add a Records-owned exact system point-read, route it through Runtime Approval, use phase-specific field sets, and retain one immutable broad base snapshot per touched record only where `PreviewBeforeUpdate` genuinely needs the complete stored record.
- Correctness boundary: preserve first-match process ordering, independent pre-lock and locked snapshots, fail-closed LockRule behavior for fields that cannot be statically bounded, and the full response record. Do not pre-union later process fields or alias freshness phases.
- Local evidence: exact projection and routing tests prove capped `SelectFields`, System scope, no alternate query or `GetRaw` fallback, and one planning base read across three ordered same-record FieldUpdates. Records, the independent Runtime mutation composition, focused race tests, and Automation all pass; Automation excludes one fenced-scheduler integration test that was reproduced unchanged on clean `origin/main`.
- Review correction: the first implementation reused the public typed selected-root normalizer for internal reads, incorrectly rejecting projectable physical types outside the v1 typed union (demonstrated by MultiPicklist). The owning Records boundary now separates physical projection eligibility from public wire representation; the fix is guarded by a physical-field type matrix plus Approval LockRule and replay regressions.
- Security correction: physical projectability is also not read authority. The exact System reader now rejects metadata-declared `ReadProtectionPolicy=blocked` fields before repository projection, while ordinary FLS-hidden fields remain available to explicitly justified System consumers. Approval propagates that rejection without a `GetRaw` fallback or mutation. This keeps the optimization app-blind and preserves the existing hard read fence even under System context.
- Next check: finish local and CI verification, then deploy the frozen candidate to test2 and repeat the same isolated approval profile before claiming an RU or latency improvement.
