scheduler: FF link out of a start-of-day 0-day milestone anchors on the previous working day, absorbing lag

Summary

Found by the independent CPM oracle (#3987 (closed)): an FF link out of a 0-day milestone held at the start of a working day anchors on the end of the previous working day instead of the milestone's own instant, so a weekend absorbs a later lag on the link after it. Both the Python and Rust engines agree with each other and disagree with the reference.

Repro

Calendar: Mon–Fri, project start Mon 2026-01-05.

M0(0d, held at project start, Mon 01-05)  -FF->  M1(0d)  -FS+1d->  T(1d)

Both engines put T on Mon 01-05. The reference — and the equivalent M0 -FS-> M1, which both engines also agree on — puts T on Tue 01-06.

Why this is wrong

The FF link should anchor M1 on M0's own raw instant (the start of Monday), the same point an FS link anchors on. Anchoring instead on the close of the previous working day (Friday) moves M1 a working day earlier than its FS equivalent, which then lets the weekend silently absorb the +1d lag on the link after it.

Where it is tracked today

Excluded from oracle generation, unfixed, by _known_divergent() in packages/scheduler/tests/test_cpm_oracle.py (~line 327):

(link.kind == "FF" and is_milestone[link.pred])

Acceptance criteria

  • Decide the correct behavior (reference's position, or amend the docs)
  • Fix packages/scheduler and packages/wasm-scheduler in lockstep
  • Remove this case from _known_divergent() and let the oracle generate it
  • Update _known_divergent()'s docstring and the CONTRIBUTING.md line
  • Once fixed, finish_meeting()'s zero-lag branch in reference_cpm.py becomes reachable from an FF-out-of-milestone case; drop the comment added in #3987 (closed) marking it unreachable until then