City of San Antonio · Software Engineer
Updated · 2026-09-24

City of San Antonio Software Engineer
Interview Questions & Guide 2026

THE 60-SECOND BRIEF

The Software Engineer role within the City of San Antonio is a pivotal position dedicated to building and maintaining the digital infrastructure that serves one of the nation’s largest and fastest-growing municipalities. You will be responsible for developing, deploying, and supporting mission-critical applications that directly impact the daily lives of San Antonio residents.

Most rounds test how you handle an under-specified problem more than what you recall. A wrong first approach you correct out loud is recoverable; a constraint you assumed silently and were never given is the expensive mistake.

PracHub has no confirmed round sequence for City of San Antonio. Treat the sections below as preparation areas and confirm the format with your recruiter.

Make every determination replayable from a frozen snapshotTreat accessibility conformance as a functional requirementKey idempotency on business facts, not requests

38 min read

Browse Software Engineer questions

See the practice prompts

14Practice promptsAcross five skill areas
3With worked solutionsIncluded in the practice prompts

The Software Engineer role within the City of San Antonio is a pivotal position dedicated to building and maintaining the digital infrastructure that serves one of the nation’s largest and fastest-growing municipalities. You will be responsible for developing, deploying, and supporting mission-critical applications that directly impact the daily lives of San Antonio residents.

This role is unique because it combines technical rigor with a profound sense of public service. You are not just writing code; you are facilitating government efficiency, improving accessibility to city services, and ensuring that internal systems function reliably for thousands of city employees. Whether you are working on Application Support or new feature development, your work serves as the backbone for city operations.

01

Preparation focus

editorial

No round sequence has been reported for this company, so work the categories below and confirm the format with your recruiter.

What to demonstrate

  • Breadth across SQL, experimentation and product reasoning
  • Ability to state assumptions before choosing a method

How to prepare

  • Drill the practice exercises below and time yourself
  • Prepare three quantified stories about decisions you drove
PracHub interview preparation framework ↗

PracHub editorial advice for the preparation topics above.

01

Computing a statutory due date by adding an interval to a UTC timestamp

The deadline is a civil date in a jurisdiction that observes daylight saving, and a civil day is not always 86,400 seconds; the same arithmetic also ignores weekends and a holiday list that is amended annually and differs by jurisdiction. The result is a due date off by a day near a transition, which reports a case as on time when it is late by law - the direction of the error that produces findings rather than complaints. Store the event as an instant, convert to the case's civil time zone, and walk the business-day calendar as versioned data with its own effective dates, then test the transitions and the holidays explicitly rather than the happy path in July.

02

Treating an integration partner as if it were a synchronous API when the system of record is a nightly batch

The effective consistency model is 'as of last night', so a screen that shows a constituent their updated status immediately after a submit is telling them something the authoritative system will not agree with for hours, and a caseworker who acts on it creates a conflict that surfaces as a reconciliation exception nobody owns. Read-after-write expectations also encourage retry-until-consistent loops that hammer a mainframe window sized for one pass. Make staleness explicit in the model and in the interface - show the as-of time, keep the local record in a pending state until the batch confirms, and design the reconciliation job as the place where disagreement is resolved rather than as an exception report.

03

Comparing floating-point values for equality, or holding money in them

Binary floating point cannot represent 0.1 exactly, so repeated addition drifts and an equality check fails on values that are mathematically equal. Store currency as integer minor units or a decimal type, and compare floats against a tolerance you chose for a stated reason.

04

Sharing mutable state with no stated owner

Say which thread, request or task owns each mutable structure, and what protects it when the answer is more than one: a lock, a queue that hands ownership across, or an immutable copy per reader. A structure documented as safe for concurrent reads is usually not safe for a concurrent write alongside those reads.

Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.

11 technical prompts3 include a worked solution

Rebuild an award timeline as of a past decision date

mediumWorked solution
intervalsbitemporalsweep-line

One case has up to 400 determination rows across all reopen cycles: determination_id, reopen_cycle, supersedes_determination_id, decided_at TIMESTAMPTZ, effective_from DATE, effective_to DATE (NULL meaning open-ended, both endpoints inclusive), award_amount_minor. Given a set of queries (benefit_date D, as_of decision time T), return the award in force for D according to what had been decided by T, plus any benefit dates inside the covered span that no determination covers. Later-decided wins on overlap. Give the complexity for building the answer and for each query.

Approach
  1. Convert every interval to half-open [effective_from, effective_to + 1 day) at the boundary of the system, once. Keeping inclusive ends in the algorithm produces an off-by-one at every adjacency, and the error is a single uncovered or doubly-covered day that a reviewer reads as a gap in benefit.
  2. For a given T, filter to determinations with decided_at <= T. Do not use is_current: that column answers what is in force now, and the whole point of the as-of query is that a determination decided after T must be invisible even though it exists today.
  3. Paint the surviving intervals onto a timeline in ascending decided_at order so later decisions overwrite earlier ones where they overlap. Equivalently, sweep the sorted endpoints with a max-heap keyed on decided_at and lazily discard heap entries whose interval has already ended. O(n log n) build.
  4. Answer each query by binary search over the painted, non-overlapping interval list: O(log n). Gaps fall out of the same structure as the elementary intervals with no covering determination between the minimum effective_from and the maximum effective_to of the surviving set. Note what that definition implies: deleting one determination only produces a gap where nothing else still covers those dates, so an overlapping earlier award absorbs the deletion silently and correctly.
  5. With n at most 400, a quadratic paint over elementary intervals is about 160k comparisons and is genuinely fine; say so rather than reaching for the heap by reflex. The heap earns its place when the same routine runs across a program-wide cohort rather than one case.
  6. If queries carry many distinct T values, the painted timeline is per-T and rebuilding it per query is O(Qn log n). Sort queries by T and advance one sweep through decided_at order, materialising each version as you pass it, or accept the rebuild when Q is small.
Worked solution 30 min
  1. Build five determinations for benefit year Y: d1, decided in January, pays 50000 minor units for [Jan 1, Dec 31]; d2, decided in June, pays 62000 for [Mar 1, Dec 31]; d3, decided in November on reopen cycle 1, pays 0 for [Jul 1, Sep 30]; d4, decided in December, restores 62000 for [Sep 1, Sep 30]; d5 covers [Jan 1, Jan 31] of year Y+1.
  2. Paint the timeline with T set to the end of July and read the award for a benefit date in August.
  3. Repeat with T set to the end of December and read the same August date, then read a September date under both values of T.
  4. Delete d2 alone, re-run at T in December, and read both the August award and the gap report.
  5. Delete d1 as well, leaving only d3, d4 and d5, and re-run the gap report.
EXPECTED RESULTAt T in July, August returns 62000 and September returns 62000. At T in December, August returns 0 and September returns 62000, because the November decision covers both and the December decision overwrites only September. Deleting d2 produces no gap at all: d1 still pays 50000 for the whole of year Y, so August returns 50000 and the gap report is empty — removing a superseding interval falls back to what it superseded rather than exposing a hole. Deleting d1 as well leaves a surviving span of [Jul 1 of Y, Jan 31 of Y+1] with nothing covering Oct 1 through Dec 31, and the gap report names exactly those dates.
Follow-up
  • A determination is decided with an occurred-earlier effective_from that reaches back behind an already-settled disbursement. What does the timeline say, and what does that imply for the payment side?
  • Two determinations in different reopen cycles share a decided_at to the microsecond. What is your tiebreak and why must it be total?
  • How do you answer the same question for 200,000 cases in a nightly report without rebuilding 200,000 heaps?

Replay sixty million determinations after a retroactive rule correction

hard
bulk-replayinverted-indexdeterminism

A regulator corrects three clauses of a ruleset with effect six years back. Sixty million determination rows fall under the affected rule family, each carrying rule_version_id, evidence_snapshot_hash and a trace of the clauses that fired. Evaluation is a pure function costing about 8 ms of CPU, but each replay must rehydrate the frozen evidence snapshot from a content-addressed store capped at 500 fetches per second shared with live traffic. Replaying everything is correct. Explain why it is not viable, and give the algorithm that is.

Approach
  1. Cost the naive run before optimising it. CPU is not the constraint: 60 million evaluations at 8 ms is about 133 CPU-hours and parallelises freely. The store is: 60 million fetches against a 500 per second ceiling is 120,000 seconds, roughly 33 hours of wall clock while consuming the entire budget live traffic also needs. The run is correct because replay is deterministic and unaffected determinations converge on the existing row through the partial unique index, so it is purely a cost problem.
  2. Build an inverted index from clause to determination. Either a separate determination_clause table indexed on clause_id, or a GIN index over the trace array. The three corrected clauses then yield a candidate set by index scan instead of a full scan, typically well under one percent of the 60 million rows.
  3. Recognise that the fired-clause filter alone is unsound. A correction that widens a guard makes a clause newly reachable, so determinations that never reached it before can change now, and those are precisely the denials the correction was issued to reverse. If the trace only records clauses that fired, the filter silently omits the population the regulator cares about.
  4. Close the gap with what the trace can actually support, and be explicit that the target is a sound superset, not an exact set. If the trace records evaluated-and-false clauses as well as fired ones, include both: every determination that can change is then selected, along with some that cannot — a determination that already passed the widened guard is selected and replays identical, because widening a guard cannot exclude an input it already admitted. That asymmetry is the correct trade. A false positive costs one rehydration; a false negative is an uncorrected determination. If the trace records only fired clauses, fall back to a wider superset: every determination under the affected rule_versions whose effective period intersects the corrected period, which is far larger than the clause filter and still orders of magnitude under 60 million.
  5. Deduplicate the rehydration, not the evaluation. Distinct evidence_snapshot_hash values are the unit of store work, and a single snapshot attached to several cases in a household or an appeal chain is fetched once and evaluated per determination. Order the candidate scan by hash so the cache hits are adjacent rather than scattered across the run.
  6. Make the run resumable and rate-limited by construction: a durable cursor over the candidate set, a token bucket sized to the share of the 500 per second ceiling you are permitted, and writes that rely on the uniqueness key rather than a read-then-insert, so a restart after a crash converges instead of producing a second current determination.
Follow-up
  • The correction changes an amount rather than an outcome. Does your candidate filter change, and does the notice obligation?
  • A replayed determination comes back identical. Do you write anything at all, and what does an auditor need to see that you checked it?
  • Halfway through the run the regulator issues a correction to the correction. What happens to the work already done?

Surface the fifty most SLA-at-risk cases per unit

medium
top-kheapindex-selectivity

A queue view must return the 50 cases closest to breaching their service standard for one assigned_unit_id. Candidate rows come from case: case_id, jurisdiction_code, sla_due_on DATE, submitted_at, status, assigned_unit_id. Four million cases are open across 200 jurisdictions. Risk orders by business days remaining to sla_due_on ascending, then submitted_at ascending, then case_id ascending; already-breached cases sort first and must not clamp at zero. Business days come from a per-jurisdiction holiday calendar. Give the algorithm, the complexity, and where the work must happen.

Approach
  1. Keep a bounded max-heap of size k=50 ordered by the full comparison key and stream the candidates: push, and when the heap exceeds k pop the maximum. What survives is the k smallest. O(n log k) time and O(k) space, against O(n log n) time and O(n) space for sorting the unit's whole backlog.
  2. Narrow before you compute. Business days remaining is an expression over a calendar, so no index can order by it, and a naive ORDER BY on that expression sorts every candidate row. Within one jurisdiction the business-day remainder is monotone in sla_due_on, so an index range on (assigned_unit_id, sla_due_on) with a horizon bound gives a correct prefix cheaply; compute the calendar arithmetic only on that narrowed set.
  3. Do not carry the monotonicity across jurisdictions: two jurisdictions with different holiday lists order differently for the same sla_due_on. Run the k-selection per jurisdiction and merge the per-jurisdiction heaps, or pull the narrowed union and heap it in one pass, but do not assume one global sla_due_on order is the risk order.
  4. Make the key a total order. Ties on the first two components are common because overnight batch intake stamps thousands of submitted_at values inside the same second, and without case_id as the final component two replicas computing the same list return different pages. Determinism here is a correctness property of the page, not a nicety.
  5. Pin the as-of instant for the whole computation and return it with the list. Business days remaining changes at a civil midnight per jurisdiction, so a list computed across that boundary would otherwise mix two answers and be unreproducible when someone asks why a case ranked where it did.
  6. The heap ranks; it does not assign. Handing a case to a worker is a conditional UPDATE guarded on row_version, and a zero-row result means another worker took it, so the caller drops to the next candidate rather than retrying the same row.
Follow-up
  • Two workers open the queue in the same second and both see case X first. What happens, and whose problem is it?
  • A jurisdiction's legislature adds a holiday with retroactive effect. Which cached sla_due_on values are now wrong, and how do you find them?
  • The product asks for page two of this list. What does that cost with a size-k heap, and what would you build instead?

Day one measures instead of guessing, under a fixed rubric, and the remaining hours are allocated in proportion to the gaps before any studying begins. The allocation is deliberately not renegotiated midweek, because the area that feels worst on day three is usually the one that is moving.

Small steps. Visible outcomes.0 / 7 completed
ONE WEEK · YOUR PACE

Prepare, practise & reflect

One practical outcome each day. Spend longer where you need it.

0 / 7 done
01Diagnostic, scored before you study anything
  • Sit a 110-minute diagnostic in four blocks: forty-five minutes on two coding problems, twenty-five on one design prompt taken to interface and data model, twenty of short-answer fundamentals, and twenty delivering two behavioural answers aloud.
  • Score each block from 0 to 3 on a fixed rubric where 3 is correct and fluent, 2 is correct but slow or prompted, 1 is partially correct and 0 is stuck, grading the artifact rather than how the attempt felt.
  • Allocate days two to five in proportion to 3 minus each block's score, write the allocation down, and commit to leaving it alone.

Deliverable: A scored rubric and a fixed hour allocation for the rest of the week.

Practice prompt ↗Practice prompt ↗Worked solution ↗
02Largest gap: find the boundary rather than the subject
  • Split the weakest area into named sub-skills and rate each separately. For coding those are restating the problem, choosing the structure, stating the invariant, turning the invariant into loop bounds, handling empty and single-element input, and accounting for complexity out loud.
  • Attempt three items positioned just above where the rating drops off, and for each write the first move you failed to make.
  • Re-attempt one of them from blank four hours later with nothing open.

Deliverable: A sub-skill map with the two blocking sub-skills circled.

Practice prompt ↗Practice prompt ↗
03Drill the blocking sub-skill by repeating the shape
  • Do eight short repetitions of the same shape rather than eight different problems, so what gets practised is the pattern and not the puzzle.
  • State the rule you now hold in one sentence, then test it against a case built to break it, a sliding window over an array containing negative values, or a cache-aside read path whose invalidation message is dropped.
  • Have someone else read your one-sentence rule and find the precondition you left out.

Deliverable: One rule statement with its preconditions attached and one counterexample that would have caught the incomplete version.

Practice prompt ↗Practice prompt ↗
04Second gap, plus maintenance on the strongest area
  • Run the same sub-skill decomposition on the second-largest gap in half the time.
  • Spend twenty-five timed minutes on the block you scored highest, choosing the hardest item you can still finish rather than a warm-up.
  • Write whether each area fails you on recall, on setup, or on execution, and set the fix accordingly: repetition for recall, a written checklist for setup, timed work for execution.

Deliverable: A second sub-skill map plus a one-line failure diagnosis for each area.

Practice prompt ↗Practice prompt ↗Worked solution ↗
05The gap that is not a skill
  • Record one technical and one behavioural answer, then count two things in the playback: seconds before your first clarifying question, and sentences you began without knowing where they would end.
  • Practise saying that you do not know, followed by how you would find out, without letting it soften into a guess, and practise stating a complexity or an estimate before being asked for it.
  • Redeliver one answer under a hard ninety-second cap, which forces structure ahead of detail.

Deliverable: Two recordings with a counted reduction in time-to-first-question.

Practice prompt ↗Practice prompt ↗
06Retest under day-one conditions
  • Sit the same 110-minute structure with new prompts of comparable difficulty and score it on the identical rubric.
  • For any block that did not move, change the method rather than adding hours: a block stuck at 1 usually means the practice was too varied, not too short.
  • Write down which single block you would still lose the offer on.

Deliverable: A second scored rubric placed beside the first, with one named remaining risk.

Practice prompt ↗Practice prompt ↗
07Full loop under interview conditions
  • Run a sixty-minute mock over the two blocks that moved least, with an interviewer briefed to interrupt and change direction mid-answer.
  • Write the recovery script for going blank: restate the question, state your assumption, name the first thing you would check.
  • Say every rule from the week aloud without reading it, and cut any you cannot state in a single sentence, since a rule you have to reconstruct mid-answer will not survive an interruption.

Deliverable: A one-page card holding the recovery script and only the rules you could state from memory.

Practice prompt ↗Practice prompt ↗Worked solution ↗

Expand any day for tasks and deliverables. Your progress is saved on this device.

Every story you tell gets read for blast radius and judgement: what could have broken, who else it touched, what you knew at the moment you decided. Nobody can audit your code in an hour, so they audit your reasoning instead. Pick work where the call was genuinely yours and the consequences were real enough to remember.

Reverse a decision to write audit rows asynchronously

hard
auditabilitytransactional outboxreversaldata-access boundary

You chose to write audit_access_log rows through a fire-and-forget asynchronous call so a read path would stay inside its latency budget. Months later the rows are missing in exactly the windows an investigator cares about. The table is audit_access_log(audit_id, occurred_at, actor_id, actor_role, delegation_id, subject_type, subject_id, action, purpose_code, source, client_ip, request_id, retained_until). Describe a reversal of this shape that you owned: what made the original choice defensible, the evidence that changed your mind, what replaced it, and what the migration cost.

Approach
  1. State the original reasoning without apologising for it. The read path had a budget, the audit write is not on the user's critical path, and asynchronous is the textbook answer. A reversal narrative that opens with 'it was obviously wrong' tells the interviewer you never understood why anyone chose it, which makes the reversal luck rather than judgement.
  2. Give the evidence in the form that actually moved people: not 'some rows are missing' but a measured drop ratio against a known denominator, counting audited reads at the data-access boundary versus rows landed, bucketed by hour, showing loss concentrated in the highest-load hours. Those are the hours an investigation will later want to reconstruct, which is what makes the loss non-random rather than merely unfortunate.
  3. List the bypasses separately from the drops, because they need different fixes: a read replica, a report extract, a cache hit that never touches the table, and a search that returned the record, since a search hit is an access even if nobody opened the result. Some of those can only be closed below the application, in a policy or a view, rather than in a controller.
  4. Choose between same-transaction and an outbox deliberately and price both. Writing the audit row inside the read's transaction turns every audited read into a write transaction, which rules out serving it from a read replica at all and couples read availability to the audit table. The outbox keeps the read path fast but is only trustworthy with a liveness alarm on the age of the oldest unpublished row, not on whether the publisher process is up.
  5. Cost the migration honestly. The gap in the historical record cannot be backfilled from anything, so part of the reversal is documenting that period as incomplete and saying so out loud, rather than quietly starting to be correct from a Tuesday.
Follow-up
  • The outbox publisher is wedged for six hours. What does the read path do in the meantime, and who is told, and when?
  • How do you prove to an auditor that capture cannot be bypassed, instead of asserting that it is not?
  • purpose_code is an enum precisely so it is auditable. What stops staff from always selecting whichever value sorts first?

Explain a denied determination to an auditor and a caseworker

easy
communicationprovenanceappealsevidence

A determination denied an application and the constituent has appealed fourteen months later. An auditor wants to know which rules were applied and why; a caseworker wants to know what to tell the constituent this afternoon. You have the determination row (rule_version_id, evidence_snapshot_hash, ordered reason_codes, clause trace, decided_by), the case_event history and the per-channel notice dispatch record. Write both explanations. State what you will not assert, and what you would check before asserting it.

Approach
  1. Answer the two audiences separately, because they need different objects. The caseworker needs the ordered reason codes turned into what the constituent can do next; the auditor needs provenance: which rule_version governed, which clauses fired, which evidence snapshot fed them, and who or what decided.
  2. Lead the auditor's version with the fact that decided_by being NULL means the determination was fully automated, which is a materially different fact from a human decision and is the first thing they will ask about. Papering over it costs you the rest of the conversation.
  3. Separate what the record proves from what you are inferring. The record proves which clauses fired against which evidence hash. It does not prove the constituent received the notice, because dispatch is recorded per channel and dispatch is not receipt.
  4. Distinguish procedural reason codes from substantive ones, since they lead to opposite advice: evidence not returned is curable by sending a document, while a determination over a threshold is not, and the caseworker will act on whichever you imply.
  5. Say what you would verify before asserting any of it: replay the determination against its own rule_version_id and evidence_snapshot_hash and confirm it reproduces byte for byte, and report a mismatch as a different question rather than as an answer.
Follow-up
  • The replay does not reproduce the original outcome. What do you do first, and what do you tell the auditor in the meantime?
  • The caseworker asks you to describe it as a system error so the conversation is easier. How do you handle that?
  • The rendered notice is itself evidence. What does that imply about template versions and fonts?

Unblock an engineer whose replay creates duplicate determinations

easy
mentoringidempotencyreplayconstraints

An engineer's bulk replay job, re-running determinations after a rule correction, has left some cases with two rows flagged current and has re-issued notices for cases whose outcome did not change at all. They have been on it for two days and are now proposing a cleanup script to delete the extra rows. Describe unblocking someone in this shape: how you found where their model was wrong, what you had them do first, and how you left them able to handle the same class of bug without you.

Approach
  1. Get the invariant said out loud before anyone touches code. 'A replay that changes nothing writes nothing' is usually the sentence they have not yet said, and saying it reframes the problem from a concurrency puzzle into a missing no-op check, which is a different and much smaller fix.
  2. Separate the two failures they have merged into one bug. Duplicate current rows are a concurrency defect the database should have rejected; re-noticing unchanged cases is a logic defect in the job. A cleanup script addresses neither, and running it before the constraint exists guarantees running it again next week.
  3. Have them reproduce the smaller failure themselves — two concurrent inserts against a table with no partial unique index — rather than describing it. A reproduction they built transfers to the next bug; a diagnosis handed to them does not.
  4. Be explicit about what you deliberately did not do: you did not take the keyboard, and you did not let the cleanup script go first. Say how you decided that, because with an incident running the wrong answer is to teach instead of to stop the bleeding, and the judgement call is the interesting part.
  5. Close the loop on repeatability for them: a no-op predicate compared before writing, a dry-run mode whose output is counts by reason code, and agreement on who reviews the next replay before it runs.
Follow-up
  • Notices already went to constituents whose determination did not change. What are they told, and who writes it?
  • How do you tell whether the duplicate rows came from concurrency or simply from the job being run twice?
  • What changes in your approach if an auditor found this rather than the engineer?
  • 01

    You chose to write audit_access_log rows through a fire-and-forget asynchronous call so a read path would stay inside its latency budget. Months later the rows are missing in exactly the windows an investigator cares about. The table is audit_access_log(audit_id, occurred_at, actor_id, actor_role, delegation_id, subject_type, subject_id, action, purpose_code, source, client_ip, request_id, retained_until). Describe a reversal of this shape that you owned: what made the original choice defensible, the evidence that changed your mind, what replaced it, and what the migration cost.

  • 02

    A determination denied an application and the constituent has appealed fourteen months later. An auditor wants to know which rules were applied and why; a caseworker wants to know what to tell the constituent this afternoon. You have the determination row (rule_version_id, evidence_snapshot_hash, ordered reason_codes, clause trace, decided_by), the case_event history and the per-channel notice dispatch record. Write both explanations. State what you will not assert, and what you would check before asserting it.

  • 03

    An engineer's bulk replay job, re-running determinations after a rule correction, has left some cases with two rows flagged current and has re-issued notices for cases whose outcome did not change at all. They have been on it for two days and are now proposing a cleanup script to delete the extra rows. Describe unblocking someone in this shape: how you found where their model was wrong, what you had them do first, and how you left them able to handle the same class of bug without you.

PracHub interview preparation framework ↗
Is this an official City of San Antonio interview guide?

No. It is PracHub's own research and practice material for the Software Engineer role at City of San Antonio. Rounds and questions reflect what candidates have reported, not a process City of San Antonio has published, and they change over time. Confirm the current format and scope with your recruiter.

PracHub interview research ↗
How difficult are the technical interviews?

The technical interviews focus on core fundamentals and your ability to solve practical problems. If you have a solid grasp of your primary tech stack, you will find the questions focused and fair.

PracHub interview research ↗
What is the typical timeline for the process?

The timeline can vary based on the specific department's current projects. Generally, you should expect a few weeks from the initial screen to the final decision.

PracHub interview research ↗
Is this role fully remote?

Most roles at the City of San Antonio require a presence in the local area to facilitate collaboration. Check your specific job posting for details regarding hybrid or on-site expectations.

PracHub interview research ↗
Sources & methodology 3 sources ↗

No official company page is cited. Rounds and questions come from candidate reports and PracHub editorial material; each source shows the date it was read.