ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
Past-paper tracking that finds the topics costing you marks, and an AI prediction engine built on ten years of real grade boundaries.
EducationPython · HTMLGitHub @vineigenphaseOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Past-paper tracker for A-level and SQA students — predicts the grade you are on from your own marks against real published grade boundaries, and picks the next three questions to practise. Flask, Postgres, Stripe.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
A past-paper tracker that tells A-level and SQA students the grade they are
actually on, and the three questions that would move it.
A student finishes a past paper, writes "62%" at the top, and files it. That
number is close to meaningless. 62% on a brutal 2019 Physics paper and 62% on a
soft 2023 one are not the same performance, and neither tells them what to do
on Tuesday evening.Read the full README ↗A past-paper tracker that tells A-level and SQA students the grade they are actually on, and the three questions that would move it.
Live at telosapp.co.uk · Flask · Postgres · Railway · Stripe · installable PWA
A student finishes a past paper, writes "62%" at the top, and files it. That number is close to meaningless. 62% on a brutal 2019 Physics paper and 62% on a soft 2023 one are not the same performance, and neither tells them what to do on Tuesday evening.
Telos records every question separately, converts each attempt to a position on a continuous grade scale using that paper's real published boundaries, and turns the residue into a ranked list of what is costing marks.
Three questions, in order:
| Diagnosis | Which topics are bleeding marks, ranked by what they actually cost |
| Prediction | What grade am I on, with a confidence level and the marks to the next boundary |
| Prescription | What are the three specific questions to do next |
| Qualifications | 67 — 61 graded across AQA, Edexcel, OCR A and SQA, plus 6 admissions tests |
| Grade boundary rows | 1,001 real published boundaries |
| Levels | A-Level, AS-Level, Higher, Advanced Higher, admissions test |
| Components | 219 papers, modules, parts and coursework units |
| Routes | 85 |
| Tables | 33, under 51 numbered migrations |
| Tests | 32 suites, ~987 assertions |
| Code | ~45,000 lines across 253 tracked files |
Coverage is not approximate. test_boundaries.py fails the build if any
graded paper the app offers lacks boundaries — a qualification a student can
select but cannot be graded on is a bug, not a gap.
The exemption for ungraded qualifications is two-sided, so it cannot become a loophole. TMUA and ESAT report a 1–9 scale score and have no A*–E ladder at all, so they are not required to have boundaries — and they are required not to have any. A boundary row for a 1–9 scale test is somebody's invention, and the same test catches it.
The reverse direction is reported but deliberately not failed on: Edexcel publishes boundaries for Further Maths option papers the catalogue does not yet offer. That is real data waiting on a missing feature, so the suite prints it every run rather than hiding it or treating it as an error.
app.py Flask routes, session, entitlement gates (~3,600 lines)
db.py psycopg3 shim — Postgres behind a sqlite3 API
prediction.py grade engine — pure, no Flask, no DB
prescription.py "your next 3 questions" — pure
revision.py spaced repetition — pure
admissions.py equipercentile equating — pure
admissions_papers.py the official ENGAA/NSAA/TMUA papers and keys — pure
sharecards.py server-rendered PNG share cards
brand.py the Telos mark, drawn in code
interview.py Telos Interview — AI mock Oxbridge interviews, own blueprint
paper_templates.py 67 qualifications, 219 components
migrations/ 51 numbered idempotent SQL migrations
tests/ 32 standalone suites
scripts/boundaries/ 36 board-document scripts
prediction.py, prescription.py and revision.py import no Flask and touch
no database. They take plain data and return plain data.
This is the single decision the codebase most depends on. The grade engine has
genuinely intricate rules — recency weighting, difficulty normalisation,
confidence intervals, qualifications whose ladder stops at A instead of A* —
and all of it is testable without a request context, a fixture user, or a
network round trip. test_prediction.py and test_engine_sweep.py between
them exercise every qualification in the catalogue in about a second.
A*=6 A=5 B=4 C=3 D=2 E=1 U=0 with fractional positions between
A grade score of 4.6 means "comfortably into B, most of the way to an A". Each attempt is placed on this scale using the boundaries for that specific paper and series, so paper difficulty normalises out automatically.
Three details that took real care:
a_star
absent means it tops out at A, d present with e absent means it bottoms
out at D — so an AS student is never predicted a grade that cannot appear on
their certificate.MissingBoundaries is
raised and handled. Summer 2020 and 2021 were cancelled in England, so no
boundaries exist; an attempt at those years falls back to the median of the
real years, which is the honest answer.derived_from_course so the
interface can say so rather than implying a precision that is not there.auth.py is the single source of truth for paid access, and nothing grants Pro
on a redirect back from checkout. A customer.subscription.* webhook is the
only thing that writes an entitlement. A user who closes the tab at the wrong
moment, or who edits the success URL by hand, gets exactly what they paid for.
The gate is deliberately generous in the other direction: past_due keeps
access, because Stripe retries a failed card for about two weeks and a student
mid-revision should not be locked out over an expired card. Only canceled and
unpaid cut access.
This was verified end to end in live mode with a real card — charge, webhook, Pro granted, cancel, access removed.
db.py — Postgres behind a sqlite3 APITelos began on SQLite. Rather than rewrite every call site during the Postgres
migration, db.py presents the sqlite3 interface the app already spoke — ?
placeholders, .lastrowid, row objects that index by name — over psycopg3.
It also carries the operational scar tissue that hosting on Neon requires: a serverless Postgres instance sleeps, so a pooled connection can be dead by the time it is handed out. Connections idle longer than a 15-second grace are health-checked before use, and a query that fails on a dead connection is retried exactly once — but only if it had not already done work, so a retry can never replay a partial write.
Free — diagnosis
Pro — prediction and prescription
Everyone
A few decisions worth explaining, and a few scars worth keeping.
40 SQL files, tracked by filename in schema_migrations. The Procfile is a
bare gunicorn line — migrations are run deliberately, by hand, because a
migration that runs automatically on every boot is a migration that will
eventually run during an incident.
They are idempotent because they get re-run. One of them once had a DELETE
scoped more widely than its INSERT and removed 98 rows it had not written on
its second run. The fix — scoping the delete to exactly what the insert
creates — is now the rule the rest follow.
36 scripts under scripts/boundaries/ — extractors, generators and
verifiers. Every extractor
validates each component against its own maximum mark before emitting SQL.
That guard exists because a mis-parsed PDF column silently produces boundaries
that are plausible, wrong, and would quietly mis-grade every student who sat
that paper.
PDF and spreadsheet parsing dependencies are installed for the extraction and
uninstalled afterwards. They are not in requirements.txt — the running
application has no reason to be able to read a PDF.
No pytest. Each suite is a Python file that runs top to bottom, prints
PASS/FAIL per assertion, and exits non-zero on failure; tests/run_all.py
runs all 24. The integration suites create and destroy their own fixture users
through tests/_fixtures.py, which exists because killed runs used to leave
orphans behind that broke the next run.
The suite is also where non-obvious invariants live:
None when there is nothing to compare against, never 0 —
a new account has no trend, and "+0 this week" is a lie told to every user on
their first day.TELOS_STATE.md keeps the full list. Three that generalise:
.btn { display: inline-flex } beats the browser's [hidden] rule.
Buttons meant to be hidden were visible in production. Specificity beat
intent, silently.python -m venv .venv
.venv\Scripts\python.exe -m pip install -r requirements.txt
railway run .venv\Scripts\python.exe app.py # dev server :5000
railway run .venv\Scripts\python.exe tests\run_all.py # all 24 suites
railway run .venv\Scripts\python.exe migrations\run_migrations.py
railway run injects the environment; see .env.example for the variable
list. Secrets live in Railway and never in the repository.
railway runalso injects the productionCANONICAL_HOST, which 301s the test client.run_all.pystrips it per suite — which is why suites are run through the runner rather than individually.
| Application | Flask 3.1, Flask-Login, gunicorn (threaded workers) |
| Database | Neon Postgres (eu-west-2), psycopg3 with pooling |
| Hosting | Railway, EU West, auto-deploy from main |
| Payments | Stripe — Checkout, Billing Portal, webhooks (live) |
| Resend, DKIM/SPF verified | |
| Images | Pillow — share cards and PWA icons rendered in code |
| Front end | Server-rendered Jinja, hand-written CSS, no framework |
Eight runtime dependencies — the eighth is anthropic, for Telos Interview.
There is no JavaScript build step, no bundler and
no CSS framework — ~5,200 lines of hand-written CSS and 1839 of vanilla JS.
Proprietary — all rights reserved. See LICENSE.
Telos is a commercial service. The source is published so it can be read and evaluated, not so it can be reused: no permission is granted to deploy it, copy it, or run a service derived from it. Quoting excerpts for review or teaching is fine, with attribution.
The grade boundary data is published by AQA, Pearson Edexcel, OCR and SQA. It is factual reference data, it is not mine, and those organisations' own terms govern it.
/terms and /privacy are the service's own documents, and both are public —
somebody deciding whether to sign up, or a parent checking what their child's
revision app collects, should not need an account to read them.
app.py db.py auth.py mailer.py brand.py core application
prediction.py prescription.py revision.py pure engines
admissions.py admissions_papers.py pure engines, admissions
sharecards.py paper_templates.py rendering, catalogue
migrations/ 51 numbered SQL migrations
scripts/boundaries/ 36 board-document scripts
scripts/check_stripe.py read-only Stripe config verification
scripts/build_source_dump.py whole codebase as one annotated file
scripts/upload_admissions_papers.py push the official PDFs to the volume
tests/ 32 suites, ~987 assertions
templates/ 44 Jinja templates, including /terms and /privacy
LICENSE proprietary — all rights reserved
static/ CSS, JS, fonts, PWA manifest, service worker
TELOS_STATE.md living handoff — infrastructure, phases, gotchas
TELOS_ARCHIVE.md the reasoning behind every settled decision