Files
Trey T 90aea92fba Fix Full Table eligibility — accept ordinary verbs, reject orto
The eligibility filter required every form's regularity tag to equal
"regular", but the data uses four labels:
  - regular   (179 forms — curated paradigm verbs)
  - ordinary  (50,992 forms — pattern-following verbs like hablar, comer)
  - irregular (8,653)
  - orto      (176 — orthographic spelling changes like busqué)

Result was a 27-combo eligible pool, ~26 of which were -ir verbs in
present tense — every Full Table prompt landed on the same handful of
verbs.

Pulled the rule into a SharedModels function (FullTableEligibility) so
it's testable in isolation. Accepts "regular" + "ordinary" (both mean
"follows the pattern"); rejects "irregular" and "orto". 9 unit tests
cover the matrix including edge cases (incomplete forms, mixed labels,
unknown values).

PracticeSessionService.makePromptIfFullyRegular now delegates to
FullTableEligibility, sorting forms by personIndex so the regularity
array lines up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 11:26:34 -05:00

75 lines
2.6 KiB
Swift

import Testing
@testable import SharedModels
@Suite("FullTableEligibility")
struct FullTableEligibilityTests {
// MARK: - Should be eligible
@Test("all-ordinary verb (e.g. hablar present) is eligible")
func allOrdinary() {
// hablar present: hablo / hablas / habla / hablamos / habláis / hablan
let r = Array(repeating: "ordinary", count: 6)
#expect(FullTableEligibility.isFullyRegular(regularities: r))
}
@Test("all-regular paradigm verb (e.g. vivir present) is eligible")
func allRegular() {
// vivir present is tagged "regular" in the curated subset
let r = Array(repeating: "regular", count: 6)
#expect(FullTableEligibility.isFullyRegular(regularities: r))
}
@Test("mixed regular + ordinary across persons is eligible")
func mixedRegularOrdinary() {
// The data never actually mixes these, but it shouldn't matter if it
// did both labels mean "follows the regular pattern".
let r = ["regular", "ordinary", "regular", "ordinary", "regular", "ordinary"]
#expect(FullTableEligibility.isFullyRegular(regularities: r))
}
// MARK: - Should NOT be eligible
@Test("any irregular form rejects the combo")
func anyIrregular() {
var r = Array(repeating: "ordinary", count: 6)
r[3] = "irregular"
#expect(!FullTableEligibility.isFullyRegular(regularities: r))
}
@Test("orthographic spelling change rejects the combo (excluded by design)")
func anyOrto() {
// buscar preterite: yo "busqué" carries an orto tag for the cqu shift.
// Per design choice, orto verbs are NOT eligible for Full Table.
var r = Array(repeating: "ordinary", count: 6)
r[0] = "orto"
#expect(!FullTableEligibility.isFullyRegular(regularities: r))
}
@Test("all-irregular rejects")
func allIrregular() {
let r = Array(repeating: "irregular", count: 6)
#expect(!FullTableEligibility.isFullyRegular(regularities: r))
}
// MARK: - Edge cases
@Test("incomplete forms (fewer than 6 persons) are rejected")
func incompleteForms() {
let r = Array(repeating: "ordinary", count: 5)
#expect(!FullTableEligibility.isFullyRegular(regularities: r))
}
@Test("empty input is rejected")
func empty() {
#expect(!FullTableEligibility.isFullyRegular(regularities: []))
}
@Test("unknown regularity value is rejected (defensive default)")
func unknownValue() {
var r = Array(repeating: "ordinary", count: 6)
r[2] = "garbage_value"
#expect(!FullTableEligibility.isFullyRegular(regularities: r))
}
}