Escalation guidelines (lfx-v2-newsletter-service)
These detail the boundaries behind the escalation decision: the service's
critical parts, its shared surfaces, and what scale-with-importance means here. A
change escalates to needs-human if it has that character, wherever in the tree it
lives; one that merely sits near such an area without moving it does not. Match
the substance, not the neighborhood.
Three properties of the service shape the critical boundaries. It runs no
authorization of its own: the gateway (Heimdall, from this repo's chart) decides
who may call each route. Two routes are deliberately reachable without
authentication (a recipient's mail client has no session), each guarded by its own
server-verified token. And every cross-service call travels over NATS to contracts
owned by peer services.
Auth and the gateway
- Authentication. JWT verification in the HTTP middleware
(
internal/handler/), behind a toggle that can disable it, with the bearer
deliberately not forwarded downstream. Any change to how a request is
authenticated, to that toggle or its default, or that forwards the bearer.
- Authorization. The service checks no access itself; the chart's Heimdall
RuleSet maps each route to a viewer or writer relation. Changing that mapping,
adding a route without one, or adding or removing an in-service check. Merely
routing a
project_uid through a handler is not this.
- The unauthenticated surface. Two routes are reachable by anyone: the
open-tracking pixel (guarded by an opaque recipient hash) and one-click unsubscribe
(guarded by an HMAC-signed token). Both reach the database anonymously — the pixel
records an open, unsubscribe writes a project-scoped opt-out. Any change to either
guard or to what the endpoint does, or any new unauthenticated route or write.
Shared and cross-repo surfaces
A break here lands in a repo this PR cannot show you, so lean on the skills.
pkg/api. Imported by other repos; its JSON shapes mirror the Self Serve
interfaces, and the version / If-Match concurrency surface is part of it.
Changing shapes, casing, status codes, or concurrency semantics. Confirm
consumers with the lfx skill (skills/lfx/SKILL.md in linuxfoundation/lfx-skills).
- The schema (
internal/schema/). Encodes the invariants every deployed pod
assumes: the draft-to-sent state machine, sent-requires-a-group-id, token and
hash formats, cascade deletes, the idempotent lock-serialized apply.
- NATS contracts. Peers own the subjects this service calls (committee,
project, email, auth). Changing a request or reply shape from this side, or
adding a peer dependency. Resolve ownership with the
lfx skill (skills/lfx/SKILL.md in linuxfoundation/lfx-skills).
Sending behavior
Sending is the highest-blast-radius act, but only the behavior needs a human, not
the look. Presentation (rendered HTML and CSS, layout, copy, styling) is the
reviewer's domain and does not escalate, even though rendering happens in the
orchestrator. Send behavior does escalate: who the orchestrator resolves as
recipients, how sends fan out, dispatch order or idempotency, failure handling,
the integrity of the per-recipient group id, and first wiring
a send-adjacent capability the service lacks today. So does any path that logs,
returns, or stores a recipient email or name beyond what the service already
persists, weakens a hash, or changes how the database credentials are handled.
(Open tracking persists only an opaque recipient hash; the unsubscribe table
persists the lowercased email, project-scoped, so a change to how that email is
stored, exposed, or matched is in scope.)
Scale and visibility
Some changes need a human for their weight, not a single boundary: a large change
reworking or touching many key workflows at once, or a significant,
high-visibility piece of work a lead should know is landing, even when each part
looks sound. Judge scale with importance, not line count: big but low-risk work
(a mechanical refactor, a sweep of UI, a batch of tests or docs) does not
escalate; a big change moving auth, the send path, the schema, or several core
handlers at once does.
Pipeline and supply chain
Changes under .github/, to the chart (charts/, carrying the Heimdall RuleSet
and network policy), to CODEOWNERS or the build toolchain, or to the PR review
system's own config (the .github/skills/ review skills and the
.github/copilot-instructions.md routing) change how code reaches production or
gets reviewed. A new
dependency, or a version bump in the auth path or to a pinned LFX module this
service couples to, shifts the supply chain. Routine patch and minor bumps of
uninvolved dependencies do not.
1---2name: escalation-guidelines3description: Detailed boundaries behind the needs-human decision for lfx-v2-newsletter-service: the critical surfaces (auth, the unauthenticated surface, schema, send behavior), shared and cross-repo contracts, scale-with-importance, and pipeline/supply-chain. Load this whenever judging whether a newsletter-service PR needs a human, as the detail behind the `needs-human-escalation` skill.4---56<!-- Copyright The Linux Foundation and each contributor to LFX. -->7<!-- SPDX-License-Identifier: MIT -->89# Escalation guidelines (lfx-v2-newsletter-service)1011These detail the boundaries behind the escalation decision: the service's12critical parts, its shared surfaces, and what scale-with-importance means here. A13change escalates to needs-human if it has that character, wherever in the tree it14lives; one that merely sits near such an area without moving it does not. Match15the substance, not the neighborhood.1617Three properties of the service shape the critical boundaries. It runs no18authorization of its own: the gateway (Heimdall, from this repo's chart) decides19who may call each route. Two routes are deliberately reachable without20authentication (a recipient's mail client has no session), each guarded by its own21server-verified token. And every cross-service call travels over NATS to contracts22owned by peer services.2324## Auth and the gateway2526- **Authentication.** JWT verification in the HTTP middleware27 (`internal/handler/`), behind a toggle that can disable it, with the bearer28 deliberately not forwarded downstream. Any change to how a request is29 authenticated, to that toggle or its default, or that forwards the bearer.30- **Authorization.** The service checks no access itself; the chart's Heimdall31 RuleSet maps each route to a viewer or writer relation. Changing that mapping,32 adding a route without one, or adding or removing an in-service check. Merely33 routing a `project_uid` through a handler is not this.34- **The unauthenticated surface.** Two routes are reachable by anyone: the35 open-tracking pixel (guarded by an opaque recipient hash) and one-click unsubscribe36 (guarded by an HMAC-signed token). Both reach the database anonymously — the pixel37 records an open, unsubscribe writes a project-scoped opt-out. Any change to either38 guard or to what the endpoint does, or any new unauthenticated route or write.3940## Shared and cross-repo surfaces4142A break here lands in a repo this PR cannot show you, so lean on the skills.4344- **`pkg/api`.** Imported by other repos; its JSON shapes mirror the Self Serve45 interfaces, and the version / `If-Match` concurrency surface is part of it.46 Changing shapes, casing, status codes, or concurrency semantics. Confirm47 consumers with the `lfx` skill (`skills/lfx/SKILL.md` in `linuxfoundation/lfx-skills`).48- **The schema** (`internal/schema/`). Encodes the invariants every deployed pod49 assumes: the draft-to-sent state machine, sent-requires-a-group-id, token and50 hash formats, cascade deletes, the idempotent lock-serialized apply.51- **NATS contracts.** Peers own the subjects this service calls (committee,52 project, email, auth). Changing a request or reply shape from this side, or53 adding a peer dependency. Resolve ownership with the `lfx` skill (`skills/lfx/SKILL.md` in `linuxfoundation/lfx-skills`).5455## Sending behavior5657Sending is the highest-blast-radius act, but only the behavior needs a human, not58the look. Presentation (rendered HTML and CSS, layout, copy, styling) is the59reviewer's domain and does not escalate, even though rendering happens in the60orchestrator. Send behavior does escalate: who the orchestrator resolves as61recipients, how sends fan out, dispatch order or idempotency, failure handling,62the integrity of the per-recipient group id, and first wiring63a send-adjacent capability the service lacks today. So does any path that logs,64returns, or stores a recipient email or name beyond what the service already65persists, weakens a hash, or changes how the database credentials are handled.66(Open tracking persists only an opaque recipient hash; the unsubscribe table67persists the lowercased email, project-scoped, so a change to how that email is68stored, exposed, or matched is in scope.)6970## Scale and visibility7172Some changes need a human for their weight, not a single boundary: a large change73reworking or touching many key workflows at once, or a significant,74high-visibility piece of work a lead should know is landing, even when each part75looks sound. Judge scale with importance, not line count: big but low-risk work76(a mechanical refactor, a sweep of UI, a batch of tests or docs) does not77escalate; a big change moving auth, the send path, the schema, or several core78handlers at once does.7980## Pipeline and supply chain8182Changes under `.github/`, to the chart (`charts/`, carrying the Heimdall RuleSet83and network policy), to `CODEOWNERS` or the build toolchain, or to the PR review84system's own config (the `.github/skills/` review skills and the85`.github/copilot-instructions.md` routing) change how code reaches production or86gets reviewed. A new87dependency, or a version bump in the auth path or to a pinned LFX module this88service couples to, shifts the supply chain. Routine patch and minor bumps of89uninvolved dependencies do not.