91 lines
2.8 KiB
Markdown
91 lines
2.8 KiB
Markdown
# Strong Grading Implementation Notes
|
|
|
|
## Safety rule
|
|
|
|
This patch is additive and backward-compatible. Existing historical semester scores remain displayed from stored `semester_scores` values and are labeled as legacy by metadata. The new strong-grading machinery is present, but strong-mode finalization only activates when `strong_grading_enabled` is enabled through configuration.
|
|
|
|
## What changed
|
|
|
|
### Legacy display protection
|
|
|
|
`semester_scores` now supports:
|
|
|
|
- `calculation_mode`
|
|
- `calculation_policy_version`
|
|
- `snapshot_id`
|
|
|
|
Existing rows are backfilled as:
|
|
|
|
- `calculation_mode = legacy`
|
|
- `calculation_policy_version = legacy_v1`
|
|
|
|
No historical score is recalculated by this migration.
|
|
|
|
### Score safety columns
|
|
|
|
The score tables now support:
|
|
|
|
- `max_points`
|
|
- `status`
|
|
- `excused_reason`
|
|
- `locked_at`
|
|
- `locked_by`
|
|
|
|
Existing numeric score rows are marked `scored`. Existing blank rows are marked `pending`, not `missing`, so old data is not punished by the new policy.
|
|
|
|
### Validation
|
|
|
|
A central `ScoreValueValidator` rejects impossible scores before storage. The default max remains `100` to preserve old behavior until item-level max points are configured.
|
|
|
|
### Attendance grace
|
|
|
|
Attendance now names the one-absence grace policy explicitly instead of hiding it in `(total_days + 1 - absences) / total_days`. The result is intentionally equivalent.
|
|
|
|
### Strong-mode lock validation
|
|
|
|
`GradingLockService` now checks the policy mode before locking. In legacy mode, behavior remains compatible. In strong mode, pending scores and invalid score ranges block locking.
|
|
|
|
### Snapshot infrastructure
|
|
|
|
`semester_score_snapshots` and `SemesterScoreSnapshotService` were added. Strong-mode finalized scores can store calculation inputs and outputs for auditability.
|
|
|
|
### Display resolver
|
|
|
|
`GradeCalculationDisplayResolver` resolves whether a row should be shown as `Legacy Calculation` or `Strong Calculation`.
|
|
|
|
## Configuration gates
|
|
|
|
Strong mode is off by default.
|
|
|
|
Suggested configuration values:
|
|
|
|
```text
|
|
strong_grading_enabled = false
|
|
strong_grading_class_sections = *
|
|
```
|
|
|
|
When enabled:
|
|
|
|
```text
|
|
strong_grading_enabled = true
|
|
strong_grading_class_sections = 12,15,20
|
|
```
|
|
|
|
or all sections:
|
|
|
|
```text
|
|
strong_grading_class_sections = *
|
|
```
|
|
|
|
## What is intentionally not done yet
|
|
|
|
This patch does not globally replace the legacy PTAP formula. That would change grade math. The legacy formula remains the default until strong grading is intentionally activated for a class section.
|
|
|
|
This patch does not silently recalculate historical records. That would be reckless, so naturally we avoided it.
|
|
|
|
## Verification
|
|
|
|
PHP syntax checks passed for the modified and new PHP files.
|
|
|
|
PHPUnit could not run in this sandbox because the PHP runtime is missing required extensions: `dom`, `mbstring`, `xml`, and `xmlwriter`.
|