@massu/core 1.15.7 → 1.16.0

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
@@ -10,6 +10,69 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
10
10
  > redistributed under the **Apache License 2.0**. Full license + NOTICE:
11
11
  > `packages/core/assets/embedder/MODEL-LICENSE`.
12
12
 
13
+ ## [1.16.0] - 2026-07-14
14
+
15
+ ### Fixed — cloud sync had, in practice, NEVER succeeded for a real session
16
+
17
+ The client's request timeout was `2_000ms`, shipped with a comment asserting it was "well under
18
+ hook timeout while still tolerating typical latency." Nobody had ever timed the endpoint. Measured
19
+ against the live API (`scripts/measure-sync-latency.sh`, now committed so the number is re-derived
20
+ rather than believed):
21
+
22
+ | payload | mean | worst |
23
+ |---|---|---|
24
+ | empty (auth/bcrypt only) | ~900ms | 1191ms |
25
+ | 1 session + 50 observations | ~2090ms | **2168ms** |
26
+
27
+ An ordinary session payload **exceeded the timeout every time** — it was queued, retried, timed out
28
+ again, and after 10 retries **the data was discarded**. A timeout is indistinguishable from an idle
29
+ seat, so this went unnoticed for the product's entire life.
30
+
31
+ - Request timeout is now `8_000ms`, sized from the measurement (~4× the real figure).
32
+ - The whole sync runs under a `20_000ms` **deadline**, and every attempt is clamped to the time
33
+ actually remaining. Bounding only the per-request timeout left total time =
34
+ `retries × timeout + backoff`, which silently exceeds the hook budget the moment a knob is tuned.
35
+ The deadline is the structural guarantee.
36
+
37
+ ### Fixed — a learned rule could be destroyed before it was ever delivered
38
+
39
+ `drainTeamPromotions` / `drainTeamRevocations` / `drainRulePromotionEvents` **deleted a promoted
40
+ rule at the moment they READ it** into a sync payload. If the upload then failed, the payload went
41
+ to `pending_sync`, was retried, and was **discarded after 10 attempts**. `read == delete` is the
42
+ whole disease: *delivery failure* and *nothing to deliver* produced the same end state, and that
43
+ state was the quiet one.
44
+
45
+ **Delivery is now ACK-based** (`rule-delivery.ts`): `lease() → deliver → ack()` on a confirmed
46
+ server receipt, `nack()` on any failure. A rule leaves an outbound store on exactly ONE event — the
47
+ server confirmed it. A failed delivery **keeps every row**, counts the attempt, and raises a LOUD
48
+ stall alarm rather than a silent zero. The `pending_sync` give-up path now **rescues** learned rules
49
+ back into the durable store instead of destroying them.
50
+
51
+ An ack requires `SyncResult.transmitted` — set only after a real 2xx. `success` alone is not a
52
+ receipt: it is also `true` when cloud sync is *disabled*, i.e. nothing was sent.
53
+
54
+ ### Added
55
+
56
+ - **`rule_candidates` table.** Candidates previously existed only as loose JSON on disk, so the
57
+ product could not answer "has anything ever been promoted?" — and could not detect that the
58
+ answer was no. The lifecycle (`proposed → shown → promoted | dismissed`) is now queryable.
59
+ - **`massu rule approve` / `dismiss` / `review` / `delivery-status`.** `applyRuleCandidate()` — the
60
+ promotion chokepoint carrying the whole transaction, rollback, audit and team-publish machinery —
61
+ had **zero callers**. The protocol said "invoke `applyRuleCandidate(...)`"; no command existed
62
+ that could. The CR-57 hardened-promotion preview (two-operator review of *executable* rules) was
63
+ likewise unreachable. All are now wired to real entry points.
64
+ - `massu rule delivery-status` reads the `cloud_sync_giveup` telemetry — which until now was the
65
+ only analytics event Massu had ever recorded, and nothing read it.
66
+
67
+ ### Changed (internal API)
68
+
69
+ - Removed `drainTeamPromotions`, `drainTeamRevocations`, `drainRulePromotionEvents` from
70
+ `memory-db`. Deleted rather than deprecated: a destructive drain that still exists is a
71
+ destructive drain someone will call again. Use `leaseLearning` / `ackLearning` / `nackLearning`.
72
+ - The team-promotion enqueue now runs **inside** the promotion transaction. It previously sat
73
+ post-COMMIT in an empty `catch`, so a failed enqueue produced a rule committed locally, its
74
+ candidate file already deleted, no outbound row, no log line, and a cheerful `ok: true`.
75
+
13
76
  ## [1.15.7] - 2026-07-14
14
77
 
15
78
  ### Added — the verification laws now ship IN Massu, and reach every repo