Interview guides · Allen Integrated Solutions
Allen Integrated Solutions Data Scientist Interview Questions & Guide 2026
Practice explaining analysis before a Allen Integrated Solutions data scientist interview: the recommendation, the uncertainty, the follow-ups.
The 60-second brief
As a Data Scientist at Allen Integrated Solutions, you are stepping into a mission-critical role at the intersection of advanced analytics and national security. Based in Washington, DC, our teams tackle some of the most complex and sensitive data challenges in the industry. Whether you are joining as a Mid-Level Data Scientist, a Senior Data Scientist, or an Exploitation Specialist, your work directly impacts how we process, analyze, and derive actionable intelligence from massive, unstructured datasets.
SQL is seldom the hardest round and is often the one that eliminates people. The working bar is usually window functions, correct deduplication, and joins that do not silently fan out rows, rather than obscure syntax.
Focus areas
- Separate bookings, recognised revenue and collected cash
- Compute utilisation against a defended availability denominator
- Segment margin by pricing model before comparing
Overview
The impact of this position extends far beyond standard business metrics. You will build machine learning models and analytical pipelines that empower decision-makers to act swiftly in high-stakes environments. Our products rely on your ability to synthesize disparate data sources—ranging from text and imagery to complex signals—and transform them into reliable, deployable insights.
Expect a highly collaborative, rigorous, and secure working environment. You will partner with intelligence analysts, data engineers, and domain experts to solve unprecedented problems. This role requires not only deep technical expertise in statistical modeling and machine learning but also the strategic foresight to understand how your algorithms serve a broader, mission-driven operational goal.
The Allen Integrated Solutions interview process
Allen Integrated Solutions candidates report 3 rounds · ≈ 3-5 weeks. The stages below are what candidates describe, not a published process.
Recruiter Screen
A screening call is a matching exercise run by someone who will not evaluate your statistics. They are checking that the work described on your resume is work you personally did, and that its scope matches the level the role is written for. Logistics get settled in the same half hour so nobody spends an interviewer's afternoon on a mismatch. The answer that fails is the one narrated in the plural. If every sentence is 'we built' and 'the team decided', there is nothing specific to write down about you. Name the piece that was yours, the decision you made inside it, and what changed after.
What to demonstrate
- Whether the ownership implied by your resume survives one round of follow-up about who actually did which part
- Whether your described scope (data size, stakeholders, what shipped) matches the seniority the role is written at
- Whether timeline, location and compensation expectations make the rest of the loop worth scheduling
How to prepare
- Rewrite your top three resume bullets in the first person singular, each with the decision you made and what moved afterwards, then say them out loud once so the 'we' does not return under pressure
- Attach one number to each project: the baseline, the change, and the window it was measured over. Where impact was never measured, say that plainly rather than inventing a figure
- Settle your compensation range before the call and give it as a range with a reason behind it, such as current total comp or a competing timeline, instead of deflecting the question twice
Technical Screening
Much of what gets scored here happens out loud while you type. Nobody can see your reasoning inside a half-written query, so five silent minutes read as being stuck even when they are not. State the plan in plain language first: which tables, what grain you are aggregating to, and the one filter that defines the population. Then write it. The narration doubles as insurance, because a wrong plan gets caught early and cheaply while a wrong query gets caught at the end with no time left to redo it. A timed statistics section, where one exists, is a separate test with its own clock.
What to demonstrate
- Whether the query you write matches the plan you just described
- What you do with a hint, meaning whether the correction gets absorbed or the first approach gets defended
- Whether you can debug your own wrong output by reading the result set and naming which part of the query produced the anomaly
How to prepare
- Solve three problems while screen-sharing into a recording, then watch it back and mark every stretch longer than thirty seconds where you said nothing
- Practise compressing the plan into one sentence before typing, then check afterwards whether the finished query actually matched it
- Time yourself on statistics questions that carry a business reading, such as what a confidence interval does and does not claim, rather than re-reading notes without a clock
Panel Interview
A loop is not scored one interview at a time. The people you meet compare notes afterwards, usually in a meeting you are not in, and the outcome turns on what each of them can say about you when asked. That rewards something other than survival: every room needs one specific thing worth repeating, and none of them can contradict another. The common way to lose is to tell the same project four times with different numbers in it, or to be uniformly fine in a way that leaves nobody with anything to argue for.
What to demonstrate
- Whether your account of a project survives being told twice, with the same scale, the same metric definition and the same numbers each time
- Whether each interviewer leaves with one concrete claim they could make on your behalf later, rather than an absence of complaints
- Whether a question you already answered in an earlier room gets the same answer at the same depth, without visible impatience
How to prepare
- Write a one-page fact sheet for your two or three main projects that fixes the numbers you will quote: rows of data, the metric as a single sentence, the effect you measured and how long the work took. Say them aloud from the sheet until they come out identical every time
- For each kind of room you expect, decide the one sentence you want that interviewer repeating in a debrief, then check during the mock that you said it outright instead of implying it
- Rehearse answering the same project question twice in one sitting, the second time as though you had not just answered it, because the thing that needs fixing is the flatness that creeps into a repeated story
Where candidates lose points
Pooling margin, realisation or overrun across pricing models
Fixed-fee margin falls with hours worked; uncapped time-and-materials margin rises with hours worked; retainer margin depends on neither. A quarter in which the firm sells more fixed-fee work will show a margin change caused entirely by mix, not by delivery performance, and the aggregate can move in the opposite direction to every individual pricing model. Always stratify by fct_engagement.pricing_model before comparing periods, and report the mix shift alongside the within-stratum change.
Treating accounts as independent observations
Revenue is concentrated: a small number of client_ids typically carries a large share of fees, and engagements within one account share a partner, a rate card and a delivery team. Ordinary standard errors computed over engagements therefore understate uncertainty badly. Cluster at client_id, and with fewer than roughly 40 clusters use a wild cluster bootstrap or a CR2 correction, because cluster-robust standard errors are downward-biased in that regime and will manufacture significance that a replication will not reproduce.
SQL that silently fans out on a one-to-many join
State the grain of each table and the grain you want in the result before writing the join. Pre-aggregate the many side to the join key, or use EXISTS or a window function, and verify with a row count against COUNT(DISTINCT id) rather than trusting that the numbers look plausible.
Reporting a mean for a heavy-tailed metric without saying what it hides
For spend, session length or items per order, a small fraction of units carries most of the total, so the mean has a wide standard error and one account can move it. Fix the handling before you see the result: cap or winsorise at a pre-declared percentile, and report the median or the share above a threshold next to the mean. Capping changes the estimand, so say which question the capped number answers, and check how much of any difference comes from the top 0.1 percent of units.
Questions & practice
How do you handle multicollinearity in a multiple regression model?
Medium · machine learning and modelling
Approach
- Pick an evaluation metric that matches the cost of each error type, not a default.
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- Check what information would not exist at prediction time, and exclude it.
Follow-up
- How would you choose the decision threshold, and who owns that choice?
- What would you monitor after launch to know the model is still valid?
Here, we assess your theoretical foundation and your ability to diagnose model behavior.
Medium · machine learning and modelling
Approach
- Say how the offline result would be validated online before it is trusted.
- Check what information would not exist at prediction time, and exclude it.
- Pick an evaluation metric that matches the cost of each error type, not a default.
Follow-up
- How would you choose the decision threshold, and who owns that choice?
- Where could label leakage enter this setup?
Implement billable utilisation against a defended availability denominator
Medium · metric implementation · denominators · proration
Implement billable utilisation for one calendar month at consultant grain, then roll it up to practice_area. Inputs: time_entries (consultant_id, work_date, hours, is_billable, charge_code, status), consultants (consultant_id, practice_area, fte_fraction, home_region, is_billable_role, hire_date, termination_date) and holidays (region, holiday_date). Numerator is approved hours with is_billable true. Denominator is scheduled workdays in the month, clipped to [hire_date, termination_date] and net of that region's holidays, times 8 times fte_fraction, minus approved leave hours. Roll up as sum(numerator) / sum(denominator).
Approach
- Build the workday set per region first: business days in the month minus that region's holiday_dates. State the Monday-to-Friday assumption out loud, because a region with a different working week makes np.busday_count wrong rather than approximate.
- Prorate by clipping each consultant's interval to [max(month_start, hire_date), min(month_end, termination_date or month_end)] and counting workdays inside the clipped interval, so a mid-month start produces a smaller denominator instead of a fake dip in the ratio.
- Subtract approved leave hours (charge_code in leave_paid, leave_unpaid) only for leave falling on days already counted as workdays; leave logged on a public holiday would otherwise be subtracted twice and can push a denominator negative.
- Filter to is_billable_role, then drop consultant-months whose denominator is zero or negative (full-month leave, a hire on the last day) rather than emitting inf or NaN, and return the dropped count as part of the result.
- Roll up by summing numerators and denominators separately. Averaging per-person ratios gives a 0.2 FTE consultant the same weight as a full-time one and produces a practice number that no individual reconciles to.
Worked solution (35 min)
- Per region, workdays = np.busday_count(month_start, month_end + 1 day, holidays=region_holidays); per consultant, recompute on the clipped [start, end] interval so proration and holidays compose.
- leave = time_entries[status=='approved' & charge_code.isin(['leave_paid','leave_unpaid']) & work_date.isin(region workdays)].groupby('consultant_id').hours.sum().
- denominator = workdays_clipped * 8 * fte_fraction - leave, reindexed to the billable-role consultant list and filled with 0 leave where absent.
- numerator = time_entries[status=='approved' & is_billable].groupby('consultant_id').hours.sum(), reindexed and zero-filled.
- Drop rows with denominator <= 0 (counting them), compute utilisation_pct = 100 * numerator / denominator, then groupby practice_area and divide summed numerator by summed denominator.
Expected result: A consultant-month frame carrying numerator, denominator and utilisation_pct, a practice-area frame whose ratio equals sum(numerator)/sum(denominator), and an explicit count of consultant-months excluded for a non-positive denominator.
Verify it yourself
- A full-time consultant with no leave in a 21-workday month has denominator exactly 168.0.
- Every consultant's denominator is at most workdays * 8 * fte_fraction, with equality only when leave is zero.
- The practice-area ratio equals the denominator-weighted mean of the per-consultant ratios, and sits between their min and max.
- Summed numerators across practice areas equal total approved billable hours for in-scope consultants.
Follow-up
- Utilisation rose two points this month while realisation fell. Reconcile those two movements with one mechanism.
- A regional lead says their team looks four points below another region. What do you check before you answer, and in what order?
Given a schema of user logins, write a SQL query to identify users who have logged in for five consecutive days.
Medium · sql and data manipulation
Approach
- Check whether any join is one-to-many before aggregating, or the sums inflate.
- Compute rates by summing numerator and denominator separately, never by averaging rates.
- Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
Follow-up
- How does the query change if the join becomes one-to-many?
- How would you verify this result without re-running the same query?
Write a Python function to calculate the moving average of an array without using external libraries.
Medium · sql and data manipulation
Approach
- Say which table is the grain you start from, and join outward from it.
- Compute rates by summing numerator and denominator separately, never by averaging rates.
- Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
Follow-up
- How would you verify this result without re-running the same query?
- How does the query change if the join becomes one-to-many?
Dense consultant-week series with a trailing four-week average
Medium · window functions · calendar spine · running aggregates
fct_time_entry holds consultant_id, engagement_id, charge_code, work_date, hours, is_billable and status. dim_consultant holds consultant_id, is_billable_role, hire_date, termination_date and is_current. Produce one row per billable-role consultant per ISO week over the last 26 weeks with approved billable hours and the trailing four-week average including the current week. Weeks with no time entries must appear as 0, not disappear. No consultant may appear before hire_date or after termination_date. State where you put the right-hand edge of the window and why.
Approach
- Build the week spine with generate_series over date_trunc('week', ...), which is Monday-aligned in Postgres, and CROSS JOIN it to the eligible consultant set, bounding each consultant by hire_date and termination_date. The spine is what converts an absent week into a zero week; no amount of COALESCE on a query driven by fct_time_entry can recover a row that was never there.
- Aggregate time entries to (consultant_id, week_start) in a CTE first, then LEFT JOIN that onto the spine and COALESCE(hours, 0). Aggregating before the join keeps it one-to-one and removes any chance of fan-out.
- Average with AVG(billable_hours) OVER (PARTITION BY consultant_id ORDER BY week_start ROWS BETWEEN 3 PRECEDING AND CURRENT ROW). Use ROWS rather than RANGE: on a dense spine they agree, but ROWS states the intent in row terms and does not change meaning if the spine ever develops a hole.
- Decide what the first three weeks of each consultant's series mean. That window averages over fewer than four rows, so either label them as partial with a COUNT(*) OVER the same frame, or suppress them. Pick one and say so.
- Hold the right edge of the window back past the measured timesheet backfill tail. Entries are created days to weeks after work_date, so the most recent weeks are systematically incomplete and the series will show a decline that reverses on the next refresh. Measure the tail rather than guessing a round number.
Worked solution (30 min)
- Generate the 26 week_start values and confirm the count and the boundary dates before joining anything.
- CROSS JOIN to billable-role consultants and apply the hire_date and termination_date bounds, then count rows per consultant.
- Aggregate approved billable entries to consultant-week, LEFT JOIN onto the spine, COALESCE to 0.
- Add the windowed average with an explicit ROWS frame, plus a COUNT over the same frame so partial windows are visible.
- Hand-verify one consultant: print their 26 weeks and check that week 5's average equals the mean of weeks 2 through 5.
Expected result: 26 rows per eligible consultant, fewer only where hire_date or termination_date truncates the series. Zero-hour weeks are present with 0.00 hours. The trailing average on each row equals the arithmetic mean of that week and the three preceding weeks in the same consultant's series.
Verify it yourself
- SUM(billable_hours) over the dense series equals SUM(hours) over approved billable entries in the same window, proving the LEFT JOIN added no rows and lost none.
- Row count per consultant equals 26 minus any weeks outside their hire and termination bounds.
- The hand-checked consultant's week-5 average matches the mean computed by hand from weeks 2 to 5.
- No week_start in the output falls inside the held-back backfill tail.
Follow-up
- Extend to a 13-week average. Does your choice between ROWS and RANGE change, and why?
- Add the availability denominator so this becomes utilisation. What has to be subtracted from calendar hours, and what has to be prorated?
- Reproduce this series as it would have looked 30 days ago. Which column do you filter on, and why do the two versions differ?
Explain how you would optimize a Python script that is running out of memory while processing a large dataset.
Medium · product sense and metrics
Approach
- Fix the population and the time window before naming any metric.
- State what result would change your recommendation, so the answer is falsifiable.
- Name one primary metric, then the guardrail that stops it being gamed.
Follow-up
- Which segment would you cut first, and what would that rule out?
- What would you do if the primary metric and the guardrail moved in opposite directions?
How would you design an experiment to test whether a new feature improves the accuracy of our primary exploitation tool?
Medium · a/b testing and experimentation
Approach
- State the primary metric and the minimum effect worth shipping, then size the test.
- Decide the analysis before seeing data, including how long it runs and when you look.
- Say whether units interfere with each other, and switch design if they do.
Follow-up
- How would you handle interference between treated and control units?
- What would you conclude if the result is positive but the test is underpowered?
These questions evaluate your ability to design end-to-end analytical solutions for real-world problems.
Medium
Approach
- Clarify what is being asked and what a complete answer would contain.
- State your assumptions explicitly before working the problem.
- Work from the decision backwards to the evidence you would need.
Follow-up
- How would you know your answer was wrong?
- What assumption would you test first?
Define competitive win rate for a quarterly pipeline review
Easy · win rate · censoring · denominators
Pipeline reporting currently shows win rate as won proposals divided by all proposals created. Using fct_proposal (proposal_id, expected_value_usd, stage, loss_reason, is_competitive, created_at, submitted_at, decided_at), write a definition you would defend to a finance lead: numerator, denominator, window and every exclusion. Decide whether to weight by count or by expected_value_usd, and justify the choice. State what happens to proposals still in 'qualifying', 'scoping' or 'submitted' at the snapshot date, and why dropping them is not a neutral act.
Approach
- Cohort on decided_at, not created_at. A created_at cohort mixes decided and undecided proposals, so the rate for a recent quarter is computed over whichever deals resolved fastest and drifts upward on every refresh.
- Set the denominator to stage IN ('won','lost'). Excluding 'withdrawn' and 'no_decision' is defensible only if you report their count and value alongside, because they are not missing at random: they skew toward deals that were heading for a loss.
- Filter is_competitive = TRUE. Sole-sourced follow-on work closes at near certainty and mechanically inflates the rate, so it belongs on its own line rather than inside the headline number.
- Report count-weighted and value-weighted side by side. They diverge when large proposals lose more often than small ones, which is the diagnostically useful case; the value-weighted version is the one that ties to revenue.
- Treat open proposals as right-censored rather than absent. Either restrict to cohorts old enough that most proposals have decided, picking that horizon off a Kaplan-Meier cycle-time curve, or publish the rate with the undecided count and value attached to it.
Worked solution (25 min)
- Compute the naive rate (won / all created) and the proposed rate (won / won+lost, is_competitive = TRUE, cohorted on decided_at) for the same four quarters.
- For each quarter, count and sum the value of proposals in 'withdrawn' and 'no_decision', and of proposals still open at the snapshot.
- Compute the value-weighted version and compare it with the count-weighted one.
- Re-run the most recent quarter as it would have looked 30 days ago and record how much each definition moved.
Expected result: Two numbers per trailing quarter, count-weighted and value-weighted competitive win rate, each with the denominator predicate written out in full, cohorted on decided_at, plus a reported count and value for withdrawn, no_decision and still-open proposals. The horizon is chosen so the undecided share is small rather than set to a round number of days.
Verify it yourself
- The value-weighted and count-weighted rates differ. If they are identical, expected_value_usd is either constant or lost in a join.
- Re-running a given quarter two weeks later moves the decided_at-cohorted number by much less than it moves the created_at version.
- Withdrawn and no_decision appear as reported counts, not as a silent exclusion.
Follow-up
- Win rate rose four points while proposal volume fell by a third. Which do you report first, and what single query separates a genuine quality shift from a volume shift?
- How would you detect partners reclassifying likely losses as 'withdrawn' to protect the rate?
Days sales outstanding improved while collections got worse
Medium · right censoring · survival analysis · cash
A cash dashboard reports mean days-to-pay as AVG(paid_at - issued_at) over fct_invoice_line where status = 'paid'. It improved from 47 to 39 days last quarter. The finance lead insists collections are worse, and invoice volume rose about 30% after a large batch issued early in the quarter. Using invoice_line_id, engagement_id, issued_at, due_date, paid_at, status and amount_usd, explain the contradiction and deliver the estimate you would report instead, with its assumptions.
Approach
- Name the bias precisely: at any snapshot, the set of paid invoices over-represents fast payers, because slow ones have not finished yet. Unpaid, partially paid and disputed lines are right-censored observations, not absent ones, and averaging over completions alone is biased downward.
- Explain why the bias grew: a large young cohort adds many invoices whose slow half cannot yet appear in the paid set, so a volume increase alone pushes the naive mean down even with unchanged payment behaviour.
- Build the censored dataset: event time = paid_at - issued_at for paid lines; censoring time = snapshot_date - issued_at for status IN ('issued','partially_paid','disputed'). Confirm no placeholder dates were substituted for NULL paid_at.
- Estimate with Kaplan-Meier by issue-month cohort and report both the median and the restricted mean to a fixed horizon such as 90 days, so cohorts of different maturity are compared over the same span. State the independent-censoring assumption: censoring here is administrative, driven by issue date rather than by payment behaviour, which is what makes it defensible.
- Cross-check with a metric that needs no model: share of each cohort's invoiced amount collected by day 30, 60 and 90. If the recent cohort's curve sits below prior cohorts at the same age, collections really did deteriorate.
- Report amount-weighted as well as count-weighted, since one large disputed invoice moves cash without moving the count.
Follow-up
- Disputed invoices may never pay at all. Does that break the censoring assumption, and how would you handle it?
- How would you turn this into a weekly operational report that cannot be gamed by issuing more invoices?
- Proposal cycle time has the same structure. What is the equivalent fix there?
Suggested practice checklist
Four days spend equal time on query work, statistics, modelling and product judgement at deliberately shallow depth, which produces a scored map of where you actually stand. The last three days spend everything on the two areas the role weights most, and close by re-running day one to measure movement.
Day 1 — Breadth pass: query fluency
- Solve six prompts spanning aggregation, joins, window functions and date arithmetic in 60 minutes total, stopping at 10 minutes each whether or not it works, and mark every prompt as solved, solved slowly, or stuck.
- For each unsolved prompt write the single blocking sentence (I lost the grain, I did not know the frame clause, I could not express the date boundary) instead of reading the solution.
- Translate one pandas transformation you know well into SQL and one SQL query into pandas, checking that both return the same row count and the same totals.
Deliverable: A scored six-row table, one line per prompt, saved for the day-seven re-run.
Day 2 — Breadth pass: statistics and inference
- Answer ten short questions in writing with nothing open: what a p-value is conditional on, what a 95 percent interval covers across repeated samples, when a paired test is the right one, what the bootstrap estimates, why multiple comparisons inflate false positives, how controlling the family-wise error rate differs from controlling the false discovery rate, what power depends on, what a missed real effect costs a product, the three situations where the central limit theorem does not rescue you (small n, very heavy tails, dependent observations), and what a standard error is the standard deviation of.
- Grade yourself against a reference and count only the answers that were exactly right, not the ones that were nearly right.
- Rewrite the two weakest answers the following morning from memory in full sentences.
Deliverable: Ten graded answers with an honest count of exact hits.
Day 3 — Breadth pass: modelling
- Take one tabular dataset end to end in 90 minutes: a leakage-safe split, a baseline that is not a model (majority class or historical mean), one regularized linear model, one gradient-boosted tree, and a single evaluation metric chosen before you look at any result.
- Write why that metric fits the cost structure: precision at a fixed recall for alerting, calibration for anything feeding a price or a threshold, ranking metrics for retrieval, and note that area under the ROC curve is insensitive to class balance in a way that can flatter a rare-positive problem.
- Name the leak you were most likely to introduce (an encoding fit on all rows before splitting, or a feature computed after the label's timestamp) and write the check that would have caught it.
Deliverable: A notebook whose first cell states the metric and the baseline, plus two lines on what beat what and by how much.
Day 4 — Breadth pass: product judgement
- Answer three case prompts aloud at 15 minutes each, timing how long passes before you state a success metric.
- For one case write the first segmentation you would run and the row counts you expect per segment, so that a tiny segment cannot quietly drive the conclusion.
- Take a metric definition you did not write, from a public dashboard, a textbook, or documentation you already have open, and list every place two analysts implementing it would diverge: which rows the denominator admits, whether the unit is an account or a person, what the time window is anchored to, and what happens to data that arrives late. Then write the one question that would close the largest of those gaps.
Deliverable: Three recorded case answers plus an ambiguity list for a metric someone else defined, ending in the single question you would ask about it.
Day 5 — Depth, first area
- Rank the four areas by how many bullet points in the role description each one covers, pick the top one, and spend the entire day inside it.
- Work the six hardest problems you can find in that area and for each write the generalizable move you should have reached for first, rather than the answer.
- Re-solve the two you failed the same evening with notes closed.
Deliverable: Six generalizable moves written as instructions to yourself, not as solutions.
Day 6 — Depth, second area, and the seam between them
- Repeat the depth protocol on the second-ranked area with the same six-problem structure.
- Construct one problem that requires both areas at once, for example a metric redefinition whose effect you must validate with a test whose readout you then have to query.
- Solve your own combined problem end to end and note where the handoff between the two areas cost you time.
Deliverable: One combined problem, solved end to end, with the handoff failure written down.
Day 7 — Integration and re-measurement
- Re-run the six prompts from day one under the same clock and compare both correctness and time.
- Run a 60-minute mixed mock that moves between areas without warning, since switching cost is what breadth passes do not train.
- Write the two areas you would still fail on, and the sentence you will use in the interview when you hit one of them.
Deliverable: A before-and-after score table plus a written plan for the two remaining gaps.
Where your data came from
Data people depend on systems owned by other teams, and much of the job is negotiating for instrumentation, access, or a fix to a broken pipeline. Prepare an example of getting something changed upstream that you did not control. Describe what you asked for, what you traded, and how you worked while you waited.
Tell me about a time you had to explain a highly technical concept to a non-technical stakeholder.
Medium · behavioural and stakeholder questions
Approach
- Name the disagreement or constraint, and how you resolved it with evidence.
- State the situation in two sentences and spend the rest on your reasoning.
- Quantify the outcome, including what you would not claim credit for.
Follow-up
- How did you know the outcome was caused by your change?
- What would you do differently if you ran that project again?
Describe a situation where you had to work with messy, undocumented data. How did you proceed?
Medium · behavioural and stakeholder questions
Approach
- Close with what you would do differently, concretely.
- Quantify the outcome, including what you would not claim credit for.
- State the situation in two sentences and spend the rest on your reasoning.
Follow-up
- How did you know the outcome was caused by your change?
- What did you decide not to do, and why?
Disagreeing with a proposed utilisation target using realisation evidence
Medium · realisation · guardrail metrics · observational evidence
A delivery lead proposes raising the billable utilisation target for analyst through senior_consultant from 72 to 85 percent. You have fct_time_entry, including is_billable, bill_rate_usd and written_off_hours, and fct_invoice_line. You believe the target will raise reported utilisation and lower fees. Prepare the disagreement: the evidence you pull, the mechanism you name, the metric pair you propose instead, and the condition under which you would concede that the target is correct.
Approach
- Name the probe: whether you disagree with a mechanism and a measurement, or with an opinion about a metric being bad.
- State the substitution precisely. Utilisation counts approved hours with is_billable = TRUE. An hour that is charged to the client and later written off stays in that numerator, so utilisation is unaffected while realisation, fees divided by hours times bill_rate_usd, falls and margin falls with it. That is the exact channel by which a higher target can raise the reported number and lower revenue.
- Pull the evidence at consultant-month grain: plot realisation and the write-off share, written_off_hours over billable hours, against utilisation decile. If the current top decile already shows lower realisation, the proposed target moves a large share of the staff into that regime.
- Stratify before concluding. Fixed_fee teams can show high utilisation and high realisation for reasons that have nothing to do with the proposal, so run the comparison within pricing_model and report the mix.
- Propose the pair rather than the veto: utilisation published with realisation and write-off rate as standing guardrails, with the threshold at which the combination is net positive stated in advance. Then name your concession condition: if the top utilisation decile shows no realisation penalty and bench hours are the binding constraint, the target is right and you will say so.
Follow-up
- Utilisation and realisation are computed from overlapping hours. Does that make the relationship you found mechanical rather than behavioural?
- How many consultant-months would you need to detect a three-point realisation move, and does the firm have them?