Skip to content

fix(#380): Security (low): transfer scheduler is one global FIFO; one member can stall ever - #392

Merged
BeSovereign merged 1 commit into
mainfrom
fix/issue-380
Oct 19, 2026
Merged

BeSovereign merged 1 commit into
mainfrom
fix/issue-380

Conversation

@BeSovereign

@BeSovereign BeSovereign commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Refs #380

Likely CI cause (logs were not accessible): pump() broke same-millisecond created_at ties by the random job id, so a member's later job could start before an earlier one and the scheduling tests' order assumptions failed depending on host speed; ties now go by rowid (insertion order), pinned by a frozen-clock test with 10 jobs. Also added a test that a cleanup refused with JOB_LIMIT keeps its token (the early assertJobRoom guard), after the two sequential reviews; DECISIONS.md updated.

Driver gates (measured, not claimed)

  • Suites: typecheck: 1 passed, 0 failed | lint: 1 passed, 0 failed | unit: 1176 passed, 0 failed | e2e: 581 passed, 0 failed
  • Red/green check on declared tests: server/test/transfers.test.ts, server/test/migrations.test.ts
red/green output
RED without the change:
9�[39m
�[31m+ 201�[39m

�[36m �[2m❯�[22m test/transfers.test.ts:�[2m577:40�[22m�[39m
    �[90m575|�[39m     const over = await as(t, a, 'POST', '/api/v1/transfers', { mode: '…
    �[90m576|�[39m       items: [{ path: paths[MAX], onCollision: 'fail' }] });
    �[90m577|�[39m     expect(over.statusCode, over.body).toBe(409);
    �[90m   |�[39m                                        �[31m^�[39m
    �[90m578|�[39m     expect(over.json()).toMatchObject({ code: 'JOB_LIMIT', params: { m…
    �[90m579|�[39m     // Every kind of job counts and is held: a batch rename of one fil…

�[31m�[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/7]⎯�[22m�[39m

Error: ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL

  × "pnpm recursive exec" failed in /home/agent-user/Coding/Freeshard/
  │ vacation_framework/worktrees/files/issue-380/server



GREEN with the change:
again�[33m 312�[2mms�[22m�[39m
   �[32m✓�[39m transfer event streams per member �[2m(2)�[22m
     �[33m�[2m✓�[22m�[39m one stream more than the cap ends the member's oldest, on any device; the others and other members' stay open�[33m 317�[2mms�[22m�[39m
   �[32m✓�[39m transfer scheduling across members �[2m(4)�[22m
     �[33m�[2m✓�[22m�[39m two members with long queues take turns at the slots�[33m 315�[2mms�[22m�[39m
     �[33m�[2m✓�[22m�[39m another member's job completes before the first member's second job starts its first item�[33m 313�[2mms�[22m�[39m

�[2m Test Files �[22m �[1m�[32m2 passed�[39m�[22m�[90m (2)�[39m
�[2m      Tests �[22m �[1m�[32m34 passed�[39m�[22m�[90m (34)�[39m
�[2m   Start at �[22m 23:22:55
�[2m   Duration �[22m 4.00s�[2m (tests 86%, import 10%, transform 3%)�[22m


🤖 Generated with Claude Code

Likely CI cause (logs were not accessible): pump() broke same-millisecond created_at ties by the random job id, so a member's later job could start before an earlier one and the scheduling tests' order assumptions failed depending on host speed; ties now go by rowid (insertion order), pinned by a frozen-clock test with 10 jobs. Also added a test that a cleanup refused with JOB_LIMIT keeps its token (the early assertJobRoom guard), after the two sequential reviews; DECISIONS.md updated.

Refs #380

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@BeSovereign

Copy link
Copy Markdown
Contributor Author

Security review (claude-fable-5-1): no blocking finding. Cap is atomic inside the immediate insert transaction and keyed on the session user; cleanup pre-check precedes token burn with no await; scheduler alternates by job owner and cannot be spoofed; new SQL parameterised, rowid valid; tests fail without each check. Remaining: item count per job still unbounded via folder expansion (pre-existing), slot turns are per grant not per byte (accepted in DECISIONS).

@BeSovereign
BeSovereign merged commit 77a5b40 into main Oct 19, 2026
3 checks passed
@BeSovereign
BeSovereign deleted the fix/issue-380 branch October 19, 2026 22:07
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.

1 participant