Skip to content

Fix EndOf cycle final_date off-by-one#70

Merged
rymiwe merged 2 commits intomainfrom
fix/end-of-off-by-one
Mar 20, 2026
Merged

Fix EndOf cycle final_date off-by-one#70
rymiwe merged 2 commits intomainfrom
fix/end-of-off-by-one

Conversation

@rymiwe
Copy link
Copy Markdown
Contributor

@rymiwe rymiwe commented Mar 17, 2026

Summary

Split from #69 per review feedback — this PR contains only the EndOf bugfix (QUAL-6189).

  • EndOf#final_date subtracted 1 period before adding period_count, causing V1E12M to expire at end of month 11 instead of month 12
  • Removed the - 1.send(period) offset so notation matches user expectations

Example — V1E12M from Dec 1, 2025:

  • Before: expires Nov 30, 2026 (11 months)
  • After: expires Dec 31, 2026 (12 months)

Governance confirmation

Verified against four JTAC-domain governing documents:

Document Section Relevant rule
AFMAN 10-3505V2 (Stan/Eval, 7 Nov 2023) 4.8 "A JTAC evaluation expires on the last day of the 17th month following the month during which the MSN evaluation was successfully completed (e.g., an evaluation completed on 22 Mar 2017 expires 31 Aug 2018)."
JTAC MOU 2024-01 (9 Aug 2024) 3.2.5.1 "the interval between evaluations cannot exceed 18-months"
AFMAN 10-3505V1 (Training, 7 Nov 2023) 4.6.1.3 CT tasks completed "during an established six-month period"; Table 4.2 caps some items at 12 months between Live or Dry
USSOCOM M 350-5 (6 Sep 2023) 3.2.3 Recurring qualification controls completed "during an established six-month period, unless noted"

The AFMAN 10-3505V2 §4.8 example is definitive: cycles expire on the last day of the expiration month. The old code's - 1.send(period) offset shortchanged every EndOf cycle by one period, producing results that contradict the governing publications.

Previously confirmed by AFMAN 10-3500V1 A2.3.3: "For tasks with a minimum frequency determined by months, currency on the task is maintained through the last day of the expiration month."

SOFJTAC migration note

If SOFJTAC is reactivated, JTAC EndOf cycles will compute differently under this fix. Per jdowd: JTACs described evaluations as "18 month cycle" but the old code gave them 17 months. If no one compensated by bumping the period count (e.g., using V1E19M to get 18 actual months), existing notations are now correct per AFMAN and no migration is needed. Worth verifying against JTAC seed data before reactivation.

Test plan

  • All 179 existing gem specs pass with updated expectations

Fixes QUAL-6189
Split from #69

@rymiwe rymiwe marked this pull request as ready for review March 20, 2026 06:07
@rymiwe rymiwe requested review from a team March 20, 2026 06:20
rymiwe added 2 commits March 20, 2026 10:42
EndOf#final_date subtracted 1 period before adding period_count,
causing V1E12M to expire at end of month 11 instead of month 12.
Remove the offset so the notation matches user expectations:
V1E12M from Dec 1 now correctly expires Dec 31 (not Nov 30).

Fixed: EndOf cycle expiration was 1 month early (QUAL-6189)
With the off-by-one fixed, "18th month" is literally correct.
"18th subsequent month" was ambiguous about whether it meant
"18 months after" or "the 18th month following the current one."

Also simplifies dormant_to_s from heredoc+squish to a plain string,
and renames subsequent_ordinal to ordinalized_period_count.
@rymiwe rymiwe force-pushed the fix/end-of-off-by-one branch from a2ff079 to aa62e29 Compare March 20, 2026 17:45
Copy link
Copy Markdown

@rbazinet rbazinet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@rymiwe rymiwe merged commit ffa43d5 into main Mar 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants