Measured, not asserted

Does obfuscation break academic standing and probation?

Academic standing is not a quantity. It is an outcome -- continue, warn, or dismiss -- and financial aid follows it. The two directions are not symmetric. A good student reported as dismissed is noticed within a day. A failing student reported in good standing keeps drawing aid for a year.

Three students, three separate reasons

The rules in the test are the ordinary ones: a cumulative grade point average must clear 2.0, a completion rate must clear sixty-seven per cent of attempted credits, and probation may not run more than two terms. The three students were built to fail on at most one axis each, so that no result could be confounded by another.

The first has a 3.41 average and has earned everything attempted: good standing, aid eligible. The second has a 1.42 average with a healthy seventy-five per cent completion rate and has already sat two terms on probation: dismissed. The third has a passing 2.60 average but has earned only forty-two of ninety-six attempted credits -- forty-four per cent, well under the sixty-seven per cent that federal aid requires: probation, aid suspended.

Every protected run at every preset reproduced all three. The engine changed nothing about any of them.

What renaming the completion-rate floor did

Renaming ^(minCompletionRate)$ left the installed engine reading its own default of zero. The third student came back GOOD-STANDING with aid=ELIGIBLE.

The line is worth reading closely, because it does something an earlier measurement recommended and it still was not enough. It prints the value the guard consumed: pace-read=44% earned=42 of 96, and then an empty list of reasons, and then good standing. Printing the value a guard read rather than only its conclusion is a genuine improvement -- it distinguishes a guard reading nothing from a guard reading zero -- but here the value was read correctly and compared against a floor that had become zero. Forty-four per cent clears a floor of nothing.

A student completing under half of what they attempt keeps their aid, and the record shows the completion rate on the same line as the decision. There is no missing field to notice and no exception to catch.

Both floors reverted, and both reverted the same way

Renaming ^(probationGpaFloor|minCompletionRate)$ put all three students in good standing with aid eligible, including the 1.42-average student due for dismissal.

Both defaults are permissive, and that is not a coincidence to be explained away. An option key never becomes unreadable the way a record field does; the library simply substitutes its own value, present, finite and plausible. And a library that cannot know an institution's academic policy has only one reasonable default for a floor, which is not to impose one. The direction a lost threshold fails is decided by where the vendor's default points, not by how the comparison is phrased -- an earlier measurement made exactly this mistake, predicting two floors would fail in opposite directions and finding both failed open.

The practical consequence is that both of these results are quiet. Nobody complains about being told they are in good standing.

The other direction, and why it is the cheap failure

The record field carrying the average behaves differently from the option carrying its floor. Renaming ^(cumulativeGpa)$ made the value genuinely unreadable, and the caller's rule caught it cold: all three students refused with record-check(gpa read as undefined -- unreadable). Nothing was recorded.

Put the enabling flag in the pattern -- ^(cumulativeGpa|requireStandingCheck)$ -- and the rule is never consulted. Every comparison against an unreadable value is false, so the floor test fails, and because a floor's true outcome is the restrictive branch, all three students were put on probation or dismissed. That includes the 3.41 student, whose line reads gpa undefined below floor 2.00.

This is the expensive-looking failure and the cheap one to live with. A registrar's office hears about it the same morning. Set it beside the permissive arms above: the same transformation, on names one field apart, produces either a flood of complaints or a silently ineligible student who keeps their funding. Losing the value fails closed and loud; losing the policy that interprets it fails open and silent.

A ceiling whose true branch refuses

One arm sits between the two. Renaming ^(termsOnProbation)$ made the count of prior probation terms unreadable, and the dismissal test -- has probation run for more terms than allowed -- was skipped, because a comparison against an unreadable value is false. The second student came back PROBATION rather than DISMISSED.

The direction is decided by which branch the comparison's true outcome guards. Here the true outcome dismisses, so skipping it is permissive. The damage is limited only because aid was already suspended by the average, which is another way of saying this student was protected by a second, unrelated control rather than by anything about this one.

Renaming ^(maxProbationTerms)$, the option rather than the field, produced the same outcome by the other route: the library's default is no limit, so probation continues indefinitely.

What this means if you protect a student information system

Protection alone was clean, as it was in all five areas of this pass. Twenty-five base comparisons across five presets, every protected standing identical to the unprotected one. Every result above needed member renaming aimed at names the installed engine also reads.

For the code, the half of the standard advice that always helps is the finiteness check -- require a number to be finite before comparing it, and treat non-finite as a refusal. It costs one line and it catches the unreadable-record arms regardless of obfuscation, because a bad configuration file produces the same value. What it cannot do is protect a threshold that was replaced by a permissive vendor default, since that value is finite and plausible. For that, assert the thresholds themselves: read them back and refuse to evaluate anybody if the floor is not the floor your policy published.

For the build, the boundary is the thing to protect. Keep member renaming off the keys an installed library reads and off the field names on records you hand across, and do not treat a second flag on the same object as a second layer of defence.

Frequently asked questions

Did obfuscation change any standing decision on its own?

No. Five areas at five presets gave twenty-five comparisons with no differences, and all three students were evaluated correctly in every protected run. Each failure below required member renaming aimed at a name the installed engine also reads.

What put a failing student in good standing?

Renaming the completion-rate floor. The installed engine substituted its own default of zero, so a student who had earned forty-two of ninety-six attempted credits cleared it. The output printed pace-read=44% on the same line as GOOD-STANDING and aid=ELIGIBLE.

Did printing the value the guard read help?

It was not enough here. The completion rate was read correctly and printed; the floor it was compared against had become zero. Printing a consumed value distinguishes a guard reading nothing from one reading zero, which is worth having, but it cannot detect a threshold that was replaced.

Why did both thresholds fail in the permissive direction?

Because both vendor defaults are permissive, and that is the only reasonable choice for a library that cannot know an institution's academic policy. An option key never becomes unreadable; the library substitutes a value that is present, finite and plausible.

Was anything caught?

Yes. Renaming the cumulative average itself made the value genuinely unreadable and the caller's rule refused all three students with a named reason. Losing a value fails closed and loud; losing the policy that interprets it fails open and silent.

What happens when the flag in front of that rule goes too?

The rule is never consulted, every comparison against the unreadable value is false, and because a floor's true outcome is the restrictive branch all three students were put on probation or dismissed -- including the 3.41-average student. Loud, wrong, and noticed the same morning.

What should an academic standing engine assert?

Two things. Require every number to be finite before comparing it, and treat non-finite as a refusal. Then read the thresholds back and refuse to evaluate anybody unless the floors match the policy your institution published, since a reverted threshold is finite and plausible.

Related reading