Registered before the next job: under our reading, FDLoRA's personalized module is always something the server has received¶
A second review of PR #36 ran the script against a fake model stack and found that the saved
-local module is never a withheld tensor. This follows from the reading registered on
2026-09-21, not from the code.
Why. Under reading 2, the pseudocode's, the personalized module trains only in Stage 1
(Algorithm 1, lines 1 to 6). Stage 2 trains the global module (line 12), and on a sync round line
14 sets the personalized module to the client's own locally optimized global, theta_s(i)(t),
which is the upload that round: line 17 averages its difference from the dispatched global.
After Stage 1, then, a client's personalized module is one of two things:
- its Stage 1 module, which reading 1 already counts as transmitted at initialization (line 7);
- its upload from the most recent sync round.
What that means for each schedule.
H <= T:-localis the upload of the last sync round. At the defaultROUNDS=6 SYNC_PERIOD=5it is the round-5 upload.H > T, including the paper'sH = 10andH = infinityatT = 6: no sync fires and-localequals-p0.HdividingT, includingH = T, which the paper tests:-localequals the final upload, the case the final-sync refusal already excludes.
The 2026-09-23 entry's reason for SYNC_PERIOD=5 is corrected here. Reading the withheld half "one
round after its last sync" keeps it from equalling the final upload. It does not keep it from being
an upload.
Consequence, registered before any job. Read by its pseudocode, FDLoRA's split withholds no
parameters, and "remains uninvolved in the federated learning process" holds for no schedule. The
script records what -local equals in its output (local_equals), and an attack that reads
-local is reported as reading a past transmission. The 2026-09-21 prediction is restated: H
changes how many rounds old that copy is when the run ends, not whether it was sent.
The prose reading, where the inner loop trains the personalized module, would make it a withheld tensor between syncs. It was rejected on 2026-09-21 because the outer step would then receive a zero update. This finding rests on that choice, and the report says so.
Implementation choices the registration did not state, disclosed here before any run:
Kis read as epochs. The paper callsKinner "steps" (Section 3.4) and "the local update epochs K = 3" (Section 4.2).- Stage 1 trains for the same two epochs as every other adapter here (
TRAINING). - Each round restarts AdamW and its warmup and cosine schedule under the same seed, so a client sees its data in the same order every round.
Also fixed, found by the same review.
- The script read client corpora without the loader, so it would have trained on v1 client corpora
(which still hold Qt's bot comments) without noticing. It now reads through
derived_file_rowslike every other training script and recordslegacy_corpus.scripts/preflight_pilot.pyhad the same gap. A test now requires every script that builds training items to read throughsphragis.corpus.load. - The schedule's refusals (
validate_schedule), the round-0 average over every client (round0_seed) and what-localequals (local_provenance) are pure, tested functions insphragis/experiment/fdlora.py. A reintroduced per-source average now fails the suite, and a badKorTis refused before Stage 1 writes anything. - Two source specs that map to one client label are refused; before, the second silently replaced the first and the round-0 average lost a client.
fdlora_schedule.sbatchtags results with the packing seed, so two draws no longer collide, and onlyALLOW_FINAL_SYNC=1enables the override.