This project predicts whether a code change may be risky.
The current beginner version uses a small sample dataset with simple code-change features:
- number of files changed
- number of lines added
- number of lines deleted
The model learns from previous examples and predicts whether a new code change looks risky or not risky.
Later, this project will use real Git commit data, CodeBERT embeddings, and LLM-generated explanations for code reviewers.
During code review, some changes are more likely to cause bugs than others.
For example, a change that modifies many files and many lines may need more careful review than a very small change.
This project explores whether machine learning can help reviewers identify risky code changes earlier.
The current version is a beginner baseline.
It uses:
- a small fake commit dataset
- basic static features
- Logistic Regression
- simple risk prediction
- saved model results
Current input features:
files_changed
lines_added
lines_deleted
Current label:
risky
Where:
0 = not risky
1 = risky
LLM-Assisted-Code-Change-Risk-Predictor/
├── data/
│ └── sample_commits.csv
├── outputs/
│ ├── figures/
│ └── tables/
│ └── simple_results.txt
├── src/
│ ├── load_dataset.py
│ ├── prepare_xy.py
│ ├── train_simple_model.py
│ ├── test_simple_model.py
│ ├── predict_new_change.py
│ └── save_simple_results.py
├── README.md
└── requirements.txt
Create a virtual environment:
python -m venv .venvActivate it:
source .venv/bin/activateInstall dependencies:
pip install -r requirements.txtCheck setup:
python src/check_setup.pyLoad and inspect the dataset:
python src/load_dataset.pySeparate inputs and output:
python src/prepare_xy.pyTrain a simple model:
python src/train_simple_model.pyTest the model:
python src/test_simple_model.pyPredict one new code change:
python src/predict_new_change.pySave experiment results:
python src/save_simple_results.pyExample prediction:
New code change:
files_changed = 6
lines_added = 220
lines_deleted = 90
Risk prediction:
RISKY
Risk probability:
0.96
Reviewer note:
This change may need careful review because it modifies 6 files and changes 310 total lines.
This project uses ApacheJIT as the first real commit-level defect prediction dataset.
Download the training CSV:
mkdir -p data/raw data/processed
wget -O data/raw/apachejit_train.csv "https://zenodo.org/records/5907002/files/apachejit_train.csv?download=1"Load and inspect the dataset:
python src/load_real_dataset.pyThis creates:
data/processed/apachejit_train_processed.csv
The first real baseline uses ApacheJIT commit-level metrics.
Models compared:
- Logistic Regression
- Random Forest
Metrics:
- accuracy
- precision
- recall
- F1 score
Result table is saved at:
outputs/tables/final_real_model_comparison.csv
Markdown version:
outputs/tables/final_real_model_comparison.md
| model | accuracy | precision | recall | f1_score |
|---|---|---|---|---|
| Random Forest | 0.7213 | 0.7167 | 0.7322 | 0.7243 |
| Logistic Regression | 0.6822 | 0.7359 | 0.5685 | 0.6414 |
The current model learns simple patterns such as:
Small code changes are usually lower risk.
Large code changes are usually higher risk.
This is only a beginner baseline.
The goal is not to claim this fake-data model is useful yet.
The goal is to build the full pipeline step by step.
Next, this project will add:
- better static features
- real commit data
- proper evaluation tables
- Random Forest baseline
- CodeBERT code embeddings
- static + CodeBERT fusion model
- reviewer-facing LLM explanations
- error analysis
The final system should take a code change or commit diff and output:
Risk score: 82%
Explanation:
This change may be risky because it modifies many files, changes complex logic, and resembles previous risky commits.
The long-term goal is to build an explainable AI4SE system for commit-level defect risk prediction.
Current status:
Stage 2/3 complete:
Tiny fake dataset + simple ML baseline + saved results.
Next stage:
Improve the baseline with more features and cleaner evaluation.
Install PyDriller:
pip install pydrillerClone a sample repository:
mkdir -p external_repos
git clone https://github.com/pallets/markupsafe.git external_repos/markupsafeRead sample commits:
python src/read_git_commits.pyThis creates:
outputs/tables/sample_git_commits.csv
When we mine commits from a normal Git repository using PyDriller, we can extract commit features such as:
- commit message
- files changed
- lines added
- lines deleted
- total churn
However, normal Git history does not automatically tell us whether a commit is risky or bug-inducing.
For supervised training, this project uses ApacheJIT because it already includes commit-level risky/clean labels.
Mined Git commits are useful for feature extraction practice and future prediction demos.
This project uses the Hugging Face tokenizer for:
microsoft/codebert-base
The tokenizer turns cleaned diff text into tokens and token IDs.
Run:
python src/load_codebert_tokenizer.py
python src/tokenize_clean_diff.pyOutputs:
outputs/tables/codebert_tokenizer_example.csv
outputs/tables/clean_diff_tokens.csv
After creating CodeBERT embeddings, the project saves them in reusable formats.
Run:
python src/save_codebert_features_reusable.py
python src/load_saved_codebert_features.pyOutputs:
data/features/codebert_embedding_features.csv
data/features/codebert_embedding_matrix.npy
data/features/codebert_embedding_metadata.csv
data/features/codebert_embedding_feature_names.txt
outputs/tables/codebert_feature_export_summary.csv
The .npy file stores the numeric embedding matrix for fast model training.
This project compares three feature sets:
- Static-only features
- CodeBERT-only embeddings
- Static + CodeBERT fusion features
Run:
python src/create_toy_fusion_dataset.py
python src/train_toy_fusion_classifier.py
python src/save_final_fusion_comparison.pyOutputs:
outputs/tables/final_toy_fusion_model_comparison.csv
outputs/tables/final_toy_fusion_model_comparison.md
outputs/figures/final_toy_fusion_f1_comparison.png
Note: this is a toy fusion experiment using demo labels. The real fusion experiment requires static features and CodeBERT embeddings from the same labeled commits.
This pipeline mines real commit diffs from the ApacheJIT commit_id + project fields, creates CodeBERT embeddings, joins them with ApacheJIT static features and labels, and trains a real fusion classifier.
Run the full pipeline:
python scripts/run_real_fusion_pipeline.py --max-commits 2000 --resumeOr run step by step:
python scripts/mine_apachejit_diffs.py --max-commits 2000 --resume
python scripts/create_apachejit_codebert_embeddings.py --resume
python scripts/finetune_codebert_apachejit.py
python scripts/create_apachejit_finetuned_embeddings.py --resume
python scripts/reduce_fusion_embeddings.py \
--input-path data/embeddings/apachejit_finetuned_embeddings.csv \
--output-path data/embeddings/apachejit_finetuned_embeddings_pca.csv \
--pca-model-path models/fusion_finetuned_pca.joblib \
--selection-path outputs/tables/real_fusion_finetuned_pca_selection.csv
python scripts/create_real_fusion_dataset.py --embedding-source finetuned_pca
python scripts/train_real_fusion_classifier.py --model random_forest --tune-hyperparams --tune-threshold
python scripts/save_final_real_fusion_comparison.py
python scripts/summarize_results_for_report.pyKey inputs:
data/processed/apachejit_train_processed.csv
Key outputs:
data/processed/apachejit_diff_index.csv
data/processed/apachejit_fusion_dataset.csv
data/embeddings/apachejit_codebert_embeddings.csv
outputs/tables/final_real_fusion_model_comparison.csv
outputs/tables/report_results_summary.csv
Notes:
--max-commits 0mines all ApacheJIT commits (slow; requires network access for PyDriller).- Default
--max-commits 2000uses a stratified sample for a practical first real evaluation. - Mining uses GitHub repositories such as
https://github.com/apache/groovy. - Resume flags let you continue mining and embedding after interruptions.
The project creates grounded reviewer-facing explanations from evidence packets.
Run:
python src/create_explanation_evidence_packets.py
python src/create_safe_llm_prompts.py
python src/generate_sample_explanations.pyOutputs:
outputs/evidence/explanation_evidence_packets.jsonl
outputs/prompts/llm_explanation_prompts.jsonl
outputs/explanations/sample_llm_explanations.csv
outputs/explanations/sample_llm_explanations.jsonl
outputs/explanations/sample_llm_explanations.md
The explanations are review aids. They do not prove that a bug exists.
The system predicts whether a code change may be risky and generates a grounded explanation for reviewers.
Example output is saved at:
outputs/explanations/final_explanation_examples_short.md
The explanation is based on evidence such as:
- risk probability
- files changed
- lines added
- lines deleted
- total churn
- changed file paths
The explanation is a review aid, not proof that a bug exists.
Run the full static-feature risk prediction pipeline:
python scripts/run_pipeline.py --input sample_inputs/sample_commit.jsonThis runs:
- model training
- prediction for one sample commit
- reviewer-facing explanation
Main outputs:
models/static_risk_model.joblib
outputs/tables/final_training_metrics.csv
outputs/predictions/prediction_result.txt
outputs/explanations/prediction_explanation.txt
outputs/pipeline/pipeline_summary.txt
The prediction and explanation are review aids, not proof that a bug exists.
code-change-risk-predictor/
├── configs/ # configuration files
├── data/
│ ├── raw/ # original downloaded datasets
│ ├── processed/ # cleaned datasets
│ ├── features/ # saved feature matrices
│ └── embeddings/ # saved embedding files
├── examples/ # small example diffs and inputs
├── models/ # trained model files
├── notebooks/ # optional exploration notebooks
├── outputs/
│ ├── tables/ # CSV result tables
│ ├── figures/ # plots and confusion matrices
│ ├── explanations/ # generated explanations
│ ├── evidence/ # explanation evidence packets
│ ├── error_analysis/ # false positive/negative analysis
│ ├── pipeline/ # pipeline summaries and logs
│ ├── predictions/ # prediction outputs
│ └── prompts/ # LLM prompt templates
├── scripts/ # command-line entry points
├── src/ # Python source and lesson scripts
├── tests/ # future tests
├── README.md
├── requirements.txt
└── .gitignore
Check the structure:
python scripts/check_project_structure.pyProject settings are stored in:
configs/default.yaml
The config includes:
- project name
- dataset paths
- model settings
- CodeBERT settings
- output folders
- prediction paths
- explanation safety rule
Check the config with:
python scripts/check_config.pyThe project includes a reusable logging utility:
src/logging_utils.py
Check logging with:
python scripts/check_logging.pyThis writes logs to:
logs/project.log
Log files are ignored by Git because they are generated during runs.
Run the test suite with:
pytestThe tests check:
- required project folders and files
- config file sections
- sample prediction input validity
- prediction input feature compatibility, if trained feature names exist
The project report is stored in:
reports/final_report.md
It describes the problem, dataset, method, experiments, explanations, error analysis, limitations, and conclusion.
The project includes a full-stack web application for reviewer-facing risk prediction.
- Backend: FastAPI (
backend/) serves the saved static ApacheJIT model, grounded explanations, metrics, error analysis, and the final report. - Frontend: React + Vite (
frontend/) provides a dashboard UI for prediction, evaluation summaries, and project documentation views. - Current production model: The web app uses the saved static ApacheJIT Random Forest model (
models/static_risk_model.joblib) trained on commit-level static features. - Experimental extension path: CodeBERT embeddings and static + CodeBERT fusion workflows exist in the repository as research/demo code, but they are not the current production inference path.
- Safety note: All predictions and explanations are review aids. They do not prove that a bug exists.
From the repository root, activate your Python environment if needed, then:
cd backend
pip install -r requirements.txt
uvicorn app.main:app --reloadThe API runs at http://localhost:8000.
In a second terminal:
cd frontend
npm install
npm run devOpen the app at:
http://localhost:5173
Interactive OpenAPI docs:
http://localhost:8000/docs
- Dashboard — API health, model status, key metrics
- Predict Risk — submit commit features, view prediction and grounded explanation
- Model Metrics — training and report summary tables
- Error Analysis — false positives, false negatives, grouped errors
- Report — final project report markdown
- Settings — model paths, feature names, API configuration
See WEB_APP_PLAN.md for architecture, endpoints, and future roadmap.
Model file missing
If prediction returns 503 or model info shows model_loaded: false, train the static model first:
python scripts/train_model.pyThis creates:
models/static_risk_model.joblib
models/static_feature_names.txt
Backend not running
If the frontend shows a network error or cannot load dashboard data, start the FastAPI server:
cd backend
uvicorn app.main:app --reloadCORS issue
The backend allows http://localhost:5173 by default. If you run the frontend on a different host or port, update CORS in backend/app/main.py or run Vite on port 5173.
Frontend cannot reach API
The frontend uses VITE_API_BASE_URL with default http://localhost:8000.
Check:
- Backend is running on port
8000 - Browser can open
http://localhost:8000/health - Set a custom API URL when needed:
cd frontend
VITE_API_BASE_URL=http://localhost:8000 npm run devcd backend
pytestRun the full web app with Docker Compose from the repository root:
docker compose up --buildThis starts:
- Backend on
http://localhost:8000 - Frontend on
http://localhost:5173
The backend container mounts project files from the host:
models/configs/outputs/reports/
The frontend is built with:
VITE_API_BASE_URL=http://localhost:8000
API docs remain available at http://localhost:8000/docs.
Stop the stack with:
docker compose downLocal development without Docker still works using the backend and frontend commands above.