TASFA: Topology-Driven Asynchronous Stream Fabric Architecture
by
gg582 · 2026-05-24 00:48:17 · 49 views
TASFA
TASFA is the file-transfer protocol used in this tree for uploads and downloads.
It is built on top of plain HTTP/XHR and adds per-chunk encryption, a file-level sequential queue, and a server-authoritative 6-slot HTP (Hexagonal Tortoise Problem) recovery lattice for integrity control.
Routes
Upload:
POST /file/upload/initPOST /file/upload/statusPOST /file/upload/renegotiatePOST /file/uploadPOST /file/upload/completePOST /file/upload/cancel
Download:
GET /file/download/:id/handshakeGET /file/download/:id/chunk/:chunk_indexGET /file/download/:idGET /assets/tasfa/img/:filename/handshakeGET /assets/tasfa/img/:filename/chunk/:chunk_indexGET /assets/tasfa/uploads/:filename/handshakeGET /assets/tasfa/uploads/:filename/chunk/:chunk_index
Upload Protocol
The browser negotiates an upload session first, then sends chunks (default 16 MiB, mobile 8 MiB) with TASFA headers:
X-TASFA-Upload-IDX-TASFA-Upload-TokenX-TASFA-Chunk-IndexX-TASFA-Hash-TagX-TASFA-Raw-ScalarX-TASFA-Magic-Scalar
The server writes each chunk directly to the preallocated temp file at chunk_index * chunk_size. There are no transport blocks anymore.
If a normal chunk repeatedly fails, the browser sends that failed chunk through an AES-256-GCM fallback request with X-TASFA-Stream-Mode: aes-256-gcm. The server accepts the ciphertext plus the GCM authentication tag, and fallback chunks remain inside the adaptive parallel window. The fallback still carries the same HTP hash tag and balanced scalar headers.
Remainder (last partial chunk)
If the file size is not a multiple of the chunk size, the last chunk is a remainder. It is sent as a single blob with its exact byte range; the server writes it at the correct offset. No padding or splitting is performed.
Session init response
The init endpoint returns, among other fields:
chunk_size— negotiated chunk sizecurrent_parallel_chunks— the server-approved active upload windowmax_parallel_chunks— how many chunks the client may upload concurrentlydispatch_pacing_ms— a small pacing delay only when the measured link is poorupload_secret— a secondary server-secret for encrypted stream verificationstream_key_hex,stream_iv_seed_hex,stream_mode— session encryption keys (aes-256-gcm)modulus_M— the HTP modulus used for this sessiongroup_count— number of complete 6-slot HTP groupsclient_stripes— fixed value32, used by the client worker scheduler
The client treats chunk_size as a session contract because it defines each chunk's file offset. During an active upload it tunes concurrency and retry behavior, while the learned chunk-size hint is applied to the next TASFA session: good links multiply the next hint by 2, and degraded links halve it (/2).
Upload chunk response
When a chunk is accepted, the server responds with 204 No Content and headers:
X-TASFA-Accepted: 1X-TASFA-Chunk-Complete: 1
If the chunk index is already marked complete in state.bin and the index is not in the server's retry_targets, the server returns 204 with the same headers but the chunk body is discarded.
HTP Server-Authoritative Recovery Lattice
HTP is not a transport protocol and not a cryptographic proof. It is a server-side chunk-suspicion engine that ranks chunks by likelihood of corruption so the client only retransmits high-probability suspects instead of the whole file.
Chunk grouping
Chunks are grouped into consecutive 6-element vertices:
Group g: [ v0 , v1 , v2 , v3 , v4 , v5 ]
chunk g*6+0 ... g*6+5
The last group may be partial; incomplete groups are never padded and are excluded from HTP validation entirely. Zero-padding would inject synthetic topology and is forbidden.
Raw scalar
For every chunk the client computes the SHA-512 of the plaintext chunk, takes the first 8 bytes as a big-endian unsigned 64-bit integer H, and derives:
raw_scalar = H % modulus_M
Magic line invariant
For a complete group, define three lines:
L1 = v0 + v1 + v2 (mod M)
L2 = v2 + v3 + v4 (mod M)
L3 = v4 + v5 + v0 (mod M)
The invariant requires L1 == L2 == L3. If the raw scalars do not satisfy this, the client balances them by adjusting only v3 and v5:
delta2 = (L1 - L2) mod M
delta3 = (L1 - L3) mod M
v3_balanced = (v3_raw + delta2) mod M
v5_balanced = (v5_raw + delta3) mod M
All other vertices keep their raw scalar. The client sends both:
X-TASFA-Raw-Scalar— the unmodifiedraw_scalarX-TASFA-Magic-Scalar— the balanced value (v3_balancedorv5_balanced, otherwise same as raw)
The server stores both scalars separately in htp.bin so that analysis can reference the original topology independently of the artificial balancing constraints.
Why only v3 and v5?
The hexagonal lattice has two degrees of freedom. Fixing v0,v1,v2,v4 and adjusting v3,v5 uniquely satisfies the three line equations while keeping the delta minimal and local to the group.
Server-Authoritative HTP Recovery
The client is a dumb retransmission agent. It does not compute repair algebra, does not evaluate cost thresholds, and does not derive suspect rankings. All of that lives on the server.
Server validation flow
During POST /file/upload/complete the server:
- Loads all per-chunk records from
htp.bin(hash tag, raw scalar, and balanced scalar). - Validates only complete 6-slot groups (partial groups are skipped).
- If the scalar order inside a 6-slot group is permuted (out-of-order), the server searches all 720 permutations, finds one that restores the invariant, and reorders the
htp.binrecords accordingly without requiring retransmission. - For every failing group, computes suspicion scores per slot by analyzing which line equations each slot participates in.
Suspect confidence scoring (per group)
For a failing group the server evaluates each slot against the three line equations:
| Slot | Equations |
|---|---|
| v0 | L1, L3 |
| v1 | L1 |
| v2 | L1, L2 |
| v3 | L2 |
| v4 | L2, L3 |
| v5 | L3 |
The suspicion score for each slot is deterministic and derived only from topology:
score = in_fail / total_fail
where in_fail is the number of failing line equations the slot participates in, and total_fail is the total number of failing equations in that group. No arbitrary confidence constants are used.
If a slot only appears in passing equations, it is cleared from the suspect list.
Scores are aggregated across all failed groups; if a chunk appears in multiple groups, its maximum score is kept.
Repair cost threshold
Before requesting any repair, the server evaluates whether contraction is cheaper than direct retry:
repair_worthwhile(suspect_count, total_chunks, chunk_size, rtt_ms):
if suspect_count < 3 → false (too few for topology)
retry_cost = suspect_count * chunk_size * rtt_factor(rtt_ms)
repair_cost = metadata_bytes + server_cpu_cost + extra_rtt_cost
return retry_cost > repair_cost
The abstract cost model compares the bytes the client would retransmit against the server-side analysis overhead. Large chunks or high latency make contraction more attractive, while many small suspects make direct retry cheaper. Concrete numbers are server-side implementation details, not protocol constants.
If the threshold rejects repair, the server returns needs_retry with all suspect chunks as retry targets. The client retransmits them through the normal upload endpoint.
Server-side recursive contraction
If repair is worthwhile, the server performs group-level contraction: each original complete 6-slot group is collapsed to a single scalar encoding its invariant signature. The server computes the three line values L1, L2, L3 for the group, derives the residuals r12 = (L1-L2) mod M and r23 = (L2-L3) mod M, and sets the group aggregate to (r12 * r23) mod M. A passing group has r12 = r23 = 0, so its aggregate is 0; a failing group receives a non-zero deterministic signature that preserves the topology of the line inconsistencies. These group aggregates become the vertices of a higher-level HTP lattice. Consecutive groups of 6 such aggregates form level-1 super-groups, and the same line invariants are re-evaluated:
- If a level-1 super-group passes, suspects from its underlying level-0 groups are cleared (the failure pattern is consistent at the group level).
- If a level-1 super-group fails, suspects from its underlying level-0 groups are kept.
- If contraction narrows the suspect set (fewer chunks), the server stores the narrowed targets and returns
needs_retrywith the reduced list. - If contraction does not narrow the set, the server falls back to direct retry of the original suspects.
- Contraction level is incremented in session metadata so the client can report diagnostics.
The client never sees contraction groups or computes them. It only receives retry_targets.
Retransmission acceptance
When the client retransmits a chunk that is already marked received, the normal upload endpoint accepts the retransmission only if that chunk index is currently in the server's retry_targets list. After the retransmitted chunk is stored, the server removes it from retry_targets.
Protocol-visible repair response
When HTP fails and the server decides repair or retry is needed, the complete endpoint returns 409 with:
htp_status:"needs_retry"retry_targets: array of chunk indices to retransmit (ordered by suspicion score descending)suspicion_scores: array of{chunk_index, score}objectscontraction_level: how many server-side contraction passes have been appliedretry_reason: human-readable explanation (e.g."htp group inconsistency detected")
If the cost threshold says direct retry is cheaper, retry_targets contains the full suspect list and contraction_level stays at 0.
If the server successfully narrows suspects through contraction, retry_targets contains the narrowed list and contraction_level is incremented.
After all suspects are retransmitted and validated successfully, the next complete call proceeds to SHA-256 finalization.
File-Level Sequential Queue
Only one file is uploaded at a time. When multiple files are selected:
- Each file gets its own asset, preview card, and HTP session.
- Files are enqueued in
FileUploadQueue. - When the active file finishes (success or failure), the queue automatically advances to the next file.
- The batch "Upload queued files" button is always enabled; clicking it enqueues all pending files and starts the pump.
This prevents browser connection pool exhaustion and keeps stall detection reliable.
Runtime Settings
- upload chunk size:
16 MiBdesktop,8 MiBmobile - adaptive upload chunk-size hint:
8 MiBminimum, up to32 MiBdesktop /16 MiBmobile; success*2, failure/2 - download chunk size:
8 MiBdesktop,4 MiBmobile, up to32 MiBwhen the client hints a larger session - default browser upload parallelism:
16, success*1.15, failure*0.85 - max browser upload parallelism:
max_upload_parallel_chunksinblog.settings, capped at40 - max concurrent upload sessions:
max_total_parallel_uploadsinblog.settings, capped at64 - max upload size:
max_upload_sizeinblog.settings - max browser download sessions: server-defined, currently up to
48chunk requests per session - download coalesce (span group size): success
*1.2, failure*0.8, up to16chunks - upload xhr timeout: adaptive by chunk size, at least
180 s - upload session fetch timeout:
30 s
TASFA is tuned for general high-bandwidth server deployments, not an embedded/aerospace low-bandwidth profile. The browser's per-origin HTTP connection limit is still respected naturally by the worker pool.
Client adaptation
The upload client measures chunk completion time, retries, timeouts, and Network Information API hints when available. It sends those inputs to /file/upload/init and /file/upload/renegotiate; the server answers with a current parallel window and max window. Clean completions increase the active window by *1.15 up to the negotiated max, while transient failures reduce it by *0.85. AES-GCM fallback also runs inside the adaptive window.
A per-chunk absolute timeout prevents stalls caused by connections that receive partial data but never close. If a watchdog detects a stalled upload (no chunk completion within the timeout), the client performs an aggressive restart: targetParallel is reset to maxParallel, dispatchPacingMs is set to 0, and the upload resumes from the server bitmap. The learned chunk-size hint is kept session-local and is not immediately persisted to localStorage; it is only applied to the next TASFA session.
Download uses the same high-throughput bias: the handshake carries the client's preferred chunk-size hint, and active downloads grow span and parallelism by *1.2 after successful chunk groups. On failure both are reduced by *0.8. Short reads, timeouts, and network errors are requeued by chunk index; a failed group does not fail the whole download until the same chunk has exhausted a high retry budget.
For progressive video/audio playback, TASFA is stricter: the client assembles and feeds chunks sequentially, while a bounded scheduler keeps adaptive parallelism only inside a forward window from the next chunk the player needs. Failed or timed-out chunks record a retry time and release the network slot, so the scheduler can keep filling other eligible chunks in the same window. Playback can stall at the buffer edge, but it never skips a byte range, leaves a missing chunk unresolved, or closes the media stream early.
Tail RTT Prediction (Lagrange Extrapolation)
For large files (sessions with many chunks) the server accumulates per-chunk RTT samples reported by the client, up to a maximum of 8. Once 3 or more samples have been collected, a Lagrange polynomial extrapolation estimates the RTT at the last chunk index, and the remaining chunk count is multiplied to derive the estimated time left.
- Upload: after each chunk finishes, the client may attach an
X-TASFA-Chunk-RTTheader (milliseconds) to the next chunk request. - Download: the client may separately report the previous chunk's RTT via the
chunk_rtt_msquery parameter.
The server adds predicted_remaining_ms to the status response JSON, and the download chunk response carries an X-TASFA-Predicted-Remaining-Ms header. Math is intentionally kept light: sample cap of 8, simple O(n²) Lagrange, and predictions are clipped to a 30-second ceiling.
Wynn-Accelerated Predictive Guard
TASFA does not predict plaintext bytes or trust predicted chunk contents. Prediction is limited to the transfer-quality sequence observed by the client: completion time, throughput, retries, timeouts, and short reads. The client applies the Wynn epsilon transform in its Aitken Delta^2 form to the latest quality samples:
S_hat = S0 - ((S1 - S0)^2 / (S2 - 2*S1 + S0))
S_hat is clamped to [0, 1] and used only as a guard signal for the next chunk. High predicted quality keeps the normal path and lets the adaptive window grow. Medium-low predicted quality marks the next chunk as guarded, trimming the active parallel window by one before dispatch. Very low predicted quality marks the next upload chunk for parallel-capable AES-GCM fallback, or trims download span and parallelism before issuing the next range group. This is a forward-looking congestion and failure defense, not a cryptographic oracle.
Storage Model
Each upload session preallocates one temporary file:
- temp file:
data/tasfa/uploads/<upload_id>/upload.bin.part - metadata:
data/tasfa/uploads/<upload_id>/meta.json - fast binary meta:
data/tasfa/uploads/<upload_id>/meta.bin - state:
data/tasfa/uploads/<upload_id>/state.json,data/tasfa/uploads/<upload_id>/state.bin - HTP level-0:
data/tasfa/uploads/<upload_id>/htp.bin - session lock:
data/tasfa/uploads/<upload_id>/session.lock
The server no longer maintains blocks.bin or chunk_counts.bin. Chunk completion is a single bitmap write.
Session metadata also stores per-vertex arrays:
hash_tags— array of SHA-512 hex strings, one per chunkmagic_scalars— array of balanced scalars, one per chunkhtp_retry_targets— current server-issued retry target listhtp_suspicion_scores— current suspicion rankinghtp_contraction_level— number of server-side contraction passes applied
These are updated on every chunk upload and validated at completion.
Delete PIN
Completed uploads receive a one-time delete PIN. The clear PIN is a 12-character hex string (6 random bytes); it is returned once and only its hash is stored.
Download Protocol
- Client requests a handshake via
GET /.../handshake. - Server returns
session_id,session_token,chunk_size,chunk_count, concurrency hints, and session encryption keys (stream_key_hex,stream_iv_seed_hex). - Client fetches chunk groups with an adaptive
span=.... All chunks are encrypted with AES-256-GCM when session keys are present. - Client decrypts chunks in the browser using the Web Crypto API and the session keys.
- Browser assembles the response into one contiguous buffer.
DoS Mitigation via Bitmap
Both upload and download state are tracked with a dense binary bitmap (one byte per chunk, '0' / '1').
Upload side
- The server rejects any chunk whose index is already marked
'1'instate.bin, unless the chunk is explicitly in the server's retry target list. An attacker cannot replay arbitrary chunks to burn disk I/O. state.binis updated withpwrite(..., 1, chunk_index)— an O(1) atomic write. There is no JSON parsing on the hot path.- The
completehandler re-opens the bitmap, counts set bits, and refuses finalisation untilreceived_chunks == chunk_count. This prevents truncated-file attacks.
Session hardening
- Upload IDs and tokens are 16-byte / 24-byte random hex strings.
- Session locks (
flockonsession.lock) prevent racing bitmap updates from concurrent requests.
Worker Scheduler
The server uses a sticky round-robin worker scheduler. The number of workers equals the CPU count (minimum 2, maximum 64). Chunks belonging to the same upload_id are always dispatched to the same worker for cache locality and ordering. Jobs are submitted via a per-worker queue and signalled with condition variables.
Asynchronous Finalization
POST /file/upload/complete is processed asynchronously. The first call returns 202 Accepted with {"processing": true} and starts a background finalize worker. Subsequent calls poll the finalize cache; when the worker finishes, the cached status and body are returned immediately. This prevents long-running finalization work from blocking the HTTP connection.
Self-Review Checklist
| Question | Answer |
|---|---|
| Q1: Does the client compute any repair algebra? | No. The client is a dumb retransmission agent. All suspect derivation, confidence scoring, cost thresholds, and contraction logic are server-side only. |
| Q2: Is repair cost threshold explicitly evaluated before contraction? | Yes. htp_repair_worthwhile compares retry_cost_estimate (bytes × RTT) against repair_cost_estimate (server analysis overhead). It rejects repair when suspect_count < 3 or retry is cheaper, falling back to direct retry. |
| Q3: Are partial groups ever zero-padded? | No. Only complete 6-slot groups (chunk_count / 6) are validated. Incomplete final groups are excluded entirely. |
| Q4: Does the response contain suspicion scores, not just binary flags? | Yes. Every needs_retry response includes suspicion_scores as {chunk_index, score} objects. |
| Q5: Does contraction preserve original group topology? | Yes. htp_contract_groups treats each original complete group as a single higher-level vertex; suspects are never reshuffled across groups. |
| Q6: Are retry targets cleared on successful retransmission? | Yes. handler_file_upload removes the chunk from htp_retry_targets after accepting a retry retransmission. |
| Q7: Does the server repair out-of-order scalars by swapping? | Yes. htp_try_swap_repair brute-forces all 720 permutations of a 6-slot group; if any permutation restores the invariant, the htp.bin records are reordered immediately and the group passes without retransmission. |