HomeJournalThis post

Data imports need quarantine states

Quarantine-first imports preserve source provenance, classify row-level risk, resolve identity deliberately, preview consequence, commit idempotently, and reconcile every outcome.

JP
JP Casabianca
Designer/Engineer · Bogotá

A green upload progress bar proves that bytes arrived. It does not prove that the rows belong in the product.

Imports cross several trust boundaries at once. A value can parse and still target the wrong tenant. A familiar email can identify two people. A spreadsheet cell can become executable when exported later. A valid foreign key can point to a record the operator was never allowed to change.

OWASP's current CSV Injection guidance explains that untrusted input can be interpreted as formulas by spreadsheet applications and that no universal sanitization strategy works for every application and downstream consumer. That is one reason I would preserve the original material, classify it, and keep it outside authoritative tables until the intended consumer and transformation are known.

Quarantine is not an error bucket. It is a first-class product state with row-level reasons, safe previews, repair actions, explicit approval, idempotent commit, and a receipt that reconciles what changed.

The import is complete only when every submitted row has a durable outcome and the operator can explain the difference between the file and production.

01 · ReceiveFreeze the source

Hash the file, record provenance, scan limits, identify format, and store it in a tenant-scoped quarantine location.

02 · InterpretCreate reviewable candidates

Parse with a pinned version, normalize without erasing source, validate schema and policy, and expose row-level outcomes.

03 · CommitApply an approved plan

Write idempotent batches, preserve lineage, reconcile totals, surface partial failure, and delete temporary material on schedule.

Figure 1: An import crosses trust boundaries before it reaches product tables.

Freeze source and provenance

The original bytes, digest, uploader, tenant, claimed source, content type, size, arrival time, and parser version should remain immutable while derived interpretations evolve.

I would pressure-test that decision with four questions:

  • Which bytes were reviewed?
  • Who supplied them for which tenant?
  • Which parser interpreted them?
  • When must the source be deleted?

The failure mode here is overwriting the upload with a cleaned copy and losing the evidence needed to explain a mismatch. In CSV, spreadsheet, JSON, XML, archive, and partner-feed imports where untrusted files can be syntactically valid while still carrying unsafe formulas, ambiguous identifiers, invalid relationships, duplicates, stale values, or changes too consequential to apply immediately, that can hide the exact boundary a reviewer or teammate needs to understand. My working artifact would be an immutable import-source manifest. I want it close enough to the implementation that it can change the work, not created afterward to decorate the story.

The result I would look for is every candidate row traceable to exact source bytes and parser behavior. That is a narrower claim than saying the whole system improved, but it is also one I can verify and defend.

In practice, I would put an immutable import-source manifest beside the question “Which bytes were reviewed?” before the first implementation review. The next pass would use “Who supplied them for which tenant?” to test the boundary, then “Which parser interpreted them?” to expose the state most likely to be missed. I would keep “When must the source be deleted?” for the release check because it asks whether the decision still holds outside the ideal path. The work is ready to move when the artifact can explain the choice and the observed result supports every candidate row traceable to exact source bytes and parser behavior.

Treat parsing as untrusted computation

Parsers need bounded archive depth, row and cell sizes, encodings, formula-risk handling, timeouts, and explicit failure because familiar office formats are not harmless text.

The practical review starts here:

  • Which formats are accepted?
  • What resource limits apply?
  • Can nested content expand unexpectedly?
  • How are dangerous cells represented safely?

Those questions keep opening or transforming customer files in privileged operator tools before classification from becoming the default. I would capture the decision in a parser threat-and-limit table, then use it while the work is still cheap to change. For bulk data changes that can be inspected before they become product truth, the artifact should make ownership, constraint, and next action visible without requiring a private explanation.

Success would look like hostile fixtures contained without partial authoritative writes. If I cannot point to that evidence, I have a direction, not a finished decision.

The implementation move is to make a parser threat-and-limit table part of the working surface. I would use it to answer “Which formats are accepted?” while scope is still flexible, and “What resource limits apply?” before code or content becomes expensive to unwind. During QA, “Can nested content expand unexpectedly?” and “How are dangerous cells represented safely?” become concrete checks rather than discussion prompts. That sequence turns bulk data changes that can be inspected before they become product truth into something the team can operate and gives me a specific outcome to report: hostile fixtures contained without partial authoritative writes.

  1. CandidateParsed but not trusted

    Original cells, normalized values, source line, mapping version, and warnings remain available for review.

  2. ActionableValid, repairable, or blocked

    Policy separates automatic acceptance, operator correction, duplicate resolution, permission denial, and permanent rejection.

  3. TerminalCommitted or closed

    Each row points to a production mutation, unchanged match, rejection reason, superseding import, or verified deletion event.

Figure 2: Rows move through explicit states instead of one pass/fail flag.

Separate source from normalization

Keep raw values beside normalized candidates so trimming, case folding, date interpretation, locale conversion, and identifier cleanup remain inspectable and reversible.

Before implementation, I would answer:

  • Which value did the source contain?
  • Which rule changed it?
  • Can locale alter meaning?
  • Can the operator restore the original?

The artifact is a raw-to-normalized field trace. Its job is to expose the tradeoff early enough that design, engineering, support, or product can disagree with something concrete. The common trap is silently cleaning values until different records appear equivalent; it moves uncertainty downstream and makes the final interface carry a problem the system never resolved.

For me, the useful receipt is every transformed field carrying rule, version, and original value. That connects a staged import protocol that separates upload, parsing, normalization, validation, review, commit, reconciliation, and deletion to an observable result instead of a process claim.

I would test this with one typical case and one boundary case. The typical case should make “Which value did the source contain?” easy to answer. The boundary should force a decision about “Which rule changed it?” and “Can locale alter meaning?.” I would record both in a raw-to-normalized field trace, including the part that stayed unresolved after the first pass. The final check, “Can the operator restore the original?,” is where the artifact earns its place: it either supports every transformed field carrying rule, version, and original value, or it shows exactly why another iteration is needed.

Validate schema and business policy

Required columns, types, relationships, allowed values, permissions, tenant boundaries, protected fields, and temporal rules belong in distinct validation codes.

I would use these prompts during the working review:

  • Is the row structurally readable?
  • Is the change allowed?
  • Which relationship is missing?
  • Is a warning safe to override?

If the team slips into collapsing syntax, permission, and business-rule failures into invalid row, the product can still look complete while its operating rule stays ambiguous. I would make a versioned validation-code catalog the shared reference and keep it small enough to update as evidence changes.

The standard is operators seeing the correct repair or escalation for each defect. That tells me whether the decision helped the product, not merely whether the document was completed.

The working sequence is small: draft a versioned validation-code catalog, review it against “Is the row structurally readable?,” implement the narrowest useful path, and then return with evidence for “Is the change allowed?.” I would use “Which relationship is missing?” to inspect product consequence and “Is a warning safe to override?” to decide whether the result is stable enough to ship. This keeps collapsing syntax, permission, and business-rule failures into invalid row visible as a known risk and makes operators seeing the correct repair or escalation for each defect the release receipt rather than a hopeful conclusion.

SignalDecisionWorking note
SyntaxRepair the representationBad delimiters, encoding, dates, and column shapes can be corrected without guessing business identity.
IdentityResolve before mutationDuplicate emails, reused external IDs, and fuzzy names need provenance and a deliberate match, create, or skip decision.
PolicyReject or escalateCross-tenant references, protected fields, formula risks, and unauthorized changes should never become editable warnings.
Figure 3: Different defects require different operator choices.

Resolve identity deliberately

Exact external keys, verified emails, aliases, fuzzy candidates, and no-match cases need different confidence and authority rules before create or update is chosen.

I would pressure-test that decision with four questions:

  • Which key is authoritative?
  • Can identifiers be recycled?
  • Who may merge candidates?
  • What happens to ambiguous rows?

The failure mode here is matching on the first familiar field and updating the wrong person. In CSV, spreadsheet, JSON, XML, archive, and partner-feed imports where untrusted files can be syntactically valid while still carrying unsafe formulas, ambiguous identifiers, invalid relationships, duplicates, stale values, or changes too consequential to apply immediately, that can hide the exact boundary a reviewer or teammate needs to understand. My working artifact would be an identity-resolution decision table. I want it close enough to the implementation that it can change the work, not created afterward to decorate the story.

The result I would look for is zero silent merges across adversarial duplicate fixtures. That is a narrower claim than saying the whole system improved, but it is also one I can verify and defend.

In practice, I would put an identity-resolution decision table beside the question “Which key is authoritative?” before the first implementation review. The next pass would use “Can identifiers be recycled?” to test the boundary, then “Who may merge candidates?” to expose the state most likely to be missed. I would keep “What happens to ambiguous rows?” for the release check because it asks whether the decision still holds outside the ideal path. The work is ready to move when the artifact can explain the choice and the observed result supports zero silent merges across adversarial duplicate fixtures.

Preview product consequence

Review should show creates, changes, unchanged rows, removals, permission effects, downstream notifications, and derived recalculation in the language operators use.

The practical review starts here:

  • What will change?
  • Which side effect will fire?
  • Can protected values be hidden?
  • How large is the blast radius?

Those questions keep showing a spreadsheet preview that hides actual mutations and side effects from becoming the default. I would capture the decision in a consequence-focused import diff, then use it while the work is still cheap to change. For bulk data changes that can be inspected before they become product truth, the artifact should make ownership, constraint, and next action visible without requiring a private explanation.

Success would look like an approver able to predict counts and high-risk changes before commit. If I cannot point to that evidence, I have a direction, not a finished decision.

The implementation move is to make a consequence-focused import diff part of the working surface. I would use it to answer “What will change?” while scope is still flexible, and “Which side effect will fire?” before code or content becomes expensive to unwind. During QA, “Can protected values be hidden?” and “How large is the blast radius?” become concrete checks rather than discussion prompts. That sequence turns bulk data changes that can be inspected before they become product truth into something the team can operate and gives me a specific outcome to report: an approver able to predict counts and high-risk changes before commit.

Make approval risk-based

Routine valid rows can advance automatically while merges, destructive changes, sensitive fields, high-volume deltas, and policy overrides require named authority.

Before implementation, I would answer:

  • Which rows are auto-committable?
  • What threshold escalates?
  • Can one reviewer approve their own upload?
  • How does approval expire?

The artifact is an import approval matrix. Its job is to expose the tradeoff early enough that design, engineering, support, or product can disagree with something concrete. The common trap is requiring one broad approve button for a mixed-risk file; it moves uncertainty downstream and makes the final interface carry a problem the system never resolved.

For me, the useful receipt is high-consequence mutations separated without blocking safe routine work. That connects a staged import protocol that separates upload, parsing, normalization, validation, review, commit, reconciliation, and deletion to an observable result instead of a process claim.

I would test this with one typical case and one boundary case. The typical case should make “Which rows are auto-committable?” easy to answer. The boundary should force a decision about “What threshold escalates?” and “Can one reviewer approve their own upload?.” I would record both in an import approval matrix, including the part that stayed unresolved after the first pass. The final check, “How does approval expire?,” is where the artifact earns its place: it either supports high-consequence mutations separated without blocking safe routine work, or it shows exactly why another iteration is needed.

Commit idempotently in bounded batches

A stable import and row identity should make retries converge while transactions, checkpoints, and batch limits prevent one failure from creating an unknowable half-state.

I would use these prompts during the working review:

  • What is the logical row key?
  • Where is uniqueness enforced?
  • How is partial progress resumed?
  • Which side effects are deduplicated?

If the team slips into retrying the whole file after a timeout and duplicating already-applied effects, the product can still look complete while its operating rule stays ambiguous. I would make a row-commit and checkpoint protocol the shared reference and keep it small enough to update as evidence changes.

The standard is replay producing the same authoritative outcome and complete row ledger. That tells me whether the decision helped the product, not merely whether the document was completed.

The working sequence is small: draft a row-commit and checkpoint protocol, review it against “What is the logical row key?,” implement the narrowest useful path, and then return with evidence for “Where is uniqueness enforced?.” I would use “How is partial progress resumed?” to inspect product consequence and “Which side effects are deduplicated?” to decide whether the result is stable enough to ship. This keeps retrying the whole file after a timeout and duplicating already-applied effects visible as a known risk and makes replay producing the same authoritative outcome and complete row ledger the release receipt rather than a hopeful conclusion.

Reconcile every outcome

Source totals, candidate states, mutations, skips, rejections, notifications, downstream jobs, and deletion events should balance before the import is closed.

I would pressure-test that decision with four questions:

  • Do counts add up?
  • Which rows lack terminal state?
  • Did downstream work finish?
  • What drift requires repair?

The failure mode here is declaring success from the number of inserted rows alone. In CSV, spreadsheet, JSON, XML, archive, and partner-feed imports where untrusted files can be syntactically valid while still carrying unsafe formulas, ambiguous identifiers, invalid relationships, duplicates, stale values, or changes too consequential to apply immediately, that can hide the exact boundary a reviewer or teammate needs to understand. My working artifact would be an import reconciliation query pack. I want it close enough to the implementation that it can change the work, not created afterward to decorate the story.

The result I would look for is all submitted rows accounted for with bounded downstream exceptions. That is a narrower claim than saying the whole system improved, but it is also one I can verify and defend.

In practice, I would put an import reconciliation query pack beside the question “Do counts add up?” before the first implementation review. The next pass would use “Which rows lack terminal state?” to test the boundary, then “Did downstream work finish?” to expose the state most likely to be missed. I would keep “What drift requires repair?” for the release check because it asks whether the decision still holds outside the ideal path. The work is ready to move when the artifact can explain the choice and the observed result supports all submitted rows accounted for with bounded downstream exceptions.

Exercise the ugly files

Tests should include malformed encoding, formula payloads, oversized cells, duplicate clusters, cross-tenant IDs, parser upgrades, interrupted batches, repeated uploads, and stale approvals.

The practical review starts here:

  • Can hostile input escape quarantine?
  • Can retry duplicate effects?
  • Does parser change alter decisions?
  • Can an expired review still commit?

Those questions keep testing only a clean export from the same system that produced the mapper from becoming the default. I would capture the decision in an adversarial import fixture suite, then use it while the work is still cheap to change. For bulk data changes that can be inspected before they become product truth, the artifact should make ownership, constraint, and next action visible without requiring a private explanation.

Success would look like security, recovery, and reconciliation holding under representative failure. If I cannot point to that evidence, I have a direction, not a finished decision.

The implementation move is to make an adversarial import fixture suite part of the working surface. I would use it to answer “Can hostile input escape quarantine?” while scope is still flexible, and “Can retry duplicate effects?” before code or content becomes expensive to unwind. During QA, “Does parser change alter decisions?” and “Can an expired review still commit?” become concrete checks rather than discussion prompts. That sequence turns bulk data changes that can be inspected before they become product truth into something the team can operate and gives me a specific outcome to report: security, recovery, and reconciliation holding under representative failure.

What I would show in the work

The public version needs evidence from the work itself. For this topic, the first five artifacts I would reach for are:

  • an immutable import-source manifest
  • a parser threat-and-limit table
  • a raw-to-normalized field trace
  • a versioned validation-code catalog
  • an identity-resolution decision table

I would not publish all five at equal weight. One should orient the reader, one should reveal the hardest tradeoff, and one should prove the result. The others can live in a downloadable note or appear as supporting frames. That edit matters because a staged import protocol that separates upload, parsing, normalization, validation, review, commit, reconciliation, and deletion becomes harder to understand when every process detail is treated as equally important.

I would also show one rejected direction. The useful version is specific: which option looked attractive, which constraint made it wrong, and what evidence supported the narrower choice. That gives an engineering manager something real to question and keeps the case study from reading like the final answer was obvious from the beginning.

import-receipt.yml
# source
sha256:81… / customers.csv / parser v4
2,406 rows, UTF-8, tenant t_42, uploader u_9, source system crm-a, received 19:31Z, expires day 14.

# plan 2,311 insert / 61 update / 22 review / 12 reject Mapping v7, protected role ignored, 9 duplicate clusters resolved, spreadsheet export neutralized separately.

# result 2,372 committed / 34 closed Batches 18/18, row ledger complete, counts reconciled, rollback keys retained, source and previews scheduled for deletion.

Figure 4: The receipt closes the gap between file and production.

Resource path

The practical follow-up I would build is a data-import quarantine workbook with file identity, parser version, source provenance, schema mapping, row states, validation codes, formula-risk checks, identity conflicts, previews, approval boundaries, commit batches, rollback references, reconciliation totals, retention, and deletion evidence. I am treating that as a resource backlog item, not pretending the adjacent downloads below are the same artifact. The related cards cover useful pieces of the workflow today; this specific file should only be published when its examples, fields, and instructions are complete.

The first version should stay concise: context, constraint, decision, evidence, owner, and follow-up. Its value would come from helping someone repeat this exact review, not from adding another generic PDF to the site.

Review checklist

The article-specific review questions are:

  • Which bytes were reviewed?
  • Which formats are accepted?
  • Which value did the source contain?
  • Is the row structurally readable?
  • Which key is authoritative?
  • What will change?
  • Which rows are auto-committable?
  • What is the logical row key?
  • Do counts add up?
  • Can hostile input escape quarantine?

I would add two editorial checks before publishing: can a recruiter find the point in the first minute, and can an engineer trace at least one claim to an implementation or production receipt? If either answer is no, the article needs another edit.

Implementation notes

For bulk data changes that can be inspected before they become product truth, I would write the implementation note before polish. It would name the changed surface, source of truth, owner, failure boundary, and verification path. Those details prevent the principle from floating above the actual code or operational workflow.

The proof signals I care about are specific to this article:

  • an approver able to predict counts and high-risk changes before commit
  • high-consequence mutations separated without blocking safe routine work
  • replay producing the same authoritative outcome and complete row ledger
  • all submitted rows accounted for with bounded downstream exceptions
  • security, recovery, and reconciliation holding under representative failure

I would choose two or three of those signals for the first release rather than instrumenting everything. The strongest pair usually combines one direct behavior check with one operating check: a route and a data query, a keyboard path and a support state, a handler replay and a reconciliation result, or a migration count and a rendered screen.

The follow-up belongs in the note before shipping. It should say what remains temporary, what evidence would trigger another pass, and who owns that decision. That is how the first version stays intentionally narrow without making the boundary invisible.

Case-study packaging

I would structure the case-study version around the four visual lessons already established:

  • An import crosses trust boundaries before it reaches product tables.
  • Rows move through explicit states instead of one pass/fail flag.
  • Different defects require different operator choices.
  • The receipt closes the gap between file and production.

The opening frame explains the product pressure. The middle two show the decision moving through the system. The last frame is the receipt: what was checked, what held, and what remained unresolved. That order lets the reader move from product judgment into implementation detail without reconstructing the whole project first.

I would include one caveat tied to CSV, spreadsheet, JSON, XML, archive, and partner-feed imports where untrusted files can be syntactically valid while still carrying unsafe formulas, ambiguous identifiers, invalid relationships, duplicates, stale values, or changes too consequential to apply immediately: a data limit, rollout boundary, unsupported state, external dependency, or result that is still directional. A precise caveat makes the evidence easier to trust because it shows where the claim stops.

The final test is whether the page creates a better conversation. If the artifact helps someone ask a sharper question about product judgment, implementation detail, or release proof in a live interview, it belongs in the story.

Interview angle

In an interview, I would explain this through a staged import protocol that separates upload, parsing, normalization, validation, review, commit, reconciliation, and deletion. The story should start with the product pressure, then move into the system constraint, the artifact, and the proof. That order keeps the answer grounded. It also gives the interviewer several places to go deeper: data, frontend architecture, design systems, support, migration, accessibility, or release process.

The strongest version of the answer includes a tradeoff. I want to be able to say what I chose, what I left alone, and how I knew the work helped. That is more credible than presenting every project as a clean win.

The hiring signal

A quarantine-first import model is a hiring signal because it shows I can connect security, data modeling, product states, operator tooling, transactional writes, and recovery evidence.

That is the level I want this site to communicate. The work should show taste, but it should also show operating judgment. It should make me look like someone who can enter a real product system, understand the messy middle, ship the useful version, and leave enough proof for the next person to trust it.

Companion artifacts

Use this after reading.

Practical downloads and templates that turn the article into something you can bring into a product review, implementation pass, or agent workflow.

RepoJun 2026

Agent-Ready API Spec Template

An OpenAPI and Postman starter template for APIs that AI agents can discover, call, and recover from safely.

OpenAPIPostmanAI agents
View details
TemplateJul 2026

Human Review Escalation Matrix

A decision matrix for when AI can act, when it needs confirmation, and when a qualified human must take over.

Human reviewRiskAI UX
View details
TemplateJun 2026

Handoff Notes Template

A build-ready handoff format for scope, states, interactions, open questions, analytics, and QA.

HandoffEngineeringQA
View details