discovery-media-player 0.1.156 → 0.1.158

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.
@@ -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,80 @@ 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
+
1053
+ ⚠️ **What every report must carry: the version you measured on.** One field, and it is the one we
1054
+ kept losing. `version` is already in the identity card — `GET /api/doc` serves it — so this costs
1055
+ you a copy-paste and nothing else: *"measured on 0.1.146"*, beside the shape and the count.
1056
+
1057
+ This is here because a host showed that we had asked for the wrong thing. We had asked hosts to stay
1058
+ current, reasoning that we cannot act on a report we cannot reproduce. Their correction: **what we
1059
+ need is not that you are up to date, it is knowing which version the measurement came from** — and a
1060
+ stamped report from a host eleven releases behind is reproducible, while an unstamped one from a
1061
+ perfectly current host is not. We then measured this document: of twelve host findings recorded in
1062
+ it, **none** names the version it was measured on. Some of those hosts were current at the time. The
1063
+ information was lost when we wrote it down, and no amount of future alignment brings it back.
1064
+
1065
+ So: **shape, count, version.** If the measurement spans an upgrade, say both. If you no longer know
1066
+ which version a past observation came from, say that too — *"measured some time before 0.1.150"* is
1067
+ worth more than a number we would have to guess at, and far more than silence.
1068
+
1069
+ ⚠️ **And name yourself inside the report, not just in how you send it.** Reports reach us through
1070
+ whatever channel carries them, and a channel can deliver the same message twice or put one host's
1071
+ text under another host's name — both happened to us in a single round, and we spent an exchange
1072
+ establishing who had said what instead of acting on it. Neither you nor we could tell from our own
1073
+ end; only the person relaying could, and they did. **One line of self-identification in the body
1074
+ costs nothing and survives any relay** — the same reasoning as the version stamp, applied to *who*
1075
+ rather than *what*.
1076
+
1077
+ The consequence for us is worth stating too, since it is about how much we can claim to have heard:
1078
+ when a duplicate is resolved, the reading it seemed to provide does not turn up elsewhere. It leaves
1079
+ us with one fewer host heard from, and we would rather record that plainly than let a channel look
1080
+ wider than it is.
1081
+
994
1082
  **What not to send.** Shapes and counts, never contents. No row data, no reader IPs or User-Agents —
995
1083
  those are the columns half this contract exists to get rid of — no keys, tokens, connection strings,
996
1084
  or private hostnames. *"A table of ~1600 rows returned 1000"* is the whole of what we needed to fix
@@ -1001,8 +1089,61 @@ dated entry naming the case. That last part is deliberate and a host asked for i
1001
1089
  justification rots, a dated incident does not. In six months someone will read a field and ask why
1002
1090
  it exists, and the answer will name you.
1003
1091
 
1092
+ ⚠️ **But that date is ours, and for a long time we mistook it for yours.** Every changelog section
1093
+ carries the day *we shipped the fix* — 155 out of 155, checked. None carries the version *you*
1094
+ measured on, and the two answer different questions: ours says when it was closed, yours says what
1095
+ the observation was of. We had that backwards long enough to ask hosts for the wrong thing, so it is
1096
+ worth stating plainly rather than quietly correcting: **the entries above this line are unstamped,
1097
+ and cannot be retro-stamped** — the versions they were measured on were never recorded and are not
1098
+ recoverable. Everything from here on carries the stamp you send.
1099
+
1004
1100
  ## Versioning
1005
1101
 
1006
1102
  Semantic versioning on the package, independent of the `contract` number. Pin an **exact** version:
1007
1103
  the player and its hosts deploy separately, and a range brings in a version nobody decided to
1008
1104
  deploy, on a day someone ran `npm install` for another reason.
1105
+
1106
+ ⚠️ **When we say a release "changes nothing for you", check it from *your* version — ours is not
1107
+ yours.** The zone table in every Release compares the new version to **the one immediately before
1108
+ it**. That is our convenience, not your situation: a host two or three releases back is looking at a
1109
+ different diff, and theirs is the one that decides. A host caught this by redoing it — we had
1110
+ compared `0.1.156 → 0.1.157`; they were jumping from `0.1.155`, ran their own comparison, and got a
1111
+ third file we had not mentioned. Same conclusion in the end (no migrations, zero lines of code in
1112
+ `server/` once comments are excluded), **but reached on their span rather than on our word.**
1113
+
1114
+ So take the reassurance as a starting point and not as a finding. The tarballs are public: `npm pack`
1115
+ both versions and `diff -rq` the two trees is a minute's work, and it is the only version of the
1116
+ question that is about your installation.
1117
+
1118
+ ⚠️ **We asked you to stay current. That was the wrong ask, and a host took it apart.** The previous
1119
+ version of this paragraph requested that hosts keep the pin no more than one release behind, on the
1120
+ grounds that *a report we cannot reproduce is a report we cannot act on.* The premise is right. The
1121
+ conclusion did not follow:
1122
+
1123
+ > You are asking that hosts be up to date; what you need is to know **which version a measurement
1124
+ > was taken on**. They are not the same thing, and the second is strictly cheaper.
1125
+
1126
+ They are exactly right, and the counter-example is decisive. A host eleven releases behind who
1127
+ writes *"measured on 0.1.146: the 1600-row table returned 1000"* has given us a reproducible report.
1128
+ A perfectly aligned host who writes *"it returns 1000"* has not — and we find out only on the day we
1129
+ try to replay it. **Alignment neither implies the stamp nor substitutes for it.**
1130
+
1131
+ ⚠️ **And it is measurable in this very document — which is how we know the drift was never the
1132
+ cause.** They counted twelve places where this contract reports a host's finding and found one
1133
+ carrying a version nearby. We re-measured rather than take it: of those twelve, **zero** carry the
1134
+ version the host measured on. The single dated line in this file stamps *our own* measurement of our
1135
+ own code, not anyone's report. Several of those findings came from hosts who were current at the
1136
+ time. **The information was lost in the writing, not in the deployment, and no future alignment
1137
+ restores it.**
1138
+
1139
+ ⚠️ **Worse: the ask had the shape of the bias we had just written against ourselves.** A request to
1140
+ stay aligned can only be honoured by hosts who answer us, and is invisible in hosts who have
1141
+ drifted — so the channel would have reported "hosts are aligned" because the aligned are the only
1142
+ ones we hear from. That is the instrumentation bias one level up, applied to cadence instead of
1143
+ yield. The host who named it also took the release anyway, which is why the correction is theirs and
1144
+ not a concession.
1145
+
1146
+ **So the ask is now the stamp, and it is above, in what a report must carry.** Staying current keeps
1147
+ a smaller and separate value — you get fixes sooner, and a release that changes nothing for you
1148
+ costs nothing to take — but it is no longer presented as what makes your reports usable. It never
1149
+ was.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "discovery-media-player",
3
- "version": "0.1.156",
3
+ "version": "0.1.158",
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",