Interview prep · 3 projects · 98 flashcards
Know your projects inside out
Use your résumé as the interview agenda. Follow each claim into the code, rehearse the story out loud, and practice the follow-up that tests whether you understand it.
Quick start
Your résumé, line by line
If the interview is tomorrow
- 20 minutes — Read the seven résumé claims below. Give each project a 45-second pitch aloud, then say which piece you personally implemented, tested, or debugged.
- 25 minutes — Draw one borrower prediction, one weather prediction, and one finding creation from input to output. Explain where each can fail.
- 20 minutes — Practice the three hardest follow-ups with no notes. Explain RiskSight leakage, Pyrograph’s temperature-rule comparison, and Fieldnotes’ client-supplied identity.
- 15 minutes — Do the mock interview and open only the answers you missed. Rehearse one real debugging or team story with a concrete code change or test.
The sample pitches describe repository behavior. Use “I” for work you can describe from your own experience. For team or AI-assisted work, say what the project does, identify your part, and explain how you checked it. Bring one commit, function, experiment, or issue you can discuss for every project.
The seven lines an interviewer can probe
| Résumé claim, shortened | A source to open | A likely follow-up |
|---|---|---|
| RiskSight • NumPy logistic regression, loss, gradient descent, L1/L2, class weights | logistic_regression.py |
What is the gradient and where do positive examples get extra weight? |
| RiskSight • scikit-learn comparison and decision thresholds | evaluate.py |
Did the comparison isolate your implementation, or did it change class weighting too? Which set should pick the threshold? |
| RiskSight • React calls FastAPI using saved artifacts | backend/main.py |
Which preprocessing statistics have to travel with a saved model? |
| Pyrograph • weather features, chronological training/selection/test | heatwave_pipeline.py |
What weather would actually be available three days before the target day? |
| Pyrograph • single/batch routes, metadata, readiness and baselines | backend/main.py · Fixed-lead pilot |
What resets the persistence rule, and what did the forecast baseline beat? |
| Fieldnotes • React and Express on SQLite | backend/server.js |
Follow a new finding from the form to disk and back. |
| Fieldnotes • findings, role records, environment-based API connection | frontend/src/App.jsx · README |
How would a wrong frontend API URL show up? What proves the user’s identity? |
Three 30-second answers
RiskSight
RiskSight estimates the risk of serious delinquency using borrower records. The core is a NumPy implementation of logistic regression that learns weights from binary cross-entropy, including support for class weighting and regularization. FastAPI and React show the prediction and evaluation. The main evaluation issue I’d discuss is the repository’s preprocessing order. It estimates imputation and scaling statistics before the split, so I’d move those fits onto the training partition.
Pyrograph
Pyrograph is a Jaipur heat-hazard classification prototype. It builds weather and time features, selects an XGBoost classifier on a separate chronological window, and serves it through FastAPI with versioned artifacts. The retrospective evaluation used observed weather. When the project separately tried real three-day-ahead forecast inputs, a simple temperature rule had fewer false alarms and a higher critical success index.
Fieldnotes
Fieldnotes is a small research log for the heatwave project team. React sends requests to an Express API that validates findings and stores them in SQLite. The UI can filter findings by project phase and show role records. The shared PIN is a lightweight gate for a small team. For per-user permissions, I’d have the server derive identity from a verified session.
Three worked follow-ups
RiskSight • Does higher recall prove the custom optimizer is better? The repository compares a balanced scratch model with an unweighted scikit-learn baseline at the same cutoff. The weighted model is encouraged to score positives higher, and both weighting and implementation differ. An apples-to-apples experiment would use identical training-fitted transformations, equivalent weights and regularization, the same evaluation rows, and thresholds chosen on validation. On a loan decision, class weights change training and the threshold changes how a trained score is used. Evaluation script
Pyrograph • Where do the pilot CSI numbers come from? At three days, both systems found two of three positive days, so both have 2 TP and 1 FN. The classifier made 7 false alarms and the temperature rule made 2. The resulting CSI values are 2 ÷ (2 + 7 + 1) = 0.20 and 2 ÷ (2 + 2 + 1) = 0.40. This was 91 days with three positive labels. State that sample size before drawing conclusions. Fixed-lead pilot
Fieldnotes • Why can’t CORS enforce admin permissions? CORS constrains what a browser lets a page read across origins. A direct client can call the API without an Origin header. The role checks use a caller-supplied x-current-user name, so a caller with the shared PIN can claim a different identity. Derive the actor from a verified session on the server, then check the actor’s permissions against the requested record. Express middleware and routes
Your personal contribution worksheet
For each project, fill this out aloud. Keep a GitHub tab open to verify details after your first attempt.
- I personally changed ___ in ___ because ___.
- I checked it by , using input ___ and expecting .
- A teammate, library, or AI tool contributed . I reviewed or tested .
- The hardest bug or trade-off was . The evidence that changed my mind was .
- If I had one more week, my first change would be , because it would improve .
Score each answer from 0 to 2 on accuracy, concrete detail, ownership, and handling a follow-up. A vague claim earns zero on detail. An answer with a specific function, example, or experiment earns two when you can explain how it works.
Study method
How to study with this guide
Purpose: know every project on your résumé well enough to explain it simply, defend its choices, trace a request through its code, and openly name its limitations.
Open a card after saying the answer aloud. Use the recall button to mark cards you can explain from memory. Your browser can remember these marks on this device.
How to use this workbook
For each lesson, do this sequence:
- Read the explanation once.
- Hide the answer and say it aloud from memory.
- Draw the flow on paper.
- Answer the cards at the end of the lesson.
- Repeat the cards after one day, three days, seven days, and fourteen days.
Recall levels
| Level | What you can do |
|---|---|
| 0 — recognise | You understand it while reading. |
| 1 — recall | You can explain it without looking. |
| 2 — connect | You can explain why it connects to another component. |
| 3 — defend | You can handle a skeptical follow-up or name a limitation. |
| 4 — build | You could modify or recreate a smaller version. |
Aim for level 3 on every concept before an interview. Level 4 is a bonus.
Your honest project boundary
You are not expected to know every library internals or claim industrial-scale production systems. You are expected to know:
- what you built;
- why you chose it;
- what data/request moves through it;
- what can fail;
- and the first improvement you would make.
RiskSight
RiskSight: credit-risk classification from scratch
Repository: rexyrocks/credit-risk-from-scratch
I.1 The story before the code
One-sentence story
RiskSight predicts whether a borrower is likely to experience serious delinquency, while showing how a logistic-regression classifier can be derived and implemented with NumPy rather than treated as a black box.
Interviewer’s mental model
An interviewer should leave with this picture:
Kaggle borrower rows
↓
clean missing values + numerical features
↓
custom NumPy logistic regression
↓
class weighting + threshold choice
↓
metrics / baseline comparison
↓
FastAPI prediction service
↓
React form and results interface
Speak it in 15 seconds
I built a credit-default classifier from first principles in NumPy, including the weighted loss, gradient descent, and regularisation, then compared it with scikit-learn and exposed both through a FastAPI and React demo.
Speak it in 60 seconds
RiskSight uses the Give Me Some Credit dataset, where the target is whether a borrower has a serious delinquency within two years. The interesting part was not just training a library model: I wrote the logistic-regression mechanics in NumPy—the sigmoid, weighted binary cross-entropy, gradients, gradient descent, L1/L2 regularisation, and thresholded predictions. Since defaults are uncommon, I used balanced class weights and focused on precision, recall, F1, and the confusion matrix rather than accuracy alone. I then compared the custom model to a scikit-learn baseline. For usability, the backend trains or loads cached artefacts and FastAPI exposes prediction and metrics endpoints for a React frontend. The main limitation I would fix first is that scaling occurs before the split in the original preprocessing helper, which leaks test-distribution information; the transformer should instead be fit only on the training partition.
I.2 Dataset and target
The repository uses Kaggle’s Give Me Some Credit data. Its target, SeriousDlqin2yrs, indicates whether a borrower had 90+ days of delinquency within two years. The repository describes roughly 150,000 anonymised records and ten input features, including revolving utilisation, age, debt ratio, monthly income, and late-payment counts.
The central data fact is imbalance: the README reports roughly 6.7% positive/default cases. A model can be highly accurate by predicting every borrower as non-default. That model would be useless for finding defaults.
Recall drill: five sentences, no notes
Say these answers aloud:
- What is the target?
- Why is accuracy misleading here?
- What does a positive label mean operationally?
- Name three features.
- What cost might a false negative create for a lender?
Flashcards — data
R-01What is the RiskSight target?
SeriousDlqin2yrs: whether the borrower experienced serious, 90+ day delinquency within two years.
R-02What does class imbalance mean in this project?
Defaults are a small minority of rows, so raw accuracy can hide failure to identify default cases.
R-03Give a harmful example of high accuracy.
Predict every borrower as non-default; because defaults are rare, accuracy can still look high while recall for defaults is zero.
R-04In RiskSight, what is a false negative?
A real defaulter predicted as non-default—the lender may grant a risky loan.
R-05In RiskSight, what is a false positive?
A non-defaulter predicted as default—the lender may wrongly decline or penalise a good borrower.
I.3 Preprocessing, step by step
The core helper is preprocessing.py.
load_data(path)reads the CSV through pandas.cleandata(df)dropsUnnamed: 0, a CSV index-like column that is not a predictive feature.- Missing
MonthlyIncomeis filled with the median. - Missing
NumberOfDependentsis filled with the mode. scalefeature(X)calculates a mean and standard deviation per feature and applies standardisation:(X - mean) / std.train_test_splitpermutes row indices with fixed seed 42, then uses 20% for testing.
Why median for income?
Income is commonly skewed: a small number of very large values can pull the mean upward. The median is more resistant to outliers. This is a sensible baseline, but in production you would inspect the missingness itself and perhaps add an income_missing indicator, because missingness can carry information.
Why mode for dependents?
Dependents is count-like and likely has a common most frequent value. Filling with the mode is a simple way to maintain a valid categorical/count value. It is still an assumption, so document it.
Why scaling?
Gradient descent learns weights more reliably when features occupy roughly comparable numerical ranges. Without scaling, a large-range feature can dominate the gradient simply because of its units, not because it is more meaningful.
Important flaw you must own
The current pipeline imputes missing values and standardises X before creating train/test sets. The income median, dependents mode, means, and standard deviations include the test rows. The test distribution therefore influences the training transformation. Repair the pipeline in this order.
split raw rows first
fit imputer and scaler only on training X
transform training X with training statistics
transform test X with the same training statistics
save those statistics for incoming API requests
Do not be embarrassed by this answer. Detecting and repairing leakage is exactly the kind of judgment an ML interviewer wants to hear.
Whiteboard exercise R-A
On paper, write pseudo-code for a leakage-free preprocessing flow. Include fit and transform separately. Then answer: “Why must the deployed API use the training mean and standard deviation?”
Flashcards — preprocessing
R-06Which missing-value strategy is used for MonthlyIncome?
Median imputation.
R-07Which missing-value strategy is used for NumberOfDependents?
Mode imputation.
R-08State the standardisation formula.
(x - mean) / standard deviation for each feature.
R-09Why scale data for gradient descent?
Comparable feature scales make optimisation more stable and prevent magnitude alone from dominating updates.
R-10What is data leakage in the current RiskSight preprocessing?
Income median, dependents mode, and scaling statistics are learned from all rows before splitting. The test distribution influences the training transformation.
R-11What is the correct order for split and scaling?
Split first; fit the scaler on training data only; apply it to validation/test/inference data.
R-12Why use a fixed seed?
Reproducibility: the same code can produce the same shuffled split for comparison and debugging.
I.4 Logistic regression without library shortcuts
The custom class is named logisitic_regressionScratch in logistic_regression.py. Notice the spelling typo; do not hide it if someone points it out. Say it is preserved in imports for compatibility and you would rename it with tests/refactoring in a cleanup pass.
The model
For a row of features x, the model computes:
z = x · w + b
p = sigmoid(z) = 1 / (1 + e^-z)
wis a vector of learned feature weights.bis the intercept/bias.pis a score between zero and one.
The prediction method makes a class label with:
prediction = 1 when p >= threshold; otherwise 0
Binary cross-entropy
The code calculates a weighted binary cross-entropy loss. Conceptually, the loss rewards a high predicted probability for the true label and penalises confidence in the wrong label.
loss = -[y log(p) + (1-y) log(1-p)]
The negative sign ensures a good prediction yields a small loss rather than a large negative number.
Gradient
For logistic regression, the core residual is p - y. The code multiplies it by sample weight, then obtains:
dw = (1/m) Xᵀ (weighted residual)
db = average(weighted residual)
Then it updates:
w = w - learning_rate × dw
b = b - learning_rate × db
Mini-exercise R-B: trace one update
Assume one feature, one row: x = 2, y = 1, current w = 0, b = 0, learning rate 0.1, and sample weight 1.
- Compute
z. - Compute sigmoid(
z). - Compute residual
p - y. - Compute
dwanddb. - Compute the updated
wandb.
Check: z=0, p=0.5, residual=-0.5, dw=-1, db=-0.5, so updated w=0.1, b=0.05.
Flashcards — model mechanics
R-13What is the purpose of sigmoid?
It maps an unbounded linear score to a number between zero and one.
R-14What are w and b?
w is the learned weight vector; b is the intercept/bias.
R-15What is the key logistic-regression residual?
Predicted probability minus true label: p - y.
R-16What does a smaller cross-entropy loss mean?
Predicted probabilities better agree with the true labels, with strong punishment for confident mistakes.
R-17What does the learning rate control?
The step size of each gradient-descent update; too large can diverge, too small can learn very slowly.
R-18What does predict_proba return?
The sigmoid score for each row before thresholding.
R-19What does predict add on top of predict_proba?
A configurable decision threshold that turns scores into class labels.
I.5 Class weights and regularisation
Balanced class weights
In fit, when class_weight='balanced', the code calculates:
w_positive = n_samples / (2 × number of positives)
w_negative = n_samples / (2 × number of negatives)
Because positives are less frequent, each positive usually receives a larger weight. The loss and gradient give those mistakes greater importance.
This is not magic. It intentionally changes the classifier’s trade-off. Recall may rise, but precision can fall because more cases get marked risky.
L1 versus L2
| Type | Penalty | Gradient contribution | Practical intuition |
|---|---|---|---|
| L1 | sum of absolute weights | sign(w) |
Can make some weights exactly zero; feature selection-like behaviour. |
| L2 | sum of squared weights | w |
Smoothly discourages large coefficients; stabilises correlated features. |
The implementation adds the regularisation term to dw, not db; it leaves the bias unregularised.
Mini-exercise R-C: choose a tool
For each case, choose a likely first response and explain why:
- Defaults are rare and recall is near zero.
- Coefficients are very large and unstable across samples.
- You want a sparse, easier-to-interpret linear model.
- False negatives cost much more than false positives.
Suggested answers: class weighting/threshold adjustment; L2; L1; a cost-aware threshold plus possibly class weighting.
Flashcards — imbalance and regularisation
R-20Why does the positive class get a larger balanced weight?
It occurs less often, so weighting makes positive mistakes contribute more to the loss.
R-21What trade-off can class weighting create?
Higher recall for defaults may bring more false positives and lower precision.
R-22What is L1’s gradient term?
The sign of each weight, scaled by the regularisation strength.
R-23What is L2’s gradient term?
The weight itself, scaled by the regularisation strength.
R-24Why is the bias normally not regularised?
It shifts the baseline decision level rather than expressing a feature’s complexity; penalising it is usually unnecessary.
I.6 Evaluation and threshold choice
evaluate.py manually calculates confusion-matrix components:
Actual positive Actual negative
Predicted positive TP FP
Predicted negative FN TN
Then it derives:
precision = TP / (TP + FP)
recall = TP / (TP + FN)
F1 = 2 × precision × recall / (precision + recall)
accuracy = (TP + TN) / all rows
The script sweeps thresholds from 0.1 to 0.9. It applies an illustrative monetary model: correct loan to a good customer earns interest, while a loan to a defaulter loses principal. Treat it as a teaching exercise, not an actual bank policy.
How to defend your choice of a metric
I would not select a threshold by F1 alone. The appropriate threshold depends on what a missed default, wrongly declined borrower, review capacity, fairness constraints, and probability calibration mean in the intended workflow. F1 is useful as a balance of precision and recall, but it does not encode the business cost directly.
Mini-exercise R-D: answer from a confusion matrix
Suppose TP=80, FP=120, FN=20, TN=780.
- Calculate precision.
- Calculate recall.
- Calculate F1 approximately.
- Would accuracy alone make the model look better or worse than it is?
Check: precision = 0.40; recall = 0.80; F1 ≈ 0.533; accuracy = 0.86, which can look deceptively strong despite many false positives.
Flashcards — evaluation
R-25Define precision.
Of the cases predicted positive, the fraction that really are positive: TP/(TP+FP).
R-26Define recall.
Of actual positive cases, the fraction found by the model: TP/(TP+FN).
R-27Define F1.
Harmonic mean of precision and recall.
R-28What happens when you raise the default threshold?
Fewer rows are labelled default; false positives often fall but false negatives can rise.
R-29Why is the repository’s profit sweep not a production policy?
Its revenue and loss values are hypothetical and omit real lending constraints, calibration, fairness, and operational cost.
R-30Why compare against scikit-learn?
It provides a mature baseline and a sanity check for the custom implementation; it is not proof the scratch model should outperform it.
I.7 API and frontend: trace one request
The FastAPI backend lives in backend/main.py. At startup it:
- locates project files from its own path;
- loads and cleans the training data;
- trains both the NumPy and scikit-learn models;
- creates threshold-sweep data;
- stores models, scaling statistics, test data, and sweep outputs in
backend/cache/models.joblib.
Important contracts:
POST /predict: receives a borrower profile in the known feature order and returns results from both models.GET /metrics: returns comparison and threshold-sweep information.GET /health: returns a liveness check.backend/schemas.py: Pydantic request/response contracts keep API data predictable.
The React app uses frontend/src/api.js for HTTP calls. PredictionForm collects values, ResultsPanel displays a response, and ModelPerformance renders evaluation/threshold information.
Request tracing drill R-E
Close this document and draw the route for a user pressing “Predict.” Include every component from browser form to response display. Reopen this only after you have drawn it.
Debugging scenarios
Scenario 1: The frontend gets a CORS error.
Talk through allowed origins in FastAPI’s CORS middleware, the frontend URL, and the backend URL; do not jump straight to disabling CORS broadly.
Scenario 2: An API prediction looks different from notebook results.
First verify feature order, imputation, training-vs-inference scaling statistics, model version, and threshold. These are more likely than “FastAPI changed the model.”
Scenario 3: Server restart takes too long.
Inspect whether the joblib cache exists and is valid. A robust version should also track dataset/model-code versions so stale caches cannot silently serve incompatible data.
Flashcards — delivery
R-31Why serialise the model artefacts?
To avoid retraining on every startup and to reuse the same trained model and preprocessing statistics during serving.
R-32What must an inference request preserve from training?
Feature names/order, imputations, scaling statistics, model version, and threshold policy.
R-33What is Pydantic doing in a FastAPI project?
Validating and documenting structured request/response data.
R-34Why keep api.js separate in React?
It centralises API URLs and HTTP behaviour, keeping UI components focused on presentation/state.
I.8 RiskSight mock interview
Answer each aloud in under 90 seconds. Record yourself on the second attempt.
- Explain RiskSight to a non-technical recruiter.
- Derive the path from
Xw+bto a yes/no decision. - Why did you use class weights rather than oversampling?
- What information leaks in the current preprocessing code?
- A product manager says, “Make recall 100%.” What do you ask before changing the threshold?
- What would you add for a production review?
Production-minded answer: stratified, leakage-free splits; train-only transforms in a pipeline; calibrated probabilities; fairness and drift evaluation; robust numerical clipping; data/model versioning; authentication/audit logging; monitoring; human review rules; and clear non-automated-decision safeguards.
Pyrograph
Pyrograph: heatwave classification prototype
Repository: rexyrocks/pyrograph
II.1 The story before the code
One-sentence story
Pyrograph is a Jaipur-specific prototype that classifies daily heatwave conditions with XGBoost, then serves a versioned, integrity-checked model through a typed FastAPI API.
The crucial wording rule
Call the reported evaluation retrospective classification. Its inputs were observed daily weather. The separate forecast-input pilot used archived forecasts and found that a temperature rule scored higher on CSI at leads of three to five days.
60-second explanation
Pyrograph is an extreme-heat classification prototype. I defined a fixed climatology reference for 2015–2018, used 2019–2021 for training, selected a model on 2022, and evaluated the chosen XGBoost model on 2023–2024. The model consumes observed weather, temperature lags, a temperature-departure feature, and cyclic calendar features. The API validates input ranges with Pydantic and loads the model only after checking a manifest, SHA-256 hashes, and the exact feature order, so a model cannot accidentally be combined with the wrong climatology reference. It supports individual and chronological batch predictions. Severity and persistence are explicit post-processing rules, not hidden inside the classifier. That retrospective test used observed weather. A separate forecast-input pilot found the temperature rule ahead of the classifier on CSI at leads of three to five days.
II.2 Time split and evaluation evidence
The checked evaluation.json contains this experiment design:
| Role | Period | Rows |
|---|---|---|
| Climatology reference | 2015–2018 | fixed before fitting/evaluation |
| Training | 2019–2021 | 1,096 |
| Model selection | 2022 | 365 |
| Test | 2023–2024 | 731 |
The selected model is XGBoost, selected using CSI (Critical Success Index), with F1 then name only as deterministic tie-breakers. Its committed retrospective test metrics are precision 0.8333, recall 0.8491, F1 0.8411, and CSI 0.7258.
Why the three time windows?
- Training teaches model parameters.
- Selection chooses a model/hyperparameter approach without touching the final test period.
- Test estimates how the chosen approach handles later unseen rows.
A random row split would risk training on future weather patterns while evaluating on earlier rows, producing an unrealistically easy task.
CSI in depth
CSI = TP / (TP + FP + FN)
It excludes true negatives. In rare-event detection, there can be many ordinary days; counting them can make a mediocre event detector look good. CSI focuses on hits, false alarms, and missed events.
Flashcards — evaluation
P-01Which model is selected in the committed evaluation?
XGBoost.
P-02What selection metric is used?
Critical Success Index (CSI), then F1 and model name only as tie-breakers.
P-03State the CSI formula.
TP / (TP + FP + FN).
P-04Why does CSI ignore true negatives?
In event detection, abundant ordinary days can otherwise dominate the score and hide poor event detection.
P-05What time period is used as the fixed climatology reference?
2015–2018.
P-06What is the test period?
2023–2024, with 731 rows in the committed artifact.
P-07Why use chronological splits?
To reduce future-to-past leakage and better reflect training on earlier data, testing on later data.
P-08What exact claim should you avoid?
That these results prove real forecasting lead-time skill.
II.3 Inputs and feature engineering
PredictionInput in backend/main.py contains:
- date;
- daily temperatures:
tmax,tmin,tmean; - humidity, maximum wind, pressure, solar radiation, cloud cover;
- lagged maximum temperature for the prior three days;
- lagged minimum temperature for the prior three days;
- optional previous-day heatwave result.
The backend creates additional features:
- temperature departure:
tmax - climatology normal; - day-of-year sine:
sin(angle); - day-of-year cosine:
cos(angle).
Together, the serving manifest expects 17 features.
Why sine and cosine instead of day 1 to 365?
December 31 and January 1 are adjacent in the seasonal cycle but numerically far apart as 365 and 1. Sine/cosine turn the calendar into a circle, so nearby dates remain nearby in feature space.
Why lag features?
Heat events often persist. Recent maximum and minimum temperature values communicate short-term thermal buildup that one day alone may miss. But they only work operationally if those prior observations are actually available at serving time.
Mini-exercise P-A: count the features
Without looking at the list, reconstruct why the model has 17 inputs. Then say which three are engineered inside the service.
Check: 14 supplied weather/lag inputs plus departure, sine, and cosine.
Flashcards — features
P-09What does tmax_departure represent?
Observed maximum temperature minus the climatological normal for the date.
P-10Why use cyclic calendar features?
To represent seasonal continuity across year-end boundaries.
P-11Why use temperature lags?
To capture recent heat persistence and buildup.
P-12What operational concern comes with lag features?
The prior-day inputs must be available at the intended time of prediction; that needs separate validation.
P-13What does strict Pydantic input validation prevent?
Unexpected fields and invalid/non-finite or implausible values from silently reaching the model.
II.4 Safe serving and artefact integrity
The most sophisticated implementation story in this project is backend/serving.py.
The model bundle contains:
artifacts/jaipur-fixed-v2/
manifest.json
model.json
reference.json
evaluation.json
At startup, load_runtime:
- rejects a mixture of separate model/features/climatology environment overrides;
- chooses one bundle directory;
- reads the manifest;
- checks supported schema version and expected 2015–2018 reference period;
- computes SHA-256 for model, reference, and evaluation artefacts and compares them with the manifest;
- loads XGBoost;
- verifies the model’s feature names exactly match the manifest’s 17-feature order;
- places the loaded runtime objects on FastAPI’s
app.state.
Explain why this matters
An ML system is not only model.json. A prediction depends on a model, feature contract, reference climatology, and evaluation context. If someone changes one independently, the service might still return a number but that number can be invalid. The single checked bundle reduces this “silent mismatch” risk.
Mini-exercise P-B: failure mode
Imagine model A is trained with a 2015–2018 reference but someone deploys it with a reference file from a different period. Name two possible outcomes and explain why neither is acceptable.
Answer direction: feature values change in a way the model was never trained on; score distributions/threshold meaning can change; results may look plausible but be wrong. Failing startup is safer.
Flashcards — serving
P-14Why does Pyrograph bundle model and climatology together?
To preserve the exact contract used for training/evaluation and prevent mismatched artefacts.
P-15What is SHA-256 used for here?
Checking that committed artefacts have not changed from the manifest’s recorded contents.
P-16Why verify feature order as well as feature count?
A model can receive the wrong values if fields are reordered while the count remains 17.
P-17Where are loaded runtime objects stored?
On FastAPI’s app.state.
P-18Why fail startup rather than serve a questionable bundle?
Serving a plausible-looking but incompatible prediction is more dangerous than an explicit deployment failure.
II.5 Prediction, severity, persistence, and batches
The model itself returns an XGBoost score. The API converts it to a positive classification at 0.5:
prediction = 1 when probability >= 0.5
Then it applies domain logic:
- severe: positive prediction and
tmax >= p98for that calendar day; - persistence met: the prior day is also heatwave-positive;
- alert triggered: mirrors persistence status in this response.
The important distinction:
ML model predicts a binary condition
↓
explicit post-processing turns it into severity/persistence/alert metadata
For POST /predict/batch, records must have strictly increasing dates. Consecutive days can derive the previous-day heatwave state from the last computed response. A gap clears that automatic continuity; the result becomes unknown unless explicitly supplied.
Mini-exercise P-C: reason about a batch
You send three records: 1 May positive, 2 May positive, 4 May positive. What is persistence for each if no first-record prior state is supplied?
Check: 1 May: unknown/None; 2 May: true because it follows a positive previous day; 4 May: unknown/None because there is a date gap.
Flashcards — inference logic
P-19What threshold turns Pyrograph’s score into a class in the API?
0.5.
P-20Is “severe” a separate fitted model output?
No. It is post-hoc logic: a positive prediction plus maximum temperature at or above p98.
P-21What does the persistence rule need?
A previous-day heatwave result, supplied or derived from a consecutive batch record.
P-22Why must batch dates strictly increase?
The API needs an unambiguous chronological sequence for temporal/persistence logic.
P-23What happens after a date gap?
Automatic previous-day continuity is not assumed; persistence is unknown unless provided.
II.6 The separate risk/planning index
backend/risk.py does not estimate mortality probability. Its own code calls it a transparent planning index and returns mortality_probability: None.
Inputs include heatwave probability, severe/persistence flags, and aggregate shares for older adults, young children, outdoor workers, informal housing, and social deprivation.
It computes:
overall index = 70% heat hazard + 30% vulnerability score
Then it selects a Low/Moderate/High/Severe band, surfaces three largest contributing factors, and returns suggested municipal actions.
Why separate it from the ML model?
The classifier was trained on weather-related heatwave labels. The planning index combines that hazard signal with policy assumptions about vulnerability. It has value as explainable decision support, but it has not been fitted or validated on mortality outcomes. Keeping it separate makes that boundary visible.
Flashcards — risk index
P-24Is Pyrograph’s planning index a mortality model?
No; it explicitly returns an uncalibrated planning index, not mortality probability.
P-25What is the hazard/vulnerability weighting?
70% heat hazard and 30% aggregate vulnerability.
P-26Why surface top drivers?
To make the index auditable and help a planner understand which inputs drive the result.
P-27What would be needed to make mortality-risk claims?
Appropriate granular outcome data, a properly specified/validated model, calibration, and external evaluation—not just this rule-based index.
II.7 Limitations drill
Memorise this exact, mature answer:
The committed test is a retrospective classification evaluation using realised weather, not archived forecasts issued before the target day. Its inputs and lags may not all be operationally available at a real decision cutoff, probabilities are uncalibrated, the work is single-location, and the test period had earlier inspection. Before claiming forecasting performance, I would run a time-stamped backtest using historical forecast issuance data, compare simple operational baselines, calibrate if probabilities drive actions, and validate across separate periods and locations.
Flashcards — limitations
P-28Why are realised-weather results not forecast-skill evidence?
The system gets information that may not have been available at the intended prediction time.
P-29What does “uncalibrated probability” mean?
A score of 0.8 has not been demonstrated to correspond to an observed 80% event frequency.
P-30Why is external validation valuable?
It tests whether results generalise beyond the previously inspected location, period, and workflow.
II.8 Pyrograph mock interview
- Explain fixed climatology in plain English.
- Why is CSI appropriate for this kind of evaluation?
- Trace a
/predictrequest from JSON to result. - How does the service keep model/reference versions consistent?
- Which part is ML and which part is policy/rule logic?
- What must change before a city could use this operationally?
Fieldnotes
Fieldnotes: shared research log
Repository: rexyrocks/the-log
III.1 The story before the code
One-sentence story
Fieldnotes is a small shared research workspace where a team can store, filter, and organise findings by phase, using a React/Vite frontend, Express API, and SQLite persistence.
60-second explanation
Fieldnotes is the collaboration layer around a research project. The browser UI is React and Vite; it gets its API base URL from
VITE_API_URL. The Express backend creates the SQLite schema at startup and stores findings with a constrained phase, contributor, title, body, tags, and timestamp, plus a simple roles table. The API validates fields and phase names, uses parameterised SQL, converts tags between JSON storage and arrays in responses, and returns appropriate HTTP errors. I chose SQLite for simple, portable persistence in a small project and enabled WAL mode for better read/write behaviour. For Railway deployment, the database path is environment-configured and a mounted volume prevents data loss across container redeploys. The shared access PIN is only lightweight gating; I would replace it with real server-side authentication before describing it as secure.
III.2 Data model and startup
backend/server.js starts by reading environment variables:
PORT
DATABASE_PATH
ACCESS_PIN
FRONTEND_URL
It ensures the database directory exists, opens better-sqlite3, enables WAL (write-ahead logging), then creates two tables if they do not already exist.
findings
| Column | Meaning |
|---|---|
id |
auto-incrementing primary key |
phase |
one of seven allowed project phase slugs |
contributor |
author name |
title |
short finding heading |
body |
explanation/content |
tags |
JSON string in SQLite, returned as an array by the API |
created_at |
timestamp default |
roles
| Column | Meaning |
|---|---|
id |
auto-incrementing primary key |
name |
member name |
lane |
role/lane, including possible admin marker |
description |
optional description |
Why WAL?
WAL keeps writes in a separate log before checkpointing them back into the main database. For a small application, it generally lets readers proceed more smoothly while a write occurs. It does not turn SQLite into a distributed, unlimited-concurrency database.
Flashcards — data model
F-01Which two tables does Fieldnotes create?
findings and roles.
F-02Why store tags as JSON text?
SQLite has no native array column; JSON text is a simple way to preserve a variable-length tag list in a small app.
F-03Why convert tags back to arrays in API responses?
The frontend can naturally render and manipulate tags as an array rather than parsing a storage representation.
F-04What is WAL good for?
Better concurrent read/write behaviour for SQLite by writing changes to a log first.
F-05What is DATABASE_PATH for?
It chooses where SQLite persists the database and allows different local/deployed locations without code changes.
III.3 REST API: route by route
Health
GET /health returns { ok: true }. It is useful for deployment platforms and basic checks: “is the process listening and able to answer?” It is not a full database-integrity or dependency-health probe.
Findings
GET /api/findings?phase=scoping
- trims query input;
- validates the phase against a seven-value
Set; - chooses either a phase-filtered or all-findings prepared statement;
- sorts newest first by timestamp and ID;
- parses stored tag JSON before returning rows.
POST /api/findings
- receives phase, contributor, title, body, and optional tags;
- checks the phase and required text fields;
- turns tags into JSON;
- inserts with placeholders;
- selects and returns the created record with HTTP 201.
DELETE /api/findings/:id
- validates the numeric ID and a current-user header;
- loads the finding;
- allows deletion only for its author or a role whose
laneincludes “admin”; - deletes or returns appropriate 400/403/404 errors.
Roles
GET /api/roles returns the role list.
POST /api/roles inserts a new role or updates one if a valid ID exists in the payload. Once roles exist, it checks whether the supplied current user is an admin before allowing role creation/update.
PUT /api/roles/:id validates the positive ID, loads the row, uses existing values for omitted fields, validates the final values, then updates it.
Flashcards — API
F-06What does GET /api/findings?phase=... do?
Lists findings, optionally filtered to one validated phase, newest first.
F-07Why validate phase against a Set?
It limits data to known workflow categories and produces a clear 400 error for invalid filters/creates.
F-08Why use ? placeholders in SQL?
Parameterised queries keep input values separate from SQL syntax and help prevent injection.
F-09Why return HTTP 201 after creating a finding?
It communicates successful resource creation rather than an ordinary retrieval.
F-10What errors can deletion return?
Bad/missing ID or user (400), missing record (404), or non-author/non-admin (403).
F-11Is GET /health a complete health assessment?
No; it is a simple process response and does not prove every dependency or data invariant is healthy.
III.4 Browser application and state
The React app defines seven display labels and matching API slugs. For example, “Scoping & Data Recon” maps to scoping and “Dataset + ML Model” maps to ml-model.
The application keeps separate state for:
- selected tab and active phase;
- findings for a selected view and all findings for overall statistics;
- roles/team;
- loading and error state for findings and team data;
- the add-finding form;
- search string, mobile navigation, and quick-reference panel;
- selected user and PIN gate state.
Keeping loading/error state explicitly makes a disconnected backend visible rather than showing a silently empty application.
The frontend reads:
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'
That enables a local default while allowing a deployed frontend to target its deployed backend.
Request lifecycle exercise F-A
Trace “Add finding” on paper:
click Add finding
→ React opens composer state
→ user fills title/body/tags
→ submit handler validates at UI level
→ fetch POST with JSON
→ Express validates again
→ SQLite insert
→ JSON 201 response
→ React appends/refreshes state and renders the card
Add error branches: bad phase, missing field, offline backend, invalid PIN, and server error.
Flashcards — React/client
F-12Why use VITE_API_URL?
It lets the frontend target different backend URLs by environment without hard-coding deployment-specific addresses.
F-13Why does the UI need both loading and error state?
A request that is in progress, failed, or returned an empty data set are different user experiences.
F-14Why map friendly phase labels to slugs?
The UI can use readable labels while the API receives stable, validated identifiers.
F-15Why must the backend validate even if the form validates?
Any client can bypass or alter browser code; the server is the authority protecting stored data.
III.5 CORS, lightweight access control, and the security boundary
The Express server configures CORS with a comma-separated FRONTEND_URL allowlist. It permits requests without a browser origin. An empty allowlist or a wildcard permits any origin. With a configured list, the server compares the origin to the listed entries.
If ACCESS_PIN is configured, middleware permits only /health and /api/team-names without the PIN. Other routes require an x-access-pin header equal to the configured value.
This is enough to demonstrate how middleware and environment configuration work. It is not strong production authentication:
- the PIN is shared, not tied to an identity;
- the frontend persists it in
localStorage; - a user name is supplied by the client in
x-current-user; - a caller can impersonate another displayed name;
- no session expiry, password hashing, rate limiting, or audit trail exists.
What “fix it” would actually mean
real user identity provider or local accounts
→ server-validated session/token
→ HttpOnly secure cookies where applicable
→ users/roles stored with immutable IDs
→ server derives actor identity from session
→ authorisation checks use that server identity
→ rate limiting, logs, secure secrets, tests
Flashcards — security
F-16What does CORS protect?
It controls which browser origins may read a response; it is not authentication or a complete API security mechanism.
F-17Why is a shared PIN not production authentication?
It does not establish a unique, verified user identity or provide robust session/authorisation controls.
F-18Why is client-supplied x-current-user weak?
A caller controls the header and can claim another name, so the server cannot trust it as identity proof.
F-19What should the server use for an authorisation decision?
Identity derived from a verified server-side session/token, not a client-selected display name.
F-20What does CORS not prevent?
Direct non-browser requests, stolen credentials, or a malicious client; it is not a substitute for authentication/authorisation.
III.6 Deployment and persistence
The project README describes a Railway backend and separately deployed frontend. A key deployment concern is SQLite durability.
Container filesystems are often ephemeral: a rebuild/redeploy can discard local files. The deployment recipe uses a Railway volume mounted at /data, then configures:
DATABASE_PATH=/data/fieldnotes.db
The important sentence is conditional: the file persists while the same volume remains attached. It is not backup, replication, or a guarantee against accidental deletion.
Deployment exercise F-B
Explain the difference among:
- an environment variable;
- a container filesystem;
- a mounted persistent volume;
- a backup.
If you can explain all four clearly, you can handle most intern-level deployment questions.
Flashcards — deployment
F-21Why can an SQLite file vanish after a redeploy?
The container’s writable filesystem may be ephemeral and recreated during deployment.
F-22What does a mounted volume solve?
It gives the database file storage that can survive container replacement while the volume is retained.
F-23Is a persistent volume a backup strategy?
No; it provides persistence, not independent recoverable copies or disaster recovery.
F-24Why avoid hard-coding PORT?
Hosting platforms commonly provide the port through environment configuration.
III.7 Scaling and improvements
If the team grows from 5 people to 500
Say this:
SQLite was the right simplicity trade-off for a small shared tool, but for multi-instance deployment, higher write concurrency, mature access control, and richer reporting, I would migrate to Postgres. I would introduce migrations, indexes based on observed queries, a real identity model, and API/integration tests before optimising the frontend.
Suggested incremental improvements
- Move route validation into a schema library such as Zod/Joi or carefully written validators.
- Split
App.jsxinto page, findings, team, and authentication components/hooks. - Add backend route tests using a temporary database.
- Make role checks server-derived from a real session.
- Add database migrations and indexes if data grows.
- Add pagination/search server-side when findings become numerous.
Fieldnotes mock interview
- Why was SQLite suitable here?
- What does WAL change, and what does it not change?
- Trace a POST finding request and its validation.
- How do parameterised queries help?
- What happens if the frontend is deployed but
VITE_API_URLis wrong? - Why is the PIN approach not strong auth, and how would you replace it?
Cross-project mastery
Cross-project mastery
IV.1 The project map
RiskSight
strongest proof: ML fundamentals + evaluation thinking
strongest risk: data leakage / overclaiming business value
Pyrograph
strongest proof: time-aware ML + robust model-serving contract
strongest risk: presenting retrospective classification as forecasting
Fieldnotes
strongest proof: end-to-end web/API/database engineering
strongest risk: describing lightweight PIN gating as secure auth
IV.2 Cross-project flashcards
X-01Which project best demonstrates custom ML mathematics?
RiskSight.
X-02Which project best demonstrates artefact/version integrity?
Pyrograph.
X-03Which project best demonstrates ordinary CRUD/API/database work?
Fieldnotes.
X-04Name one limitation in each project.
RiskSight: preprocessing leakage in current scaling flow. Pyrograph: realised-weather retrospective evaluation is not forecast validation. Fieldnotes: shared PIN/client identity is not robust auth.
X-05What is a feature contract?
The agreed feature names, order, types, transformations, and semantics expected by a trained model at inference time.
X-06What does reproducibility mean across these projects?
A future run can trace and recreate behaviour from fixed code, data assumptions, seeds, configuration, artefacts, and environment contracts.
X-07What is the difference between validation and testing?
Validation guides model/configuration selection; a final test set should remain untouched until selection is complete for a less biased estimate.
X-08What is the difference between a health check and business correctness?
A health check shows the service responds; it does not prove the data, model, authorisation, or output is correct.
X-09Give a correct response when you do not know an answer in interview.
State what you know from the implementation, name the assumption/uncertainty, and describe the check you would run rather than guessing.
X-10What makes a project explanation credible?
Concrete scope, data flow, a real trade-off, evidence with context, a limitation, and a realistic next step.
IV.3 Explain it at three levels
Practice every project for three audiences.
| Audience | Goal | Example opening |
|---|---|---|
| Recruiter | impact and role fit | “I built a project that takes a data/operational problem into a usable application.” |
| Engineer | architecture and trade-offs | “The system validates input, uses this serving/data contract, and I made this trade-off because…” |
| ML interviewer | methodology and evidence | “The split/metric/threshold was chosen this way; here is the limitation and how I would validate it.” |
IV.4 Answer templates
“What was the hardest part?”
The hardest part was not the initial code; it was defining a contract that stays correct across steps. In RiskSight that is keeping preprocessing identical in training and inference. In Pyrograph it is keeping the model, climatology, and feature order compatible. In Fieldnotes it is making persistence and the browser/API boundary explicit. I learned to look for hidden assumptions at those boundaries.
“What did you personally do?”
I implemented and integrated the code represented in the repository: [name the exact module/function], then I verified it by [metric/test/request path]. I would be careful not to claim external users, operational deployment, or outcomes that I did not independently measure.
“What would you do with two more weeks?”
First I would close the correctness risk: [leakage-free pipeline / forecast-time backtest / real authentication]. Then I would add focused automated tests around the critical request/data flow. Only after that would I work on extra UI or features.
Mock interviews
Active-recall exam bank
Do these without notes. Mark each answer green (complete), yellow (partial), or red (could not recall). Revisit every red card tomorrow.
Rapid round: 30 questions
- Define logistic regression in one sentence.
- Why does sigmoid appear in logistic regression?
- What does a 0.5 threshold do?
- Explain precision versus recall using lending.
- What is class weighting?
- What exact preprocessing leakage exists in RiskSight?
- How would you save correct preprocessing for an API?
- What does L1 encourage that L2 does not?
- Why is a hypothetical profit table not a business policy?
- What is a chronological split?
- Why is it appropriate for Pyrograph?
- What is CSI and why might it help with rare events?
- What is a fixed climatology reference?
- Name the three engineered Pyrograph feature types added by the API.
- What is the model-bundle manifest protecting against?
- Why validate feature order?
- What turns a positive Pyrograph classification into “severe”?
- What creates a persistence signal?
- Why is realised weather not forecast validation?
- Why is Pyrograph’s planning index not mortality probability?
- Why choose SQLite for Fieldnotes?
- What does WAL do?
- How do prepared SQL statements help?
- Why validate API input on the server?
- What does
VITE_API_URLdo? - What does CORS do—and not do?
- Why is a shared PIN not strong auth?
- Why is a mounted volume useful to SQLite?
- What first change would you make for each project?
- Give your 30-second pitch for each project.
Mini whiteboard tasks
- Draw RiskSight’s training and inference paths. Circle the point at which leakage must be prevented.
- From memory, derive precision, recall, and CSI from TP/FP/FN/TN.
- Draw Pyrograph’s bundle-validation path and label the three checked artefacts.
- Draw a three-day
/predict/batchsequence and explain date-gap behaviour. - Draw Fieldnotes’ React → Express → SQLite request path for one new finding.
- Redesign Fieldnotes auth in six boxes, ending with a server-side authorisation check.
Code reading tasks
Open each file in GitHub and annotate it yourself.
- RiskSight:
logistic_regression.py. Put a comment beside every line that changesworb. - RiskSight:
preprocessing.py. Mark each transformation as “fit”, “transform”, or “both,” then explain why the current design leaks. - Pyrograph:
backend/serving.py. List each startup condition that can fail and what bad deployment it prevents. - Pyrograph:
backend/main.py. Find where the 17 feature values are put in the manifest-prescribed order. - Fieldnotes:
backend/server.js. For each route, list input, validation, database action, and status code. - Fieldnotes:
frontend/src/App.jsx. Find where the API base URL is read and where error state changes the visible UI.
14-day plan
14-day recall calendar
Keep sessions short and active. Stop rereading when you can retrieve.
| Day | Session | Success condition |
|---|---|---|
| 1 | RiskSight I.1–I.4 + cards R-01–R-19 | 60-second explanation with no notes. |
| 2 | RiskSight I.5–I.7 + cards R-20–R-34 | Explain leakage repair and threshold trade-off. |
| 3 | RiskSight mock + rewrite one answer | Answer six follow-ups without jargon. |
| 4 | Pyrograph II.1–II.3 + P-01–P-13 | State timeline, CSI, and 17-feature story. |
| 5 | Pyrograph II.4–II.6 + P-14–P-27 | Draw artefact integrity and batch flow. |
| 6 | Pyrograph limitations + mock | Say “not forecast skill” confidently and explain what is needed. |
| 7 | Fieldnotes III.1–III.3 + F-01–F-11 | Trace one POST request and schema. |
| 8 | Fieldnotes III.4–III.6 + F-12–F-20 | Explain CORS vs auth and real-auth replacement. |
| 9 | Fieldnotes deployment + mock | Explain volume versus backup. |
| 10 | Mixed cards R/P/F/X | Score 80% green without notes. |
| 11 | Record three project pitches | Remove filler and claims you cannot defend. |
| 12 | Whiteboard all six tasks | Complete each in five minutes. |
| 13 | Full mock interview | 20 minutes: intro + all projects + follow-ups. |
| 14 | Light revision | Review only yellow/red cards; sleep well. |
Final check
Final pre-interview rule
Start with the problem and your contribution. Then give the data or request flow, one design decision, one result with its measurement context, and one limitation. End by naming the first thing you would change.