discovery-media-player 0.1.155 → 0.1.157
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/docs/HOST-CONTRACT.md +74 -0
- package/package.json +1 -1
- package/server/retention.js +8 -0
package/docs/HOST-CONTRACT.md
CHANGED
|
@@ -947,6 +947,20 @@ previous version claimed nothing. Four hours after the release, a host measured
|
|
|
947
947
|
deployment caps, times out, paginates, or rewrites anything between us and your database, that
|
|
948
948
|
limit is invisible from here and our arithmetic is probably wrong about it.
|
|
949
949
|
|
|
950
|
+
⚠️ **If you sweep your own reads for this, sort them by what the value BECOMES, not by how many rows
|
|
951
|
+
it holds.** This criterion is not ours: a host swept theirs, closed all of them, and reported that
|
|
952
|
+
the row count had been the wrong axis the whole time. The expensive ones were the **aggregations** —
|
|
953
|
+
a credit balance summed with a `reduce`, a read counter taken as `rows.length`, a visit tally
|
|
954
|
+
incremented per row. A truncated sum does not look truncated: **it is wrong *and* plausible**, which
|
|
955
|
+
is worse than the ceiling's usual symptom, a list that at least renders visibly stale. Their credit
|
|
956
|
+
ledger stood at 503 rows and grows on every AI call — the invoice would have gone wrong before the
|
|
957
|
+
table ever looked big enough to suspect.
|
|
958
|
+
|
|
959
|
+
So the useful question about one of your reads is not *"could this exceed 1000?"* but **"is this
|
|
960
|
+
value aggregated, or displayed?"** A displayed list degrades visibly. An aggregate degrades into a
|
|
961
|
+
number someone will believe. Truncation you have decided to keep is fine and cheap to make honest —
|
|
962
|
+
theirs kept one, bounded to 1000 and stated rather than assumed.
|
|
963
|
+
|
|
950
964
|
**2. Something this card asserts that you can check against your own database.** Not "does it look
|
|
951
965
|
right" — *does this number match what a query returns right now*. The purge card is the obvious one:
|
|
952
966
|
`vide: true` is what authorises dropping a column, so a wrong `true` is expensive and a wrong `0`
|
|
@@ -991,6 +1005,51 @@ measurement came from rather than only what it said.
|
|
|
991
1005
|
The two kinds want opposite things from us: a debt should be chased, a structural limit should be
|
|
992
1006
|
written down and stopped being asked about.
|
|
993
1007
|
|
|
1008
|
+
⚠️ **And there is a third kind, which we proposed as a false choice and a host corrected.** We asked
|
|
1009
|
+
another host to sort two backup figures — the PITR window, and the age of the oldest snapshot — into
|
|
1010
|
+
debt or structural limit. Their answer was neither, and the distinction is operational rather than
|
|
1011
|
+
pedantic:
|
|
1012
|
+
|
|
1013
|
+
- **Not measurable by a session.** Checked against two independent toolsets — a second host's and
|
|
1014
|
+
their own — neither the platform API nor the MCP tools expose either figure. The one tool with a
|
|
1015
|
+
near-enough name restores a *paused* project.
|
|
1016
|
+
- **Measurable by a human.** An authenticated dashboard session displays both.
|
|
1017
|
+
|
|
1018
|
+
So it is a debt whose payer is *necessarily a person*, and that is what makes it its own kind: it
|
|
1019
|
+
behaves like a structural limit toward every automated agent (chasing it changes nothing, no session
|
|
1020
|
+
will ever produce it), and like a debt toward the installation (someone can pay it, and until they
|
|
1021
|
+
do, the purge is not datable end to end). Their own phrasing, which we adopt: *"no session can
|
|
1022
|
+
render them; a human can, and until one has, the purge is not datable end to end."* They had raised
|
|
1023
|
+
it with theirs four times.
|
|
1024
|
+
|
|
1025
|
+
The practical consequence for us is a rule about **who we are asking**, which we had never written:
|
|
1026
|
+
a question a host cannot answer with the tools they run on is not answered by asking again. Either
|
|
1027
|
+
it reaches a person, or it should be recorded and dropped.
|
|
1028
|
+
|
|
1029
|
+
⚠️ **Where the substitution seam is, because a host asked and the answer was not written anywhere.**
|
|
1030
|
+
Their question came from their own defect: they had written a pagination helper after an incident,
|
|
1031
|
+
with its reason at the top, and it was called *nowhere*. The cause turned up only when they tried to
|
|
1032
|
+
use it — it called the **local binding** of their database client, while their benches replace the
|
|
1033
|
+
**export**, so adopting it broke the very bench that covered it. Their sentence is the part worth
|
|
1034
|
+
keeping: *"nobody writes «I don't use it because it breaks my doubles» — you give up in silence."*
|
|
1035
|
+
A non-substitutable helper produces no red, no complaint, no trace. It produces an absence of use,
|
|
1036
|
+
which nothing distinguishes from a need that never existed.
|
|
1037
|
+
|
|
1038
|
+
Asked of us, the answer has two halves and only one of them is a promise:
|
|
1039
|
+
|
|
1040
|
+
- **The injected context is substitutable, and that is the seam.** Every call reads `PLAYER.<member>`
|
|
1041
|
+
at the moment it fires; nothing captures it into a local binding at module load, before you have
|
|
1042
|
+
injected anything. Measured on 2026-09-05 across `server/` and `context/`: **144 calls, 0
|
|
1043
|
+
captures.** Your double of `db.request` is the one that runs. `tools/couture-substituable.mjs`
|
|
1044
|
+
now refuses a capture, so this stays true rather than happening to be true today.
|
|
1045
|
+
- **Our exports are not substitutable among themselves, and we do not promise they are.** Same date,
|
|
1046
|
+
same zones: **64 of 75 exported names are also called internally through their local binding.**
|
|
1047
|
+
If you stub `getShareBySlug` on the module we export and expect `overview()` to see your stub, it
|
|
1048
|
+
will not. That is ordinary CommonJS and we are not changing 64 call sites for it — but you would
|
|
1049
|
+
have discovered it the expensive way, so it is written here instead.
|
|
1050
|
+
|
|
1051
|
+
Bring us the seam you need and cannot get, rather than working around a missing one in silence.
|
|
1052
|
+
|
|
994
1053
|
**What not to send.** Shapes and counts, never contents. No row data, no reader IPs or User-Agents —
|
|
995
1054
|
those are the columns half this contract exists to get rid of — no keys, tokens, connection strings,
|
|
996
1055
|
or private hostnames. *"A table of ~1600 rows returned 1000"* is the whole of what we needed to fix
|
|
@@ -1006,3 +1065,18 @@ it exists, and the answer will name you.
|
|
|
1006
1065
|
Semantic versioning on the package, independent of the `contract` number. Pin an **exact** version:
|
|
1007
1066
|
the player and its hosts deploy separately, and a range brings in a version nobody decided to
|
|
1008
1067
|
deploy, on a day someone ran `npm install` for another reason.
|
|
1068
|
+
|
|
1069
|
+
⚠️ **And please keep that pin current — one train behind at most.** A host asked whether this
|
|
1070
|
+
mattered, having verified a release without moving onto it: the diff was comments only, no
|
|
1071
|
+
migration, and their argument was that what makes a verification useful is the verification, not the
|
|
1072
|
+
pin. That reasoning is sound, and the answer is still yes, for a reason that is ours rather than
|
|
1073
|
+
theirs: **a report we cannot reproduce is a report we cannot act on.** Every finding in this
|
|
1074
|
+
document arrived as "we measured X" — the ceiling, the platform timeout, the truncated aggregate.
|
|
1075
|
+
Each was worth something because we could stand the same version up beside it. When installations
|
|
1076
|
+
drift apart by several versions, a measurement stops being about the player and starts being about
|
|
1077
|
+
which player, and the first thing we spend on any report is establishing that.
|
|
1078
|
+
|
|
1079
|
+
It is a request, not a requirement: nothing here refuses to run on an older version, the contract
|
|
1080
|
+
number has not moved, and a release whose notes say it changes nothing for you genuinely changes
|
|
1081
|
+
nothing for you. But we are asking for the alignment explicitly rather than assuming it — which is
|
|
1082
|
+
the point of writing it down at all.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "discovery-media-player",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.157",
|
|
4
4
|
"description": "Self-hosted document viewer: per-recipient tracked links, reading analytics, live presentation. The core knows nothing about the application hosting it — everything it borrows arrives through an injected context.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pdf-viewer",
|
package/server/retention.js
CHANGED
|
@@ -29,6 +29,14 @@ const MIN_MOIS = 1, MAX_MOIS = 120;
|
|
|
29
29
|
// négative calculerait une borne FUTURE (perte massive), zéro purgerait tout, une chaîne/NaN/
|
|
30
30
|
// Infinity produirait une date invalide. On refuse AVANT le premier DELETE, en NOMMANT la clé.
|
|
31
31
|
// Zéro n'est PAS une purge immédiate : ce serait un geste trop dangereux pour un défaut de config.
|
|
32
|
+
//
|
|
33
|
+
// ⚠️ ET LE FRÈRE DE CETTE FONCTION FAIT DÉLIBÉRÉMENT L'INVERSE — c'est dit ici parce qu'il est à
|
|
34
|
+
// quatre cent cinquante lignes d'ici et qu'un lecteur n'arrive jamais aux deux. `delaiLecture()`
|
|
35
|
+
// RETOMBE sur son défaut au lieu de lever. La sévérité se règle sur la CONSÉQUENCE DE L'ERREUR, pas
|
|
36
|
+
// sur la nature du réglage : une fenêtre fausse supprime des lignes, un délai faux fait au pire
|
|
37
|
+
// attendre. Un hôte a prédit le défaut de ne l'écrire qu'à un seul bout — « sans la phrase, le
|
|
38
|
+
// prochain lecteur harmonisera, dans un sens ou dans l'autre, et croira corriger une incohérence ».
|
|
39
|
+
// Uniformiser les deux serait donc une régression, quel que soit le sens choisi.
|
|
32
40
|
function fenetresValidees() {
|
|
33
41
|
const brut = { ...FENETRES, ...((PLAYER.config && PLAYER.config.retention) || {}) };
|
|
34
42
|
const out = Object.create(null); // nu : la garde de forme reconnaît cet accumulateur
|