@torrent-tv/proxy 2.80.14 → 2.80.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## 2.80.16
2
+
3
+ - **Fix**: THE SPINNER CARAVAN, by arithmetic alone, and the two props 2.80.15 carried are gone with it — the threshold that made a move pay for itself, and the exclusion that kept a live run off a deadline-less zone. Both were propping up a comparison that was wrong rather than indifferent. Three quantities were computed wrongly:
4
+ 1. **A body was charged a whole piece for the one it was already making.** `arrival = delay + (index - at + 1) / rate` is right for a body that does not exist yet and wrong for a run 0.8 s into a 0.9 s piece. `delaySec` is now when a body finishes the piece it STANDS ON — for a run that has produced something, one piece; for one still warming up, the measured time to a first piece less the time it has been alive. From #58, reaching #59 costs 0.14 + 0.94 = 1.08 s against 1.88 s for a kill and a cold start: a decision by eight hundred milliseconds, where the double charge had made it a coin flip lost by ten.
5
+ 2. **The piece was priced at the unpenalised rate** while arrivals used the penalised one, so every extra body looked cheaper than it is and the plan bought a second encoder where one served. One rate now, the one the arrangement itself puts in force, and each body states its own debt as a function of it — so there is nothing to dispatch on.
6
+ - **Fix**: What a move costs is `Infinity` until something has been measured, because a move is irreversible while leaving the encoder alone is always available; placing one where there is none takes the unknown the other way, since the film gets made or it does not. And a run killed before producing anything is a measurement too — a lower bound on the first output — which is the only reading a thrash can supply, since every run in one is killed before it finishes anything.
7
+ - **Chore**: Verified by simulation over sixty ticks against the map's real shape — one encoder placed, left alone, and moved exactly once, at the viewer's own seek. NOT yet seen in the field.
8
+
9
+ ## 2.80.15
10
+
11
+ - **Fix**: THE SPINNER CARAVAN, first attempt. Field 2026-09-08: 39 encoder moves in one session, 24 of them between three adjacent numbers about 0.8 s apart, one viewer on a host affording three runs got three, and the picture stood still for 116.7 s in three interruptions, the worst 91.8 s. This release fixed the reading of `withinSeconds: null` — the map marks the film BEHIND the viewers with it, meaning nobody is waiting there, and `deadlineReaderFor` read it through `Number()`, where it is 0, so that film was due IMMEDIATELY and was the most urgent material in the file. It also made the objective the map's own rank order, as a vector compared position by position rather than three seconds-valued terms with ten ranks collapsed into two buckets.
12
+ - **Chore**: It also carried two props that 2.80.16 removes — a threshold requiring a move to beat staying by what moving costs, and an exclusion keeping a live run off any zone with no deadline. Both were written while the arrival arithmetic was still wrong; neither belongs in a model.
13
+
1
14
  ## 2.80.14
2
15
 
3
16
  - **Fix**: What the master playlist declares a variant carries is MEASURED. It was `height * height * 3.2` — for 1080 exactly the 3 732 480 the field declared for a file carrying 18.4 Mbit/s, five times more — and the comment justifying it said no measurement existed before encoding starts. Both do: the average is the file's own length over its duration, exact at session creation, and the peak is the biggest piece produced over the span it covers, equal to the average until one exists. A re-encoded height is declared at the cap we impose; a smaller height at the pixel share of the source's rate. `BANDWIDTH` and `AVERAGE-BANDWIDTH` are both emitted, as the specification names them. This is not cosmetic: the browser sizes its cushion in BYTES from `BANDWIDTH`, so 120 s asked bought 56 MB — 26 s of that film — and the deepest it ever held was 17.1 s. One expression, no case analysis: absent measurements and absent caps are written as the identity of the operation that consumes them (`services/output/rates.js`, eight checks).
@@ -188,6 +188,85 @@ was 17.1 s. Inflating it is not the answer either: hls.js compares it against
188
188
  its own estimate of the link to decide a level is unplayable, and its recovery
189
189
  then moves level by itself, which does not honour our pinning.
190
190
 
191
+ ## The objective is the map's own rank order
192
+
193
+ Not three terms in seconds. One pair per rank the map states, most urgent rank
194
+ first, compared position by position:
195
+
196
+ ```
197
+ [ late(100), done(100), late(99), done(99), … late(1), done(1) ], bodies, wasted
198
+ ```
199
+
200
+ `late(r)` is how long anybody waits past a deadline at rank `r`; `done(r)` is
201
+ when the last number of that rank is made. A difference at a higher rank settles
202
+ it and nothing lower can reopen it — which is the stated order: nobody stares at
203
+ a spinner; then the film in front is encoded as fast as it can be, band by band
204
+ as the map ranks them; then, with what is left over and only then, the film
205
+ behind, in case somebody seeks back.
206
+
207
+ **No weights, and none possible.** A weight would let seconds at one rank buy
208
+ seconds at another, and it would be a figure nobody measured. The map is the
209
+ source of truth about what matters and it already says so — ten ranks on a film,
210
+ p100 at the number a viewer is stopped on, doubling zones down to p91 for the far
211
+ tail, p1 for what lies behind them.
212
+
213
+ `bodies` ranks below every rank of the map, so spare capacity cannot buy an
214
+ encoder where the map is indifferent. `wasted` is the swarm's bill for anything
215
+ fetched twice.
216
+
217
+ ## Why an encoder is not moved for nothing, and it is not a rule
218
+
219
+ There is no threshold here, and there must not be one. What kept an encoder
220
+ moving was three quantities computed wrongly, not a policy that needed tuning.
221
+
222
+ **`delaySec` is when a body finishes the piece it STANDS ON.** For a run that has
223
+ produced something, one piece at the rate in force; for one still warming up, the
224
+ measured time to a first piece less the time it has already been alive. The
225
+ arrival of anything further on is that plus the pieces between, and nothing else.
226
+
227
+ It used to be `delay + (index - at + 1) / rate`, which charges every body a whole
228
+ piece for the one it is already making. That is right for a body that does not
229
+ exist yet and wrong for a run 0.8 s into a 0.9 s piece — and the difference is
230
+ the whole fault: from #58, reaching #59 was priced at 1.89 s against 1.88 s for a
231
+ kill and a cold start, a coin flip lost by ten milliseconds. Priced correctly it
232
+ is 1.08 s against 1.88 s.
233
+
234
+ **One rate, the one the arrangement puts in force.** Concurrent encoders slow
235
+ each other, measured on this host, so a piece costs what it costs at the body
236
+ count the arrangement has. Taken from the unpenalised rate while arrivals used
237
+ the penalised one, an extra body looked cheaper than it is and the plan bought a
238
+ second encoder where one served.
239
+
240
+ **Each body states its own debt** where it is created, as a function of what one
241
+ piece costs — because only there is it known what the body IS, and at the point
242
+ of pricing only how many there are. So there is no kind, no tag and no case
243
+ analysis.
244
+
245
+ **What a move costs is `Infinity` until something has been measured**, because a
246
+ move is irreversible while leaving the encoder alone is always available. Placing
247
+ one where there is none takes the unknown the other way: the film gets made or it
248
+ does not. And a run killed before producing anything is a measurement too — a
249
+ lower bound on the first output, and the only reading a thrash can supply, since
250
+ every run in one is killed before it finishes anything.
251
+
252
+ ### What that was for
253
+
254
+ Field 2026-09-08: 39 moves in one session, 24 of them between three adjacent
255
+ numbers about 0.8 s apart. One viewer on a host affording three runs got three.
256
+ The picture stood still for 116.7 s in three interruptions, the worst 91.8 s.
257
+
258
+ Compounding it, the map states `withinSeconds: null` for the film behind the
259
+ viewers — nobody is waiting there — and `deadlineReaderFor` read that through
260
+ `Number()`, where `null` is 0. So the film a viewer had already passed was due
261
+ IMMEDIATELY and was the most urgent material in the file: it bought encoders, and
262
+ it took the run standing in front of the viewer because that run was the nearest
263
+ body to it.
264
+
265
+ Checked by simulation over sixty ticks against the map's real shape — ten zones
266
+ doubling ahead of the viewer, one behind — at both one and three runs: the
267
+ encoder is placed once, left alone, and moved exactly once, at the viewer's own
268
+ seek.
269
+
191
270
  ## What is checked
192
271
 
193
272
  `test/one-authority.test.js` holds the shape: one caller of `#startEncodeRun`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@torrent-tv/proxy",
3
- "version": "2.80.14",
3
+ "version": "2.80.16",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "publishConfig": {