Documentation Index
Fetch the complete documentation index at: https://mintlify.com/vruizz22/innova-ai-engine/llms.txt
Use this file to discover all available pages before exploring further.
nightlyBkt is the nightly calibration job that keeps the platform’s Bayesian Knowledge Tracing model accurate over time. It runs once every 24 hours, fetches all attempts from the last 30 days for each active skill, and performs a brute-force grid search over the four BKT parameters — p_l0, p_transit, p_slip, and p_guess — choosing the combination that maximises the log-likelihood of the observed attempt sequences. The results are upserted into skill_bkt_params, which the backend reads on each student attempt to perform the online BKT update. Because the calibration is fully deterministic (scipy + numpy, no LLM calls), the function uses no external API keys and never touches S3.
Trigger and configuration
| Property | Value |
|---|---|
| Trigger | EventBridge scheduled rule |
| Schedule | cron(0 7 * * ? *) — every day at 07:00 UTC |
| Timeout | 900 s |
| Memory | 1024 MB |
| Handler | src.pipeline.nightly_bkt.handler |
| Event payload | (none read — scheduled invocation) |
This function runs 15 minutes before
nightlyIrt (cron(15 7 * * ? *)). The ordering is intentional: up-to-date BKT parameters produce better p_known (theta) estimates, which in turn improve the quality of the IRT calibration performed immediately after.Execution flow
Fetch active skills
The handler opens an asyncpg connection pool and runs:This returns every skill that is currently live on the platform.
Query 30-day attempt history per skill
For each skill, the worker fetches all attempts created in the last 30 days, joined to The timestamp is extracted as a Unix epoch (
items to filter by skill_id:float) so that AttemptObservation can sort attempts chronologically per student.Skip low-data skills
Skills with fewer than 50 attempts in the window are skipped — there is not enough signal for a reliable calibration:The structured log event
bkt_skip_low_data is emitted for every skipped skill, including the actual attempt count.Build AttemptObservation list
Each database row is converted to an
AttemptObservation Pydantic model:Run grid-search calibration
calibrate_skill(attempts) performs a brute-force search over all combinations of (p_l0, p_transit, p_slip, p_guess) on a grid from 0.05 to 0.95 in steps of 0.05. Combinations where p_slip + p_guess >= 1.0 are skipped for identifiability. The combination with the highest total log-likelihood across all students is returned as a BktParams object.Return payload
The handler returns a summary dict to EventBridge. Each key incalibrated_skills is a skill_id string; the value is the full serialised BktParams:
BktParams schema
Prior probability that a student already knows the skill before any practice. Bounded
[0.0, 1.0].Probability that a student transitions from not-knowing to knowing after each practice opportunity. Bounded
[0.0, 1.0].Probability that a student answers incorrectly despite knowing the skill. Bounded
[0.0, 0.5]. The model requires p_slip + p_guess < 1.0 for identifiability.Probability that a student answers correctly without knowing the skill. Bounded
[0.0, 0.5].Total log-likelihood of the observed attempt sequences under the fitted parameters.
null only if no valid grid point was found (degenerate case; defaults are returned instead).Local invocation
BecausenightlyBkt reads no event payload, it can be run end-to-end against a local or staging database with a single command:
DATABASE_URL is set in your .env file pointing at a Postgres instance with skills, items, attempts, and skill_bkt_params tables.