Skip to Content

CBM & ORF Fluency

The CBM module (WP-CBM-BE) measures reading fluency and accuracy over time. It has two halves: the probe (a teacher-scored 60-second oral read) and the trend (repeated equal-difficulty probes plotted against an aim line, so a teacher can see early whether support is producing growth).

CBM scope is restricted to fluency and accuracy modalities only. Comprehension, vocabulary, morphology, and syntax monitoring belong to Progress Monitoring, not CBM. Sending a non-fluency modality to the CBM endpoints returns 400 cbm_scope_restricted_v2_3.

No speech recognition

The platform does not use automatic speech recognition (ASR) in Wave 1 or Wave 2 (V-5, Q16). The teacher listens to the student read and taps errors on a scoring grid. The server receives the error count, timing, and total words, and computes WCPM + accuracy. Audio recorded during a session is archive-only; it is never processed by any AI or speech system.

Supported CBM modalities

cbmTypeDescription
ORF_CBMOral reading fluency: words correct per minute (WCPM) from the teacher’s 60-second timing
ORF_ACCURACYOral reading accuracy: percentage of words read correctly
WORD_LIST_ACCURACYAccuracy on an isolated word list
SENT_TEXT_ACCURACYAccuracy on sentence or passage reading

Any other cbmType value is rejected with 400.

The ORF probe flow

  1. POST /api/orf/assessments/start: opens an assessment session for a student + passage.
  2. POST /api/orf/passages/:id/words: (optional) loads the word list for tap-error marking.
  3. POST /api/orf/assessments/:id/mark: records an error tap in real time.
  4. POST /api/orf/assessments/:id/stop: closes the 60-second window and triggers the CBM score computation + trend recompute.

The recompute is advisory-locked per (org, student, subSkillId) so concurrent requests from the same teacher session cannot corrupt the time-series.

Aim line and baseline

The aim line activates only after 3 probes have been recorded. The baseline is the median of the first 3 probes. This protects against a single atypical session distorting the reference point (GSR-05: no single-point decision).

Once active, the aim line is defined by:

  • baseline: median of the 3 baseline probes
  • goalScore: the target fluency score
  • goalSlope: (goalScore − baseline) / weeksToTarget

The 4-point trend rule and CbmTrendSignal

After 4 or more comparable probes exist, the engine evaluates the trend using the 4-point rule. The result is one of four signals:

SignalMeaning
trend_above_goalThe student’s trajectory is above the aim line
trend_below_goalThe student’s trajectory is below the aim line
trend_mixedProbes alternate above and below; inconclusive
insufficient_pointsFewer than 4 comparable probes; cannot yet apply the rule

null is returned while the baseline is still being collected (baselineState: collecting_baseline).

Grade-norm fail-safe

When no benchmark norm exists for a student’s grade (e.g., G1 or G4 where partner norms are pending), the probe still scores and the trend still computes on raw WCPM. The response carries:

  • riskLevel: null (shown as Not_Assessed, never as Below)
  • benchmarkMissingFlag: true

A missing norm is never treated as zero or as a risk indicator. No invented cut score is ever used.

Comparable and excluded probes

Not every probe is comparable. A probe is marked comparableFlag: false when it differs from the majority on one condition, for example, an unadapted probe in a session where the student normally receives adapted material. Excluded probes appear in the trend response’s window.excludedProbeIds list but are retained in the time series for full audit.

Emit-only design

The CBM module emits a raw cbm_alert carrying the trendSignal, alertSeverity, and the pinned benchmarkVersionUsed. It does not:

  • Apply the fidelity gate (owned by the RTI module)
  • Write a teacher-facing message
  • Change bundle_assignment.status

The RTI module reads readOpenAlerts() from this module and applies the gate + message. An acute regression (alertSeverity: acute_regression) is emitted as a signal and never auto-fails the plan.

The RTI input reader also reads the latest cbm_alert.trendSignal per student (org-scoped) and maps the 4-value CbmTrendSignal into its alert pipeline:

CbmTrendSignalRTI effect
trend_below_goalThe “not progressing against the aim line” signal; feeds Layer B’s Targeted-Support gateway, so it can raise a Student_Alert
insufficient_pointsA sentinel contributor (cbm_insufficient_points); a halt guard, never an alert
trend_above_goalNo effect (progressing)
trend_mixedNo effect; trend_mixed is the conservative “not conclusive” verdict and never maps to the flat signal, to avoid over-alerting

See RTI Decisions & Tiers for how that signal moves through the alert and tier-review flow.

Dismissing a CBM alert

POST /api/cbm/alerts/:id/dismiss requires a dismissalReasonCode from the 9-code OverrideCodeCatalog. An optional contextFlagId from the closed dictionary may be included. No free-text reason is ever accepted.

CAMELS tags

Each ORF passage is tagged with CAMELS Arabic feature tags (tagCode, arabicLabel). These tags track error patterns by Arabic linguistic category. The CamelsCardDTO in the trend response shows occurrence counts and error rates per tag. The full catalog is partner-owed; PHON_HAMZA is inactive in Wave 1 (hamza is out of the current phase per partner confirmation 2026-06-19).

API endpoints (10)

ORF:

MethodPathPurpose
POST/api/orf/assessments/startOpen a new ORF session
POST/api/orf/passages/:id/wordsLoad word list for error tapping
POST/api/orf/assessments/:id/markRecord a real-time error tap
POST/api/orf/assessments/:id/stopClose the 60-second window + compute score

CBM:

MethodPathPurpose
POST/api/cbm/probesSubmit a scored word-list or sentence/text accuracy probe
GET/api/cbm/trend/:studentId/:subSkillIdFull trend response (series + aim line + signal)
GET/api/cbm/alertsList CBM alerts (filterable by status)
POST/api/cbm/alerts/:id/dismissDismiss an alert with a reason code
GET/api/cbm/aim-linesList aim lines for a student
POST/api/cbm/modificationsRecord a modification marker (context flag + reason)

All routes are teacher-scored (require VIEW_OWN_CLASSES / ClassTeacher), tenant-scoped, and have no student-facing surface.

For full request/response shapes see the API Reference.

Last updated on