diff --git a/.changeset/approval-service-logger-warn-required.md b/.changeset/approval-service-logger-warn-required.md new file mode 100644 index 0000000000..e5ebab9aaa --- /dev/null +++ b/.changeset/approval-service-logger-warn-required.md @@ -0,0 +1,36 @@ +--- +"@objectstack/plugin-approvals": minor +--- + +**BREAKING** (compile-time only): `ApprovalServiceOptions['logger']` now +declares a **non-optional** `warn`, so a durability report always has +somewhere to land (#9754, #10556). This is the thirteenth of the thirteen +mechanical repairs the card names — held out of #10691 to serialize against +PR #10547, which owned `approval-service.ts` while it was open; that fence +has since cleared. + +`minor`, not `major`: during the launch window this stack ships breaking +changes as `minor` — every publishable package versions in lockstep, so a +`major` would promote the whole release. `patch` would be wrong in the other +direction, because this *can* break a consumer's build. This is the same +reasoning #10691 used for the twelve sibling repairs; no exemption for a +types-only break was found there either, and none applies here. + +`error` stays optional — hosts legitimately inject reduced sinks, and +requiring `error` was measured and rejected as #9754 option C. What changes +is that its *absence* now has a declared, guaranteed destination. Call sites +keep the `logger?.warn?.(…)` spelling as the backstop for hosts the type +cannot reach, so **no runtime behaviour changes**: nothing that printed +before stops printing, and nothing silent starts printing. + +### Who has to change, and what to do + +Only a caller that constructs `ApprovalService` (or an `ApprovalServiceOptions` +value) with a `logger` object that has **no `warn` method** — for example +`{ error }` alone. Add a `warn` member; there is no rename, no removal, and no +stored value or metadata key to rewrite. The only non-test construction site +in this repo (`ApprovalsServicePlugin.start`, in this same package) passes the +kernel `ctx.logger`, whose `warn` is already required, so the in-repo cost is +zero. + + diff --git a/packages/plugins/plugin-approvals/src/approval-service.ts b/packages/plugins/plugin-approvals/src/approval-service.ts index f7c52f8910..20083b9a4a 100644 --- a/packages/plugins/plugin-approvals/src/approval-service.ts +++ b/packages/plugins/plugin-approvals/src/approval-service.ts @@ -536,7 +536,7 @@ function rowFromAction(row: any): ApprovalActionRow { export interface ApprovalServiceOptions { engine: ApprovalEngine; clock?: ApprovalClock; - logger?: { info?: (msg: any, ...rest: any[]) => void; warn?: (msg: any, ...rest: any[]) => void; error?: (msg: any, ...rest: any[]) => void; debug?: (msg: any, ...rest: any[]) => void }; + logger?: { info?: (msg: any, ...rest: any[]) => void; warn: (msg: any, ...rest: any[]) => void; error?: (msg: any, ...rest: any[]) => void; debug?: (msg: any, ...rest: any[]) => void }; /** * Optional automation surface used to resume a suspended flow run when a * decision finalises a request. Usually attached after construction via diff --git a/scripts/optional-error-sink-contract.baseline.json b/scripts/optional-error-sink-contract.baseline.json index 568bfc54f3..1a933af08d 100644 --- a/scripts/optional-error-sink-contract.baseline.json +++ b/scripts/optional-error-sink-contract.baseline.json @@ -21,19 +21,17 @@ " metadata-protocol, plugin-approvals/lifecycle-hooks, both plugin-audit sinks,", " both plugin-auth sinks, plugin-email/attachment-reclaim, plugin-reports,", " plugin-sharing, plugin-webhooks and service-knowledge.", - " = 3 — what is left, and NONE of the three is left for lack of effort:", - " one is a serialisation leftover whose reason has expired (approval-service.ts),", - " and two are DESIGN calls escalated to the maintainer rather than answered by a", - " dev to make this checker green (security-plugin.ts, settings-service.types.ts)." + " = 3 — what was left after #10556's first PR, and NONE of the three was left for lack", + " of effort: one was a serialisation leftover whose reason had expired", + " (approval-service.ts), and two are DESIGN calls escalated to the maintainer", + " rather than answered by a dev to make this checker green (security-plugin.ts,", + " settings-service.types.ts).", + " -1 — #10556's follow-up dispatch repaired the serialisation leftover once its", + " fence (PR #10547/#10739) cleared: `logger@ApprovalServiceOptions` dropped the", + " `?` from `warn`, mechanically identical to the twelve already paid down.", + " = 2 — both remaining rows are the escalated DESIGN calls; neither is a `?` deletion." ], "entries": [ - { - "file": "packages/plugins/plugin-approvals/src/approval-service.ts", - "sink": "logger@ApprovalServiceOptions", - "verdict": "optional-fallback", - "members": "{ info? warn? error? debug? }", - "note": "Approval-service options bag. Mechanically identical to the twelve repaired in #10556 — drop the `?` from `warn`. Held out of that PR to serialize against PR #10546, which owned this file while it was open. #10546 has since MERGED (2026-08-21), so the reason this row is still here has expired: it is a one-line repair awaiting a dispatch, not a design call and not an exemption." - }, { "file": "packages/plugins/plugin-security/src/security-plugin.ts", "sink": "logger@SecurityPlugin",