@massu/core 1.15.7 → 1.16.1

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,100 @@ 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.1] - 2026-07-14
14
+
15
+ ### Security
16
+
17
+ - **License-response signing key rotated (SEC-1).** The Ed25519 key that signs `/validate-key`
18
+ responses was rotated after a live private key was found committed in a tracked runbook (SEC-1,
19
+ `docs/reports/2026-07-14-codebase-audit-findings.md`). Production now signs with the new key and
20
+ stamps the new fingerprint `18c04567…`; the bundled client pubkey (`license-pubkey.generated.ts`)
21
+ is regenerated to trust the new key as primary while keeping the old key in the allowlist for the
22
+ transition grace window. A live signature smoke confirmed a real `/validate-key` success is signed
23
+ by the new key and verifies. The drift-guard `no-committed-private-keys.test.ts` forbids
24
+ re-introduction of any private key.
25
+
26
+ ### Fixed
27
+
28
+ - **The 2026-07-14 codebase-audit closure is now actually delivered.** The audit-closure fixes were
29
+ committed (`4f4c688`) but never published — `1.16.0` on npm predates all of them. `1.16.1` ships:
30
+ fail-closed engine startup on a fatal DB/ABI error (SF-1), Pro-tier gating of the `/v1` capability
31
+ endpoints (SEC-2), the two wired-but-previously-dead CLI subcommands `massu rule show` /
32
+ `massu rule effectiveness` (DF-1/DF-2), the documented-but-missing webhook-test route (BND-1), and
33
+ the cloud-sync "server-error-as-empty" fix (BND-3).
34
+
35
+ ### Added
36
+
37
+ - **CR-64 release-integrity gate — a published version number is immutable.** A pre-push + CI gate
38
+ (`scripts/release-integrity-check.mjs`) fails the moment `packages/core`'s version equals an
39
+ already-published npm version whose `vX.Y.Z` tag is missing or not at HEAD. This closes the class
40
+ where `1.16.0` was published without a git tag or release ceremony and then reused for six more
41
+ commits that read as "SHIPPED" while never delivered to customers. Incident:
42
+ `docs/incidents/2026-07-14-npm-publish-decoupled-from-release-ceremony.md`.
43
+
44
+ ## [1.16.0] - 2026-07-14
45
+
46
+ ### Fixed — cloud sync had, in practice, NEVER succeeded for a real session
47
+
48
+ The client's request timeout was `2_000ms`, shipped with a comment asserting it was "well under
49
+ hook timeout while still tolerating typical latency." Nobody had ever timed the endpoint. Measured
50
+ against the live API (`scripts/measure-sync-latency.sh`, now committed so the number is re-derived
51
+ rather than believed):
52
+
53
+ | payload | mean | worst |
54
+ |---|---|---|
55
+ | empty (auth/bcrypt only) | ~900ms | 1191ms |
56
+ | 1 session + 50 observations | ~2090ms | **2168ms** |
57
+
58
+ An ordinary session payload **exceeded the timeout every time** — it was queued, retried, timed out
59
+ again, and after 10 retries **the data was discarded**. A timeout is indistinguishable from an idle
60
+ seat, so this went unnoticed for the product's entire life.
61
+
62
+ - Request timeout is now `8_000ms`, sized from the measurement (~4× the real figure).
63
+ - The whole sync runs under a `20_000ms` **deadline**, and every attempt is clamped to the time
64
+ actually remaining. Bounding only the per-request timeout left total time =
65
+ `retries × timeout + backoff`, which silently exceeds the hook budget the moment a knob is tuned.
66
+ The deadline is the structural guarantee.
67
+
68
+ ### Fixed — a learned rule could be destroyed before it was ever delivered
69
+
70
+ `drainTeamPromotions` / `drainTeamRevocations` / `drainRulePromotionEvents` **deleted a promoted
71
+ rule at the moment they READ it** into a sync payload. If the upload then failed, the payload went
72
+ to `pending_sync`, was retried, and was **discarded after 10 attempts**. `read == delete` is the
73
+ whole disease: *delivery failure* and *nothing to deliver* produced the same end state, and that
74
+ state was the quiet one.
75
+
76
+ **Delivery is now ACK-based** (`rule-delivery.ts`): `lease() → deliver → ack()` on a confirmed
77
+ server receipt, `nack()` on any failure. A rule leaves an outbound store on exactly ONE event — the
78
+ server confirmed it. A failed delivery **keeps every row**, counts the attempt, and raises a LOUD
79
+ stall alarm rather than a silent zero. The `pending_sync` give-up path now **rescues** learned rules
80
+ back into the durable store instead of destroying them.
81
+
82
+ An ack requires `SyncResult.transmitted` — set only after a real 2xx. `success` alone is not a
83
+ receipt: it is also `true` when cloud sync is *disabled*, i.e. nothing was sent.
84
+
85
+ ### Added
86
+
87
+ - **`rule_candidates` table.** Candidates previously existed only as loose JSON on disk, so the
88
+ product could not answer "has anything ever been promoted?" — and could not detect that the
89
+ answer was no. The lifecycle (`proposed → shown → promoted | dismissed`) is now queryable.
90
+ - **`massu rule approve` / `dismiss` / `review` / `delivery-status`.** `applyRuleCandidate()` — the
91
+ promotion chokepoint carrying the whole transaction, rollback, audit and team-publish machinery —
92
+ had **zero callers**. The protocol said "invoke `applyRuleCandidate(...)`"; no command existed
93
+ that could. The CR-57 hardened-promotion preview (two-operator review of *executable* rules) was
94
+ likewise unreachable. All are now wired to real entry points.
95
+ - `massu rule delivery-status` reads the `cloud_sync_giveup` telemetry — which until now was the
96
+ only analytics event Massu had ever recorded, and nothing read it.
97
+
98
+ ### Changed (internal API)
99
+
100
+ - Removed `drainTeamPromotions`, `drainTeamRevocations`, `drainRulePromotionEvents` from
101
+ `memory-db`. Deleted rather than deprecated: a destructive drain that still exists is a
102
+ destructive drain someone will call again. Use `leaseLearning` / `ackLearning` / `nackLearning`.
103
+ - The team-promotion enqueue now runs **inside** the promotion transaction. It previously sat
104
+ post-COMMIT in an empty `catch`, so a failed enqueue produced a rule committed locally, its
105
+ candidate file already deleted, no outbound row, no log line, and a cheerful `ok: true`.
106
+
13
107
  ## [1.15.7] - 2026-07-14
14
108
 
15
109
  ### Added — the verification laws now ship IN Massu, and reach every repo