At Fuse Energy, a Software Engineer is not just a coder; you are a core builder of a modern, vertically integrated energy utility. The company is reimagining how electricity and gas are distributed, managed, and consumed. To achieve this, the engineering team builds high-performance, real-time software systems that interface directly with energy grids, manage complex transactional databases, and orchestrate high-throughput queuing pipelines.
The impact of your work in this role is immediate and highly visible. You will be responsible for developing the APIs, backend services, and client-facing interfaces that power the entire utility infrastructure. Because Fuse Energy operates in a highly regulated and physically constrained domain, your code must be exceptionally reliable, performant, and scalable. You will work on problems ranging from real-time grid balancing and consumption tracking to automated billing and customer management.
This role requires a unique combination of technical excellence and extreme ownership. The environment is fast-paced, highly demanding, and optimized for rapid execution. For engineers who thrive on solving tangible, real-world problems and are willing to dedicate themselves to a high-intensity mission, this position offers an unparalleled opportunity to drive systemic change in the global energy landscape.
Recruiter Screen
reportedHalf of this call is the part candidates treat as small talk: start date, notice period, work authorisation and its timing, location and time zone, on-call, and the number. Those are what kill offers late, after several engineers have each spent a day. Surfacing a hard constraint now costs you nothing and occasionally buys you something, since a loop compressed to fit a competing deadline can usually only be arranged if it is asked for early. The common failure is deflecting the compensation question twice, then discovering at offer stage that the band never reached your number.
What to demonstrate
- Whether your hard constraints are compatible with the role before a loop gets booked: earliest start, notice period, what authorisation you hold and when it needs action, days on site, willingness to carry a pager
- Whether you give a compensation range with something behind it, such as current total compensation or a competing timeline, rather than leaving the band untested
- Whether your stated timeline is real, since a competing deadline raised now is something scheduling can sometimes work around and the same deadline raised at offer stage usually is not
How to prepare
- Write each constraint down in one line before the call and state them as facts rather than negotiating them live under a question you were not expecting
- Set your range from two or three current data points for that level and location, and name the structure you are quoting in, so the number is comparable to the one they are holding
- If another process is running, say where it stands and by when, and ask directly whether this loop can be scheduled inside that window
Technical Rounds
reportedMost of the time lost in this format is not lost to thinking. It goes to a standard-library call you half-remember, an off-by-one in a loop bound, and a debugging loop that mutates code at random until something passes. When output is wrong, stop re-reading the whole function: take the smallest input that reproduces it and walk the state through by hand, printing intermediates if the environment allows. Guessing at a fix without a failing case you understand is how a five-minute bug becomes twenty, and the clock does not pause while you do it.
What to demonstrate
- Whether you reach the right structure without a detour, and can write it from memory rather than only recall that one exists
- Whether overflow is considered where the language has fixed-width integers, since a signed 32-bit value stops at 2,147,483,647 and then wraps in Java, is undefined behaviour in C++, and does not arise in Python, whose integers grow instead
- Whether recursion depth is treated as a constraint on large inputs, given that CPython's default limit is 1000 frames and a deep recursion can exhaust the stack in any language where an iterative version would not
- Whether a failing case is isolated and explained before any edit is made to the code
How to prepare
- From an empty file and with no references open, implement the pieces you lean on most: a heap push and pop, an iterative DFS with an explicit stack, and a binary search whose midpoint is written lo + (hi - lo) / 2, which avoids the overflow that (lo + hi) / 2 can hit in a fixed-width integer type
- Time yourself on the ten library calls you look up most, such as sorting with a custom comparator, splitting and joining strings, and finding the next key at or above a value in an ordered map, until the lookup is gone
- Take a solution you know is broken and, before touching it, write one sentence naming the input, the expected value and the actual value. Repeat until you do it without deciding to.
Final Conversations
reportedWhere the day includes a partner from product, design or data, that conversation is weighted like the technical ones and prepared for least. They are deciding one thing: whether having you in the room makes their decisions cheaper. That means options with costs attached, not implementation detail and not "it depends". An estimate someone can plan against — a range, the assumption that would push it to the high end, and what you would drop to hit the low one — is worth more than a confident single number, which everyone present already knows is wrong.
What to demonstrate
- Whether an estimate comes as a range with the assumption most likely to break it, and states what a specific scope cut would actually buy
- Whether a technical constraint is handed over as a choice with consequences on their side, rather than as a verdict they have no standing to argue with
- Whether you establish what decision is on the table before proposing anything
- Whether risk is raised while it can still change the plan, with the trigger that would confirm it, instead of reported afterwards as a slip
How to prepare
- Take a project that shipped late and write the two-sentence warning you could have given three weeks earlier, naming what you would have needed decided at that point
- Rehearse one estimate out loud until it arrives in three parts: the range, the single assumption that would blow it, and the smallest thing you would cut to protect the date
- Rewrite an objection you have actually made — the "we can't do that" version — as two options with their costs, so the choice ends up with the person who owns it
PracHub editorial advice for the preparation topics above.
Treating the database as the truth about physical stock
Every system in this domain drifts from reality, through miscounts, unrecorded damage, mis-scans and theft, so a design with no adjustment path forces the drift somewhere worse. The usual shape is a CHECK constraint or application guard that clamps a position at zero: the negative that would have exposed a missing receipt is silently swallowed, and the first visible symptom is a picker standing at an empty location for an order the system promised. The correct posture is to let the invariant fail loudly - record the cycle-count adjustment as a first-class movement with its own reason code, surface the variance, and let planning see that this location is unreliable - because an adjustment that is indistinguishable from a normal pick destroys the only signal that would have found the root cause. A related version of the same mistake is deleting or updating a movement row to fix a mistake, which leaves the position correct and the history a lie.
Holding a database transaction open across a physical or third-party operation
It is natural to open a transaction, lock the position, call the rating or tendering API, and commit on the response, and it works perfectly until the partner's p99 goes from 200 milliseconds to thirty seconds. At that point every request holding a lock on a hot item-node pair queues behind it, the connection pool fills with transactions that are waiting on the network rather than on the database, and an unrelated service sharing the pool fails at the same moment. In this domain the effect is amplified because demand concentrates on a few hot rows during a promotion or a seasonal peak, exactly when partner latency is also degraded. The structural fix is to keep transactions short and local - commit the state change together with an outbox row, let a relay perform the external call, and reconcile asynchronously - accepting at-least-once delivery and making the effect idempotent rather than trying to stretch a transaction over something the database cannot roll back.
Tests that assert on the implementation rather than the behaviour
Assert on what a caller can observe, not on the number of internal calls or the shape of a private field. A test that breaks on every refactor but still passes when the answer is wrong costs more than it protects.
A cache with no invalidation story
Say how an entry goes stale, how long you can serve it stale, and what happens when many requests miss the same key at the same instant. One popular key expiring under load sends every concurrent request to the origin together; single-flight coalescing, jittered expiry, or serving stale while revalidating are the standard answers.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
Design and implement a clean interface for a real-time data parser, fo…
Design and implement a clean interface for a real-time data parser, focusing on error handling and modularity.
Approach
- State the target complexity and say which constraint rules the naive version out.
- Walk one small example through your approach before writing the whole thing.
- Name the brute-force solution and its complexity before improving on it.
Follow-up
- Which test case would catch an off-by-one here?
- How does this change if the input no longer fits in memory?
Refactor a poorly structured block of code to improve its extensibilit…
Refactor a poorly structured block of code to improve its extensibility and readability without breaking existing functionality.
Approach
- Name the brute-force solution and its complexity before improving on it.
- Walk one small example through your approach before writing the whole thing.
- State the target complexity and say which constraint rules the naive version out.
Follow-up
- What is the worst case, and how likely is it on real data?
- How does this change if the input no longer fits in memory?
Implement a fully functional version of Tetris within a one-hour time …
Implement a fully functional version of Tetris within a one-hour time limit, ensuring modular code structure and handling multiple feature requests sequentially.
Approach
- Name the brute-force solution and its complexity before improving on it.
- State the target complexity and say which constraint rules the naive version out.
- Walk one small example through your approach before writing the whole thing.
Follow-up
- Which test case would catch an off-by-one here?
- How does this change if the input no longer fits in memory?
Fold late out-of-order status events into a monotonic leg state
Leg statuses form the chain planned < tendered < accepted < picked_up < in_transit < delivered, with exception and cancelled outside it. You ingest 300 million observation_event rows a day carrying subject_id (leg), observed_status, occurred_at, received_at, clock_offset_ms and dedupe_key; five percent arrive over an hour late and a tail arrives a day late. Write the merge that produces each leg's current status, prove the result depends only on the set of events and not their order, and state the per-event cost.
Approach
- Define the per-leg state as a tuple ordered totally:
(status_rank, occurred_at, source_priority, event_id), and definemerge(a, b)as the maximum under that order. Rank leads;occurred_atand the rest only break ties. The proof is then one line: maximum over a total order is idempotent, commutative and associative, so the state space withmergeis a join-semilattice and the fold over any permutation of the event set yields the same value. That is also why no global sort is needed — the O(n log n) disappears and the fold is O(1) per event, O(distinct legs) state. - Rank before time, deliberately.
occurred_atis device-reported and sometimes wrong; if it led the comparison, the leg's status would be handed to whichever device has the most badly skewed clock. Ranking first means a bad clock can only reorder events within one rank. Correctoccurred_atbyclock_offset_mswhere it was measured, and where the offset exceeds a threshold keep the observation but bar it from winning a tie — the event is still evidence, it just stops being authority. - Make the lattice total, because
exceptionandcancelledare not points on the chain andmaxover a partial order is undefined for incomparable pairs. Modelcancelledas an absorbing top element, and carryexceptionas a boolean flag merged by OR alongside the rank rather than as a rank of its own — otherwise an exception at rank 4 either blocksdeliveredat rank 6 or is erased by it, and both are wrong. A product of semilattices is a semilattice, so the order-insensitivity argument still holds over the tuple. - Deduplicate on
dedupe_keyeven though the merge is idempotent. Idempotence covers a byte-identical redelivery; a partner replaying a window with a freshevent_idis not identical, and the tie-break would let the replay displace the original for no reason. Dedupe on the stable key, then fold — both halves are needed, and conflating them is the usual defect. - Partition the stream by
subject_idso all events for one leg land on one partition: broker ordering guarantees are per-partition only, and while a commutative merge makes interleaving harmless, a concurrent read-modify-write on the same leg row is still a lost update. Where that cannot be guaranteed, make the write a compare-and-set on a version column, or a conditional update that only raises the state. Because the state is mergeable, shard maps combine cleanly and replaying the whole day converges to the same answer — which is what makes reprocessing safe. - Say where genuine regressions live: a delivered shipment that is refused and returns is a new leg, not a rank decrease. Monotonicity is only sound if real reversals are modelled as new objects, and keeping every superseded observation is what lets you answer the dispute later, so the fold discards nothing — it marks losers
superseded.
Worked solution 40 min
- Write the rank table and the tuple comparison explicitly, including where
cancelledand theexceptionflag sit, before any pipeline code. - Implement
merge(a, b)as a pure function and test the three algebraic laws directly:merge(a, a) == a,merge(a, b) == merge(b, a), andmerge(merge(a, b), c) == merge(a, merge(b, c)). - Build a 200-event batch across five legs including an out-of-order
picked_upafterdelivered, a duplicateddedupe_key, onecancelled, oneexception, and one event with a three-hour clock offset. - Fold the batch, then fold 50 random permutations of it and assert every run produces identical per-leg state.
- Re-feed the entire batch a second time and assert the state is unchanged, which is idempotence end to end rather than only in the merge function.
Follow-up
- An event arrives a week late for a leg already closed and invoiced. Does it change the status, the on-time metric, both, or neither?
- Two events for one leg have the same rank and the same
occurred_atfrom different sources. What decides, and is that decision stable across a replay? - How would you test order-insensitivity rather than assert it?
Decide whether available-to-promise is derived or stored
Available to promise at one node equals inventory_position.qty in state on_hand minus the sum of allocation.qty in status held or committed for that key. The read sits inside checkout: 4,000 reads per second at peak, p99 budget 20 ms. inventory_position holds 40 million rows; during a promotion a single hot item-node pair carries about 2,000 open allocations. Decide whether to compute this per read or to maintain available_qty on the position row. Give both paths, the failure mode of each, and what the browse read may do that the allocate read may not.
Approach
- Cost the derived read in tuples, not in plans. One index probe into the position is trivial; the aggregate over allocation touches one tuple per open claim on that key. Even if only a tenth of peak lands on the hot pair, 400 reads per second times 2,000 rows is 800,000 index tuples per second for one item at one node, and it gets worse exactly as the key gets hotter. A partial index on status IN ('held','committed') does not help, because the row count is the cost, not the selectivity.
- Maintaining available_qty on the position row is nearly free on the contention axis, which is the point most candidates miss. The allocator already takes a row lock or a compare-and-set on that same position row, so the extra column costs no lock that was not already held, and the read collapses to a single primary-key probe well inside 20 ms.
- It is not free on the correctness axis. available_qty becomes a second derived value that can drift, so it joins qty under the same reconciliation job with its own re-sum against the allocation table, and a drift alert on that comparison is the operational price of the read speed.
- Split the two reads rather than arguing about one. The browse read may serve from a replica or a short-TTL cache and must err low, showing less than is there. The allocate read must be on the primary and inside the same transaction as the conditional update, because replication lag peaks during the write burst that made the key hot. Conflating them is what makes a replica read look safe in a benchmark.
- Pick the TTL against the drain rate, with a number. If a promotion burns 2,000 units in a minute, a 30-second cache is a thousand units stale, so the displayed figure should be a banded signal such as in stock or low stock rather than an exact count that the allocate step will then contradict.
- Do not denormalise availability across nodes into a single network number. A yes-somewhere answer cannot be allocated against, so sourcing will disagree with the page, and the customer sees a promise retracted after checkout rather than an honest out-of-stock before it.
Follow-up
- Roll this out on a live system. How do both paths run side by side, what do you compare, and what result gates the cut-over?
- The reconciliation job finds available_qty drifted by 3 on one key. What do you do, and what must you not do?
- Lot-tracked items multiply the position rows per item-node. Does your answer change, and where does the read now spend its time?
Model the movement ledger so a retried write is a no-op
inventory_movement is append-only: movement_id, item_id, node_id, lot_id, state, delta_qty (signed BIGINT), uom_code, reason_code, ref_type, ref_id, idempotency_key, occurred_at, recorded_at, reversed_by. inventory_position is keyed (item_id, node_id, lot_id, state) with qty, version, last_movement_id. Give the DDL constraints and the exact statements a pick confirmation runs so that a client which times out after the commit and retries changes nothing. Then say how you correct a pick recorded against the wrong lot two days ago, and why the position carries CHECK (qty >= 0) rather than clamping at zero.
Approach
- Put the guarantee in the schema, not the handler: UNIQUE (idempotency_key) on inventory_movement. A SELECT-then-INSERT cannot work, because two concurrent retries both read nothing before either commits and both then insert.
- Claim with INSERT ... ON CONFLICT (idempotency_key) DO NOTHING RETURNING movement_id, and branch on rowcount. Zero rows means the first attempt already committed, so the handler returns success without touching the position. This branch is the whole point: applying the position update on the conflict path is what makes the ledger and the shelf disagree by one pick forever.
- Keep the insert and the position update in one transaction: UPDATE inventory_position SET qty = qty + :delta, version = version + 1, last_movement_id = :id WHERE item_id = :i AND node_id = :n AND lot_id = :l AND state = :s AND version = :v, then test the rowcount and retry the transaction on zero.
- Use lot_id BIGINT NOT NULL DEFAULT 0 rather than NULL. In a default unique index NULLs are distinct from each other, so a NULL lot would let two position rows exist for the same untracked item and split the running sum in half.
- Correct the mis-keyed pick with two compensating movements, never an UPDATE or a deleted_at flag: one reversal restoring the wrong lot, one fresh pick against the right lot, both with reason_code = 'reversal' or 'pick' and ref pointing at the original movement_id. The original row keeps its values; reversed_by is a back-pointer written in the same transaction so a reader does not need a reverse scan to see that the row was undone.
- CHECK (qty >= 0) aborts the transaction and surfaces a real defect. GREATEST(qty + :delta, 0) writes a plausible number instead, so the missing receipt that caused the negative is never investigated and the first symptom is a picker at an empty location.
Worked solution 20 min
- Write the two CREATE TABLE statements including UNIQUE (idempotency_key), the composite primary key on the position, CHECK (qty >= 0) and lot_id NOT NULL DEFAULT 0.
- Write the handler as one transaction: the ON CONFLICT DO NOTHING RETURNING insert, the rowcount branch, then the versioned conditional UPDATE with its own rowcount test.
- Send the same pick twice with one idempotency key and assert one movement row and a position that moved by delta once, not twice.
- Apply the lot correction as two new movements and show that summing delta_qty per lot now matches the shelf while both the wrong and the right lot retain a legible history.
Follow-up
- Two retries of the same pick arrive concurrently on different application instances. Walk through both transactions statement by statement and say which one commits a position change.
- occurred_at from a handheld is five minutes ahead of recorded_at because the device clock drifted. Which of your queries break, and which column should each of them actually be using?
- How long do you keep idempotency_key unique for, given the table grows by tens of millions of rows a month?
How would you architecture a multi-client notification system that gua…
How would you architecture a multi-client notification system that guarantees at least-once delivery under high network latency?
Approach
- Fix the scope first: who calls this, how often, and what they do when it fails.
- State the consistency you need, and where you are willing to be stale.
- Choose a partition key and say what query it makes expensive.
Follow-up
- How does this behave when that dependency is down for an hour?
- What would you drop to keep the system up under load?
Explain how you would design a highly available billing pipeline that …
Explain how you would design a highly available billing pipeline that processes millions of transactions daily without data loss.
Approach
- Choose a partition key and say what query it makes expensive.
- Name the read and write paths separately; they rarely have the same bottleneck.
- State the consistency you need, and where you are willing to be stale.
Follow-up
- What breaks first when traffic grows ten times?
- How does this behave when that dependency is down for an hour?
Fan shipment status out to five thousand customer webhooks
Customers subscribe to shipment status by webhook: 5,000 endpoints, some with an 8 second p99, some down for a day. The upstream is folded leg status, not raw observations. Requirements are per-shipment ordering at each subscriber, at-least-once delivery with a stable dedupe id, and no subscriber able to slow another. Assume 3 million legs a day, about six status transitions each, and a mean of three subscribers per shipment. Design the fan-out and quantify what folding first saves you.
Approach
- Fan out transitions, not observations, and do the arithmetic before designing delivery. Raw ingest averages 9,000 observations a second, about 780 million a day. Three million legs at six transitions each is 18 million notification sources a day, 208 per second, and three subscribers apiece is 54 million deliveries a day, 625 per second. Folding first is worth a factor of about 43 - 208 sources per second instead of 9,000, and 625 deliveries per second instead of roughly 27,000 - and that factor dominates every subsequent optimisation, so settle it before tuning delivery.
- Keep delivery state as a durable per-subscriber cursor over a per-subscriber queue rather than a row per attempt. At 54 million deliveries a day a row per attempt is roughly 19.7 billion rows a year before a single retry is counted, and retries only add to it; a cursor plus a bounded in-flight window gives retry and progress without any of them. Per-event rows earn their cost only where you must later prove a specific delivery in a dispute, so scope them to the subscribers who contract for that rather than to all 5,000.
- Preserve ordering deliberately: a bounded in-flight window greater than one can reorder. Give each subscriber's queue a small number of lanes keyed by hash(shipment_id), so order is strict within a lane and parallelism comes from lanes. Ordering is then a property of the key, not of a hopeful single-threaded consumer.
- Isolate subscribers with a per-subscriber concurrency cap drawn against a shared worker pool. By Little's law an 8 second endpoint receiving 20 notifications per second wants 160 workers in flight; without a cap it takes them from the pool and starves the other 4,999. The cap converts a slow subscriber into its own growing backlog instead of a shared outage.
- Handle the dead endpoint as a bounded liability: circuit-break after consecutive failures, stop attempting, let the cursor lag, and retain the queue to a fixed horizon such as 72 hours. At the horizon, advance the cursor, record a gap, and tell the subscriber to re-sync from the pull API. Unbounded retention for one dead customer is how the fan-out store becomes the next incident.
- Make at-least-once an explicit contract rather than an accident: every payload carries a stable event id and the leg's status_rank, so a customer can discard a duplicate or a stale retry on their side, and that requirement is documented rather than discovered.
Worked solution 30 min
- Derive the notification rate from legs per day, transitions per leg and subscribers per shipment, set it beside the raw observation rate, and state the reduction factor that justifies folding first.
- Choose between per-event delivery rows and a per-subscriber cursor, and show how the chosen shape still preserves per-shipment ordering under retry.
- Set a per-subscriber concurrency cap and compute an 8 second endpoint's in-flight occupancy at its share of traffic.
- Write the circuit-breaker states, the retention horizon and the re-sync contract for a subscriber that returns after a day offline.
Follow-up
- A customer demands exactly-once. What can you actually offer, and what must they implement to get the effect they want?
- One subscriber covers 40 percent of all shipments. What breaks first in a per-subscriber queue design, and what do you shard on instead?
- How do you replay a day of notifications for one subscriber after a bug on your side, without re-sending to the other 4,999?
Allocation p99 hits nine seconds while database CPU stays flat
At 14:10 allocation p99 went from 30 ms to 9 s and an unrelated read service sharing the connection pool began failing. Database CPU and mean statement time are unchanged. pg_stat_activity shows 80 of 100 connections in state 'idle in transaction' with a mean transaction age of 18 s, and lock waits concentrated on about 30 inventory_position rows. In the same minute a carrier's rate-quote p99 went from 180 ms to 22 s. Give the ordered diagnosis, the immediate mitigation, and the structural fix.
Approach
- Ask whether the database is working or waiting, because the two look the same from the client. Flat CPU and flat mean statement time with most connections in 'idle in transaction' says the database is idle inside open transactions: the application has begun a transaction and gone off to do something else. That state name is the whole diagnosis and it points at application structure, not at the database.
- Tie the holders to the dependency rather than assuming the link. Compare the distribution of now() minus xact_start against the carrier's latency histogram in the same window; when the two track each other, the transaction is wrapping the external call. The 18 s mean transaction age against a 22 s partner p99 is that match.
- Locate the contention: join pg_locks to pg_stat_activity, group by the locked tuple, and confirm the waits concentrate on a few dozen hot (item_id, node_id) keys. Demand concentrates on those rows precisely during a promotion, which is also when partner latency degrades, so the two curves multiply rather than add.
- Mitigate without a deploy where possible. Set a call timeout on the partner shorter than the lock budget, set idle_in_transaction_session_timeout and lock_timeout so a stall sheds instead of queueing, and give the carrier gateway its own connection pool so one degraded partner cannot drain the pool an unrelated service depends on. A circuit breaker on that partner turns a 22 s wait into an immediate, handled failure.
- Fix the structure: take the external call out of the transaction. Write the allocation state change and an outbox row in one short local transaction, let a relay make the rating or tender call asynchronously with a persisted idempotency key, and advance the saga on the result. Lock hold time then equals local work, single-digit milliseconds, and is independent of any partner.
- Accept and handle what the outbox costs you. Publication becomes at-least-once, so the consumer and the external effect must both be idempotent, and the caller now sees an asynchronous outcome it must be designed for. That is the trade: bounded lock hold time in exchange for eventual consistency and duplicate delivery you have to absorb.
Follow-up
- Your mitigation adds a lock_timeout. What does the allocation path do when it fires, and what does the customer see?
- Even with short transactions, 30 rows absorb most writes on promotion day. How do you keep those keys from serialising everything?
- How do you test this before the next promotion without a degraded partner to hand?
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.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Diagnostic, 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 ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Nobody is scoring your stamina at three in the morning. What carries weight is which signal told you something was wrong, what you measured before touching anything, what you rolled back versus what you fixed forward, and why you picked one. 'We restarted it and it went away' is a story about not knowing.
Ship freight cost attribution with named, dated debt
You have eight working days to get freight cost onto order margin. The correct model allocates each shipment_leg cost across the orders on that leg through a bridge, with a stated basis such as billable weight, and attaches accessorials to the stop that incurred them. The version that fits the window copies linehaul_cost_cents onto each line, split evenly. Describe a time you shipped known debt: exactly what you cut, the guard that made the shortcut visible rather than silent, who agreed to carry it, the date it was paid down, and what it cost while it stood.
Approach
- State the accepted failure concretely rather than as a category: on a multi-stop load, an even split charges a two-pallet order the same freight as a twenty-pallet order, and a detention accessorial incurred waiting at one stop is smeared across orders that were not there. Margin on small orders is understated and on large ones overstated, in a way that is systematic rather than random, so it will not average out.
- Make the shortcut loud. Emit a counter on legs with more than one order, tag every attributed row with the basis used so downstream consumers can filter, and report the share of cost that went through the even split. A shortcut that reports its own frequency converts an unknown into a number you can take to the paydown conversation.
- Bound the exposure before shipping: count historical legs with more than one order and the weight dispersion within them. If ninety percent of legs are single-order parcel, the debt is small and quantified; if a third are multi-stop truckload, the plan does not survive contact and you learned that in a query rather than in a finance review.
- Handle the arithmetic correctly even in the shortcut, because integer minor units do not divide evenly. Splitting 100,003 cents across three orders must assign the residue deterministically, to the largest order or to the first by id, and the sum of the parts must be asserted equal to the leg cost; rounding each share independently is how a reconciliation against the carrier invoice ends up off by cents nobody can explain.
- Name the owner, the date and where both are written, then report what actually happened: how much cost flowed through the shortcut, whether the paydown date held, and if it slipped, by how long and what finally forced it.
- Distinguish debt you can pay from debt that compounds. An attribution you can recompute from shipment_leg and the bridge later is recoverable; one that overwrites the leg cost or discards the stop detail destroys the inputs and cannot be unwound, and a strong answer says it would have refused that version at any deadline.
Follow-up
- The paydown date arrives and the team has a new deadline. What is different about this conversation from the first one?
- Finance has been reporting margin off this for six weeks. What do you tell them, and what do you restate?
- Which version of this shortcut would you have refused outright, and why that one?
Argue against serving available-to-promise from a cache
The availability read sits inside checkout with a p99 budget in the low tens of milliseconds, and it is missing it. A senior engineer proposes serving available-to-promise from a two-second in-memory cache, falling back to a read replica, and leaving the allocation write untouched. You believe this is either harmless or an overselling bug depending on one detail nobody has stated. Describe a design you argued against: the distinction you drew, the evidence you brought, the alternative you offered, and what was actually decided. Be specific about the failure you predicted and whether it happened.
Approach
- Draw the distinction the room is missing before arguing anything: an advisory availability read that decorates a page is a different object from the check that gates an allocation write. Caching the first is ordinary; caching the second removes the atomicity that no-over-allocation depends on, because the check and the write must be one step.
- Make the argument falsifiable with the schema rather than with principle. If the allocation still commits through UPDATE inventory_position SET qty = qty - :n, version = version + 1 WHERE (item_id, node_id, lot_id, state) = (...) AND version = :v AND qty >= :n, with the affected-row count tested, then a stale cache produces failed attempts and a worse conversion rate, not oversold stock. If the write trusts the cached number, the cache is the bug. Ask which one is on the branch.
- Quantify the exposure instead of asserting it. On a hot item-node pair taking 40 allocation attempts per second with a two-second staleness window, roughly 80 attempts can be decided against an unchanged number; multiply by the fraction of pairs whose available quantity is below that to get the oversell rate, and note that both factors peak on the same day. Replication lag has the same shape and is worse, because lag grows precisely under the write burst that makes availability tight.
- Offer a cheaper path to the latency goal so the argument is not simply obstruction: serve the browse and search paths from the cache with an explicit staleness label, keep the authoritative check on the primary row, and attack the p99 where it actually is by measuring whether the cost is the query, the connection pool wait, or fan-out across nodes for a multi-node promise.
- Say where you were willing to lose. If the measurement showed the check was already conditional and the cache only chose candidates, the correct move is to concede quickly and say so, because an engineer who argues the same way regardless of the evidence stops being listened to.
- Report the outcome honestly, including the version that shipped and whether your predicted failure appeared. A strong answer names the metric that would have proved you wrong and whether anyone put it in place.
Follow-up
- The team keeps the primary check but wants the cache to prefilter which nodes are even considered. What can now go wrong that could not before?
- How would you bound overselling on one very hot item-node pair without adding latency to every other pair?
- What would you measure for a week to decide whether the cache is safe, and what result would change your mind?
Turn an implicit fail-open availability answer into a decision
When the inventory service is unreachable, the availability client returns the last value it cached, because a broad except block around the call does that by accident. Nobody chose it. During a 40-minute outage the storefront kept promising stock for items that had sold out, and 900 lines short-shipped. Describe a time you converted an implicit behaviour into an explicit decision: how you surfaced it, the two directions the error can go and what each costs, what you actually chose for the checkout path versus a browse page, and where the choice is now written down.
Approach
- Surface the behaviour as a fact before arguing about it: the except block is a policy, it was never chosen, and it currently applies identically to a browse page and to the promise made at checkout. Framing it as an unowned decision rather than as someone's bug is what gets it looked at.
- Price both error directions with the operations they trigger, since neither is free. Promising stock you do not have produces a short-ship, a customer contact, a re-source or refund and, on the floor, a picker sent to an empty location; refusing stock you do have loses the order outright. Both are real, the second is cheaper to reverse, and that asymmetry is the argument.
- Split the decision by path instead of choosing one policy for the system. A browse page can serve a stale value with a staleness label and be right most of the time; a checkout promise should degrade to a conservative answer, which is not zero but the last known position reduced by an in-flight allowance sized from the recent allocation rate for that key. Applying one policy to both paths is the actual defect.
- Bound the staleness, because a cached value with no age is the same bug wearing a different hat. Serve the cached number while it is under a stated age, then switch to the conservative answer, then refuse; the thresholds need owners and should appear on a dashboard as the share of reads answered from each tier.
- Write it down where the next person meets it: a short decision record giving the behaviour, the two costs, the chosen policy per path and the date, plus a test that asserts the checkout client cannot serve an unlabelled stale value. A decision that lives only in a thread gets reverted by the next broad except block.
- Report what the change actually cost. If the conservative answer suppressed some orders that would have been fillable, say how many, because a degradation policy that was never measured is indistinguishable from one that was never enforced.
Follow-up
- How do you size the in-flight allowance, and what happens to it during a promotion on that item?
- The outage is 4 hours rather than 40 minutes. Does your policy still hold, and what changes at which threshold?
- Someone adds a new consumer of the availability client next quarter. What stops them inheriting the wrong policy by default?
- 01
You have eight working days to get freight cost onto order margin. The correct model allocates each shipment_leg cost across the orders on that leg through a bridge, with a stated basis such as billable weight, and attaches accessorials to the stop that incurred them. The version that fits the window copies linehaul_cost_cents onto each line, split evenly. Describe a time you shipped known debt: exactly what you cut, the guard that made the shortcut visible rather than silent, who agreed to carry it, the date it was paid down, and what it cost while it stood.
- 02
The availability read sits inside checkout with a p99 budget in the low tens of milliseconds, and it is missing it. A senior engineer proposes serving available-to-promise from a two-second in-memory cache, falling back to a read replica, and leaving the allocation write untouched. You believe this is either harmless or an overselling bug depending on one detail nobody has stated. Describe a design you argued against: the distinction you drew, the evidence you brought, the alternative you offered, and what was actually decided. Be specific about the failure you predicted and whether it happened.
- 03
When the inventory service is unreachable, the availability client returns the last value it cached, because a broad except block around the call does that by accident. Nobody chose it. During a 40-minute outage the storefront kept promising stock for items that had sold out, and 900 lines short-shipped. Describe a time you converted an implicit behaviour into an explicit decision: how you surfaced it, the two directions the error can go and what each costs, what you actually chose for the checkout path versus a browse page, and where the choice is now written down.
Is this an official Fuse Energy interview guide?
No. It is PracHub's own research and practice material for the Software Engineer role at Fuse Energy. Rounds and questions reflect what candidates have reported, not a process Fuse Energy has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗What is the work-life balance like at Fuse Energy?
The company operates with a high-intensity work culture. Candidates are explicitly informed during the interview process that the expectation is to work roughly 60 to 80 hours per week, which often includes evenings and weekends. This role is best suited for individuals who are highly career-focused and thrive in an intense startup environment.
PracHub interview research ↗How difficult are the technical interviews?
The technical interviews are challenging but fair. They focus on practical engineering tasks—such as building a working application or designing a realistic system—rather than trick algorithmic puzzles or LeetCode brain teasers.
PracHub interview research ↗What are the founder rounds like?
The founder rounds include a "vibe check" with the CEO and a problem-solving session with the COO. These conversations focus on your motivation, alignment with the company's culture, and your ability to break down complex, ambiguous business problems using first-principles thinking.
PracHub interview research ↗Does Fuse Energy support remote work?
While some job postings mention remote options, the company has a strong preference for candidates who can work onsite at their core hubs, such as London, to foster high-velocity collaboration and alignment.
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.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
PracHub page · Accessed 2026-09-24 - 02PracHub Software Engineer practice ↗
Cross-company practice questions for this role.
PracHub page · Accessed 2026-09-24 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
PracHub page · Accessed 2026-09-24