- Published on
Membership Reconciliation: When an Audit Stops at 10,000 Records

- Authors
- Name
- Antonio Perez
The first production result looked reassuring: exactly 10,000 subscriptions.
It was also wrong.
The business needed to reconcile membership status across a legacy subscription provider, a commerce platform, and a loyalty platform. A customer could appear active in one system, carry a membership tag in another, and have a different tier in a third. The audit needed to find those disagreements and correct the safe cases without removing benefits from a legitimate member.
An even 10,000 records should have triggered suspicion immediately. Instead of returning an error, the provider silently stopped the search at its result cap. A report built on that response would have treated thousands of active subscribers as absent and converted incomplete data into plausible but wrong cleanup decisions.
The lesson is broader than one provider or membership program:
A reconciliation process is only as trustworthy as its proof of completeness.
The business problem was entitlement, not data synchronization
The goal was not to make three databases contain identical fields. The goal was to answer a business question safely:
Should this customer currently receive membership benefits?
Several signals could support that decision:
- An active legacy subscription
- A current membership purchased through the new commerce platform
- A VIP tier in the loyalty platform
- A membership tag on the commerce customer
Those signals did not have equal authority. Some represented payment or enrollment. Others were projections used for storefront behavior and marketing segmentation. Treating the customer tag as the source of truth would only confirm the state being audited.
The architecture therefore needed to model the business capability—membership entitlement—before deciding which vendor records could prove it.
A round number is evidence, not reassurance
The first subscription census returned exactly 10,000 rows. A second search restricted to active subscriptions also returned exactly 10,000.
That coincidence was the signal. The provider imposed a silent search ceiling: no error, no truncation flag, and no continuation token. The result looked complete unless the caller challenged it.
This is a dangerous failure mode because the data remains internally plausible. A network failure is obvious. A schema error is noisy. A capped result can flow through joins, reports, and write logic without producing a technical exception.
The audit was changed to search subscriptions in daily creation windows. Every window had the same hard ceiling:
- Fewer than 10,000 records meant the window could be accepted.
- Exactly 10,000 meant the audit stopped rather than assuming completeness.
- Coverage was recorded separately so interrupted runs could resume without skipping a day.
- The current partial day was never cached as complete.
After sharding, the actual active legacy population was more than 44,000 subscriptions—not 10,000.
Completeness needs an invariant
Pagination is not proof of completeness when the upstream interface does not expose honest pagination behavior.
The audit needed explicit invariants:
- The search window covered the entire known lifetime of the legacy program.
- No individual window reached the provider cap.
- Every active subscription could be joined to at most one commerce customer.
- Current membership orders were scanned from the beginning of the new program.
- No order was truncated at its own line-item limit.
- Every cleanup candidate was checked against the loyalty source of truth.
If any invariant failed, report mode could still explain the gap, but write mode refused to run.
That distinction matters. Incomplete data can be useful for diagnosis. It is not safe evidence for destructive correction.
Identity ambiguity must remain unresolved
Subscriptions did not carry the commerce customer identifier needed for the final comparison. The audit had to cross payment-method, internal-customer, email, commerce-customer, and loyalty-card identities.
The tempting shortcut was to join by email and choose the first match. That would make the report look cleaner while assigning an entitlement to an arbitrary customer record.
The safer rule was strict:
- A deterministic internal identifier could establish a match.
- A unique email match could establish a fallback match.
- Multiple possible customers remained unjoinable.
- An unjoinable active subscription blocked cleanup unless explicitly reviewed.
An audit should preserve uncertainty instead of resolving it with an undocumented guess. A smaller set of honest results is more useful than a complete-looking report built on ambiguous identity.
The nominal read path was not actually read-only
The loyalty client contained a helpful behavior: when it read a card with a missing baseline tier, it repaired that tier automatically.
That behavior made sense for normal application traffic. It violated the audit's contract.
A report labeled “no writes” cannot trigger thousands of opportunistic repairs while inspecting rows. The client was changed to support an explicitly read-only mode with identical mapped output and no self-healing side effect.
This exposed a common integration problem: method names such as readCustomer or findCard do not prove observational behavior. Audit tooling must trace the real dependency path and disable hidden writes, callbacks, webhooks, and downstream events.
Source-of-truth rules protected valid members
The first complete comparison found roughly 1,350 customers whose commerce tag appeared stale. Removing all of those tags would have been wrong.
The loyalty platform still classified more than 130 of them as enrolled VIP members. The legacy subscription data could not see every historical path that granted VIP status, so absence from the subscription and new-membership sources was insufficient evidence for removal.
The cleanup rule became:
candidate appears stale
AND legacy subscription coverage is complete
AND current membership coverage is complete
AND identity is unambiguous
AND loyalty platform says the customer is not VIP
→ membership tag may be removed
That rule corrected more than 1,200 stale tags while preserving every candidate the loyalty system still considered entitled.
The audit also found the mirror-image problem: dozens of customers who should have carried the tag but did not. Most were already VIP in the loyalty platform. This asymmetry pointed to a workflow that could update the tier successfully and then fail while projecting the tag.
Reconciliation should look in both directions. Finding only excess state misses absent state caused by partial success.
The SDK became part of the operating model
The provider SDK retained a surprising amount of memory for every materialized subscription. The small normalized record needed by the audit was only a few hundred bytes, but the SDK kept the much larger original object graph alive.
Increasing the heap delayed the crash without fixing it. The complete historical sweep still failed.
The durable solution was process isolation:
- Each bounded date range ran in a child process.
- The child emitted only normalized subscription records.
- The parent recorded coverage after successful completion.
- Process exit reclaimed memory the SDK would not release.
- A missing coverage interval blocked reconciliation.
This is not elegant in the abstract. It is operationally simple and honest. Replacing or patching the SDK might be preferable in a reusable product, but a bounded production audit needed a design the team could trust immediately.
Alternatives considered
Trust the provider search
This produced a fast result and a dangerously incomplete population. It was rejected once the round-number cap was confirmed.
Drive the audit only from the application database
This would have been cheaper, but it could not find active subscriptions belonging to customers who had never been linked into the newer application database. It could measure known records, not prove legacy coverage.
Remove every apparently stale tag
This treated absence from two systems as proof that no other valid entitlement path existed. The loyalty check demonstrated that assumption was false.
Keep the audit permanently report-only
Report-only mode was the correct default. It was not the final answer because a carefully bounded cleanup could remove confirmed stale projections safely. Write mode was retained behind explicit coverage, identity, and source-of-truth gates.
Tradeoffs accepted
- Daily sharding increased API traffic and audit duration in exchange for complete enumeration.
- Strict joins left some records unresolved instead of maximizing automatic coverage.
- Consulting the loyalty platform added another dependency but prevented valid members from losing benefits.
- Child processes added orchestration code but provided reliable memory reclamation.
- Write refusal gates made the tool less convenient and made production correction safer.
- Rounded public figures preserve the engineering lesson without exposing an internal operational report as marketing data.
Lessons learned
Completeness must be demonstrated
A successful response, a drained iterator, or a round total does not prove that the source returned everything. Reconciliation needs coverage invariants tied to the upstream system's actual behavior.
Negative evidence is weak across system boundaries
“Not found here” is not the same as “does not exist.” Before removing an entitlement, identify every system and historical workflow that can legitimately grant it.
Read-only must be verified through dependencies
An audit can write through self-healing reads, event emission, lazy migration, or cache warming. Trace the entire call path before promising report-only behavior.
Refuse unsafe work explicitly
Warnings are appropriate for exploration. A production cleanup should turn missing coverage, ambiguous identity, and truncated inputs into hard stops.
Reconciliation is a product capability
The lasting result was not a one-time script. It was a repeatable way to prove coverage, explain disagreement, protect valid customers, and correct only the cases supported by complete evidence.
That capability will survive the current providers. The membership program may change again, but the business will still need to answer who is entitled, why, and whether every system agrees.
If your commerce, payment, loyalty, or operational systems can disagree without a safe way to prove and repair state, systems integration consulting can help define the ownership rules, audit boundaries, and smallest responsible recovery path.
Continue exploring
Follow the architecture decisions behind this article
Continue with the principles, implementation stories, and consulting paths that apply to the same platform problem.
Related consulting
- Enterprise Systems Integration Consulting →Enterprise integration architecture for ERPs, CRMs, commerce platforms, payment systems, APIs, and operational workflows that need clear ownership and recoverable data movement.
- Technical Architecture Review & Due Diligence →Technical architecture review and due diligence for teams that need an evidence-based assessment of platform risk, scalability, integrations, vendor plans, or modernization options.
Related design principles
Related case study
Designing a Commerce Platform Around Capabilities, Not Vendors →
Keeping pricing, payments, loyalty, fulfillment, analytics, finance, and operations adaptable as the commerce ecosystem changed
Working through a similar platform decision?
Bring the business capability, constraints, and failure modes. I can help identify the smallest responsible next step.