Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .changeset/approval-service-logger-warn-required.md
Original file line numberDiff line numberDiff line change
@@ -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.

<!-- adr-0087: not-required (runtime-interface-only packages/plugins/plugin-approvals/src/approval-service.ts#ApprovalServiceOptions) the tightened type is a plain TypeScript logger interface -- no Zod projection, no metadata surface, and it is referenced by none -- so `objectstack migrate meta` has nothing to rewrite. Nothing is removed or renamed and no stored value moves; the only consumer action is adding a `warn` member at a construction site the compiler names. -->
2 changes: 1 addition & 1 deletion packages/plugins/plugin-approvals/src/approval-service.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -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
Expand Down
20 changes: 9 additions & 11 deletions scripts/optional-error-sink-contract.baseline.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -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",
Expand Down
Loading