rcf-lite 0.17.0 → 0.18.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 +22 -0
- package/blueprints/application-api-rest/README.md +5 -1
- package/blueprints/application-api-rest/blueprint.json +1 -1
- package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-006.json +4 -4
- package/blueprints/application-api-rest/contributions/tacs/tac-306-application-api-rest-operability.json +9 -8
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2103.json +3 -3
- package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2108.json +27 -27
- package/blueprints/application-api-rest/docs/topics.md +2 -2
- package/blueprints/application-api-rest/guide/application-api-rest.md +5 -1
- package/blueprints/application-spa/docs/topics.md +2 -2
- package/blueprints/delivery-ci-workflows/docs/topics.md +2 -2
- package/blueprints/deploy-cloudflare-workers/docs/topics.md +2 -2
- package/blueprints/email-smtp-resend/docs/topics.md +2 -2
- package/blueprints/observability-essentials/README.md +6 -2
- package/blueprints/observability-essentials/blueprint.json +133 -33
- package/blueprints/observability-essentials/contributions/adrs/adr-801-observability-essentials-health-probes.json +4 -4
- package/blueprints/observability-essentials/contributions/adrs/adr-802-observability-essentials-readiness-semantics.json +4 -4
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-001.json +4 -4
- package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-002.json +4 -4
- package/blueprints/observability-essentials/contributions/tacs/tac-801-observability-essentials-liveness-probe.json +10 -9
- package/blueprints/observability-essentials/contributions/tacs/tac-802-observability-essentials-readiness-probe.json +17 -11
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7101.json +12 -3
- package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7102.json +12 -3
- package/blueprints/observability-essentials/docs/topics.md +15 -8
- package/blueprints/observability-essentials/guide/observability-essentials.md +9 -3
- package/blueprints/observability-probe-endpoints/README.md +5 -1
- package/blueprints/observability-probe-endpoints/blueprint.json +116 -24
- package/blueprints/observability-probe-endpoints/contributions/adrs/adr-1503-observability-probe-endpoints-kubernetes-default.json +5 -5
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14102.json +11 -2
- package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14107.json +11 -2
- package/blueprints/observability-probe-endpoints/docs/topics.md +6 -6
- package/blueprints/observability-probe-endpoints/guide/observability-probe-endpoints.md +10 -0
- package/blueprints/persistence-data-d1/docs/topics.md +2 -2
- package/blueprints/persistence-data-sqlite/docs/topics.md +2 -2
- package/blueprints/security-auth-clerk/docs/topics.md +2 -2
- package/blueprints/security-auth-keycloak/docs/topics.md +2 -2
- package/blueprints/security-auth-magic-link/docs/topics.md +2 -2
- package/blueprints/security-auth-oauth2/docs/topics.md +2 -2
- package/blueprints/security-secrets-management/docs/topics.md +2 -2
- package/fixtures/canary-manifest.json +6 -6
- package/package.json +1 -1
- package/rcf/code-nodes/cn-074.json +19 -0
- package/rcf/code-nodes/cn-075.json +15 -0
- package/rcf/code-nodes/cn-076.json +14 -0
- package/rcf/fbs/fbs-024.json +24 -0
- package/rcf/fbs/fbs-025.json +25 -0
- package/rcf/fbs/fbs-026.json +27 -0
- package/rcf/fbs/fbs-027.json +25 -0
- package/rcf/requirements/req-012.json +22 -0
- package/rcf/test-suites/ts-034.json +32 -0
- package/rcf/test-suites/ts-035.json +23 -0
- package/rcf/test-suites/ts-036.json +65 -0
- package/rcf/test-suites/ts-037.json +55 -0
- package/rcf/user-stories/us-1201.json +34 -0
- package/rcf/user-stories/us-1202.json +25 -0
- package/rcf/user-stories/us-1203.json +43 -0
- package/rcf/user-stories/us-1204.json +25 -0
- package/releases/releases.yaml +11 -1
- package/src/blueprint/index.js +1 -0
- package/src/blueprint/remove-resolution.js +104 -0
- package/src/cli/blueprint.js +41 -0
- package/src/cli/doctor.js +76 -1
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"adrId": "ADR-801-observability-essentials-health-probes",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
4
|
"tadId": "TAD-001",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "2.0.0",
|
|
6
6
|
"status": "accepted",
|
|
7
|
-
"title": "
|
|
7
|
+
"title": "Historical: two HTTP health probes on the request-traffic listener with a stable JSON body shape (self-supervised design intent, superseded by observability-probe-endpoints as the shelf canonical path owner from v2.0.0)",
|
|
8
8
|
"context": "Every deployed application runs under an orchestrator that needs a restart signal and under a load balancer that needs a routing signal. The two signals answer different questions: 'is this process wedged, restart it' versus 'is this process able to serve, route around it if not'. A single probe folded across both questions produces the outage-amplifying failure mode where a downstream dependency blip triggers a restart storm that dwarfs the original blip. The probes have to be structurally separate at the endpoint and semantically separate at the answer.",
|
|
9
9
|
"decision": "The application serves two probe endpoints on the same HTTP listener that serves request traffic: a liveness probe at /healthz (or the configured override) and a readiness probe at /readyz (or the configured override). Both respond with Content-Type application/json and a stable body shape: { status: 'pass' | 'fail', checkedAt: <ISO-8601> } for liveness, plus a { checks: { <depName>: { state, checkedAt } } } object for readiness. Liveness returns 200 whenever the event loop is responsive and never depends on any external condition; readiness returns 200 when every declared dependency's cached state is pass and 503 otherwise. Both endpoints are auth-exempt (see ADR-804). The probes bind to the request-traffic listener rather than a separate operator port so the load balancer's probe observes the same reachability the traffic will observe.",
|
|
10
|
-
"consequences": "The orchestrator's restart action is coupled only to true process wedging: a downstream dependency outage never triggers a restart. The load balancer's rotation action is coupled to declared-dependency health only: an unready replica gets pulled from rotation without a restart the replica cannot recover from. The stable JSON shape lets third-party monitoring integrations wire once. A change to the probe path defaults or a rename of a top-level probe body field is a major version bump on this blueprint. Composing blueprints that hold a different opinion on the endpoint contract (a project that wants /health as a single endpoint answering both questions, a project that wants gRPC probes, a project that wants both probes on a separate admin port) conflict on the healthProbes topic; the expected resolution is one project-level ADR that fixes the endpoint contract.",
|
|
10
|
+
"consequences": "The orchestrator's restart action is coupled only to true process wedging: a downstream dependency outage never triggers a restart. The load balancer's rotation action is coupled to declared-dependency health only: an unready replica gets pulled from rotation without a restart the replica cannot recover from. The stable JSON shape lets third-party monitoring integrations wire once. A change to the probe path defaults or a rename of a top-level probe body field is a major version bump on this blueprint. Composing blueprints that hold a different opinion on the endpoint contract (a project that wants /health as a single endpoint answering both questions, a project that wants gRPC probes, a project that wants both probes on a separate admin port) conflict on the healthProbes topic; the expected resolution is one project-level ADR that fixes the endpoint contract. From essentials v2.0.0 this ADR is scope-local historical context: the shelf-wide healthProbes topic is claimed only by observability-probe-endpoints. The self-supervised body shape and the request-traffic-listener binding remain the intent for the essentials-alone case; the literal /healthz and /readyz path defaults were removed from TAC-801 and TAC-802 in the same bump.",
|
|
11
11
|
"alternativesConsidered": [
|
|
12
12
|
{
|
|
13
13
|
"name": "Single /health endpoint answering both liveness and readiness with one status code",
|
|
@@ -26,5 +26,5 @@
|
|
|
26
26
|
}
|
|
27
27
|
],
|
|
28
28
|
"createdAt": "2026-08-24T00:00:00Z",
|
|
29
|
-
"updatedAt": "2026-
|
|
29
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
30
30
|
}
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"adrId": "ADR-802-observability-essentials-readiness-semantics",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
4
|
"tadId": "TAD-001",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "2.0.0",
|
|
6
6
|
"status": "accepted",
|
|
7
|
-
"title": "
|
|
7
|
+
"title": "Historical: readiness fails on any declared dependency failure (strict-any-fail over an explicit boot-time-declared dependency set), self-supervised design intent superseded by observability-probe-endpoints as the shelf canonical readiness-semantics owner from v2.0.0",
|
|
8
8
|
"context": "Readiness aggregates the health of dependencies the process needs to serve traffic. The two questions the semantics have to answer are (1) which dependencies count and (2) what aggregation rule turns per-dependency states into the ready/not-ready answer. Answered implicitly, the first collapses to 'every dependency ever touched by the process' which produces false-negative readiness (pulling replicas out of rotation because a rarely-used dep is offline) and false-positive readiness (a critical dep the developer never registered). Answered wrongly, the second (e.g. quorum, majority) produces surprising behaviour under partial outage.",
|
|
9
9
|
"decision": "The readiness dependency set is an explicit boot-time declaration in application configuration, refused if malformed. Every declared dependency contributes to the aggregate readiness answer under a strict-any-fail rule: readiness is pass when every declared dependency's cached state is pass; readiness is fail when at least one declared dependency's cached state is fail. Dependencies not declared in the set do not appear in the probe response, do not contribute to readiness, and get surfaced through the status page or through the notification outcome record (or through project-authored authenticated dashboards) but never through the readiness probe. The evaluation is against per-dependency cached state maintained by a background evaluator on its own cadence (see ADR-801 and TAC-802); no synchronous downstream network call is made from the probe handler.",
|
|
10
|
-
"consequences": "The operator's contract with readiness is the declaration set and the strict-any-fail rule: one glance at the declaration answers 'what could make this replica unready'. False-negative readiness (a rarely-used dep failing) is prevented by keeping the declaration narrow: a dep whose failure does not mean 'do not send me traffic' does not belong in the readiness set. False-positive readiness (missing a critical dep) is prevented by boot-time refusal on a malformed declaration and by review discipline on the declaration itself. Composing blueprints that hold a different opinion on readiness semantics (a quorum-based aggregation, a write-path-only readiness, a graceful-degradation model where some dep failures mean serve-partial rather than not-ready) conflict on the readinessSemantics topic; the expected resolution is one project-level ADR that fixes the aggregation and the declaration scope for the project.",
|
|
10
|
+
"consequences": "The operator's contract with readiness is the declaration set and the strict-any-fail rule: one glance at the declaration answers 'what could make this replica unready'. False-negative readiness (a rarely-used dep failing) is prevented by keeping the declaration narrow: a dep whose failure does not mean 'do not send me traffic' does not belong in the readiness set. False-positive readiness (missing a critical dep) is prevented by boot-time refusal on a malformed declaration and by review discipline on the declaration itself. Composing blueprints that hold a different opinion on readiness semantics (a quorum-based aggregation, a write-path-only readiness, a graceful-degradation model where some dep failures mean serve-partial rather than not-ready) conflict on the readinessSemantics topic; the expected resolution is one project-level ADR that fixes the aggregation and the declaration scope for the project. From essentials v2.0.0 this ADR is scope-local historical context: the shelf-wide readinessSemantics topic is claimed only by observability-probe-endpoints. The strict-any-fail rule remains the essentials-alone default readiness predicate, expressed on the readiness predicate boundary rather than as a shelf-wide global commitment.",
|
|
11
11
|
"alternativesConsidered": [
|
|
12
12
|
{
|
|
13
13
|
"name": "Implicit readiness dependency set (every registered client or connection pool)",
|
|
@@ -26,5 +26,5 @@
|
|
|
26
26
|
}
|
|
27
27
|
],
|
|
28
28
|
"createdAt": "2026-08-24T00:00:00Z",
|
|
29
|
-
"updatedAt": "2026-
|
|
29
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
30
30
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"reqId": "observability-essentials-REQ-001",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
|
-
"title": "The application exposes a liveness probe endpoint
|
|
5
|
-
"description": "The application serves a liveness probe at a
|
|
4
|
+
"title": "The application exposes a liveness probe endpoint at a configured HTTP path",
|
|
5
|
+
"description": "The application serves a liveness probe endpoint at a project-supplied HTTP path. A 2xx response means the process is running its event loop and is not wedged; a 5xx response means the process is stuck and the orchestrator should restart it. The endpoint answer never depends on any external dependency: a database outage, a broker outage or a partner API outage never turns liveness red on its own. The endpoint runs entirely inside the process boundary. The liveness path is supplied by project configuration under probeInterface.paths.liveness; when observability-probe-endpoints is composed on the same project the resolved profile liveness path binds automatically (Kubernetes profile default /live). Essentials-alone projects supply the one config line at boot and the blueprint refuses boot with a stable-coded error when it is missing.",
|
|
6
6
|
"category": "functional",
|
|
7
7
|
"domain": "observability",
|
|
8
8
|
"priority": "must",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"blueprint:observability-essentials",
|
|
12
12
|
"category:01-liveness-probe"
|
|
13
13
|
],
|
|
14
|
-
"version": "
|
|
14
|
+
"version": "2.0.0",
|
|
15
15
|
"status": "approved",
|
|
16
16
|
"createdAt": "2026-08-24T00:00:00Z",
|
|
17
|
-
"updatedAt": "2026-
|
|
17
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
18
18
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"reqId": "observability-essentials-REQ-002",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
|
-
"title": "The application exposes a readiness probe endpoint
|
|
5
|
-
"description": "The application serves a readiness probe at a
|
|
4
|
+
"title": "The application exposes a readiness probe endpoint at a configured HTTP path",
|
|
5
|
+
"description": "The application serves a readiness probe endpoint at a project-supplied HTTP path distinct from the liveness path. A 2xx response means the process is ready to accept request traffic; a 5xx response means the orchestrator should stop routing traffic to this replica while the process itself remains up. The readiness answer aggregates the health of the specific dependencies the process needs to serve requests correctly, evaluated through non-blocking cached checks that never hang the endpoint on a slow dep. The readiness path is supplied by project configuration under probeInterface.paths.readiness; when observability-probe-endpoints is composed on the same project the resolved profile readiness path binds automatically (Kubernetes profile default /ready). Essentials-alone projects supply the one config line at boot and the blueprint refuses boot with a stable-coded error when it is missing.",
|
|
6
6
|
"category": "functional",
|
|
7
7
|
"domain": "observability",
|
|
8
8
|
"priority": "must",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"blueprint:observability-essentials",
|
|
12
12
|
"category:02-readiness-probe"
|
|
13
13
|
],
|
|
14
|
-
"version": "
|
|
14
|
+
"version": "2.0.0",
|
|
15
15
|
"status": "approved",
|
|
16
16
|
"createdAt": "2026-08-24T00:00:00Z",
|
|
17
|
-
"updatedAt": "2026-
|
|
17
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
18
18
|
}
|
|
@@ -2,31 +2,32 @@
|
|
|
2
2
|
"tacId": "TAC-801-observability-essentials-liveness-probe",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
4
|
"tadId": "TAD-001",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "2.0.0",
|
|
6
6
|
"status": "approved",
|
|
7
7
|
"name": "Liveness probe",
|
|
8
8
|
"purpose": "Owns the in-process HTTP handler that answers the liveness endpoint. The handler is coupled to nothing outside the process boundary: no downstream dependency, no I/O, no cache; its answer reflects strictly whether the event loop is responsive. The handler is the one place the liveness contract lives, and its registration on the HTTP router is the one place the liveness path binds.",
|
|
9
9
|
"responsibilities": [
|
|
10
|
-
"Register a GET handler on the
|
|
11
|
-
"Return 200 with Content-Type application/json and a body of shape { status:
|
|
12
|
-
"Perform zero network egress from inside the handler; the handler
|
|
13
|
-
"Answer independently of the readiness dependency state: the handler holds no reference to the readiness dependency registry and no readiness state changes affect the liveness answer (AC-7101-3)."
|
|
10
|
+
"Register a GET handler on the CONFIGURED liveness path (project-supplied under probeInterface.paths.liveness, with no shipped default in essentials) at the application HTTP router, no earlier than the router is initialised and no later than the first request bind (AC-7101-1, AC-7108-2).",
|
|
11
|
+
"Return 200 with Content-Type application/json and a body of shape { status: pass, checkedAt: <ISO-8601> } whenever the handler is invoked while the process event loop is responsive (AC-7101-1, AC-7107-1).",
|
|
12
|
+
"Perform zero network egress from inside the handler; the handler only work is filling in the response body and writing it to the response stream (AC-7101-2, AC-7110-3).",
|
|
13
|
+
"Answer independently of the readiness dependency state: the handler holds no reference to the readiness dependency registry and no readiness state changes affect the liveness answer (AC-7101-3).",
|
|
14
|
+
"Refuse boot with a stable-coded error PROBE_INTERFACE_PATHS_MISSING when probeInterface.paths.liveness is absent AND observability-probe-endpoints is not composed on the same project; when probe-endpoints is composed, the resolved profile liveness path binds automatically and the essentials-side wiring is a no-op (no dual handler registration on the same path)."
|
|
14
15
|
],
|
|
15
16
|
"internalStructure": "One handler module that exports a factory: createLivenessHandler({ path, now }) -> { path, handler }. The factory closes over the configured path and a now() function (default () -> new Date()); handler is an async function (req, res) that writes the JSON body and returns. The registrar module wires the handler into the HTTP router at boot; the auth-exempt list registration is co-located with the router wiring so a single review reads both facts.",
|
|
16
17
|
"interfaces": [
|
|
17
18
|
{
|
|
18
19
|
"name": "createLivenessHandler",
|
|
19
20
|
"kind": "factory",
|
|
20
|
-
"description": "createLivenessHandler({ path, now }) -> { path, handler }. Returns the configured probe path and a stateless async handler for it. Called once at boot; the returned handler is bound at the HTTP router."
|
|
21
|
+
"description": "createLivenessHandler({ path, now }) -> { path, handler }. Returns the configured probe path and a stateless async handler for it. Called once at boot; the returned handler is bound at the HTTP router. `path` is a REQUIRED configuration input with no shipped default; when it is missing the caller refuses boot with PROBE_INTERFACE_PATHS_MISSING."
|
|
21
22
|
},
|
|
22
23
|
{
|
|
23
24
|
"name": "livenessPath",
|
|
24
25
|
"kind": "config",
|
|
25
|
-
"description": "Configured liveness HTTP path
|
|
26
|
+
"description": "Configured liveness HTTP path supplied by the project under probeInterface.paths.liveness. There is no shipped default in essentials v2.0.0. When observability-probe-endpoints is composed, the resolved profile liveness path substitutes for this configuration entry automatically; essentials-alone projects supply it explicitly at boot."
|
|
26
27
|
}
|
|
27
28
|
],
|
|
28
29
|
"dependencies": [],
|
|
29
|
-
"tradeoffs": "The handler owns its answer entirely on in-process state; that means it cannot report on any external condition, which is precisely the point.
|
|
30
|
+
"tradeoffs": "The handler owns its answer entirely on in-process state; that means it cannot report on any external condition, which is precisely the point. Path binding is now the operator or the composed observability-probe-endpoints blueprint decision, not an essentials default: the v2.0.0 breaking change is exactly this shift. A project that wants a smarter liveness answer wires the extra logic as an additional heartbeat that faults the event loop when the class the project cares about occurs, rather than folding it into the handler.",
|
|
30
31
|
"createdAt": "2026-08-24T00:00:00Z",
|
|
31
|
-
"updatedAt": "2026-
|
|
32
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
32
33
|
}
|
|
@@ -2,23 +2,24 @@
|
|
|
2
2
|
"tacId": "TAC-802-observability-essentials-readiness-probe",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
4
|
"tadId": "TAD-001",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "2.0.0",
|
|
6
6
|
"status": "approved",
|
|
7
7
|
"name": "Readiness probe",
|
|
8
8
|
"purpose": "Owns the HTTP handler for the readiness endpoint and the background dep-health evaluator that feeds it. The handler answers from a per-dependency cache the evaluator maintains on its own cadence; the handler itself never blocks on a synchronous downstream call. The dependency registry is the operator's contract with the probe's answer.",
|
|
9
9
|
"responsibilities": [
|
|
10
|
-
"Register a GET handler on the
|
|
11
|
-
"Read from a per-dependency last-known state cache populated by the background evaluator; return 200 with status pass when every declared dependency
|
|
12
|
-
"Complete the handler evaluation within the readiness evaluation budget (default 1 second) regardless of any dependency
|
|
13
|
-
"Run the background dep-health evaluator on its declared cadence, evaluating every declared dependency at least once per interval independently of any other dependency
|
|
14
|
-
"Refuse boot with a stable error
|
|
10
|
+
"Register a GET handler on the CONFIGURED readiness path (project-supplied under probeInterface.paths.readiness, with no shipped default in essentials) at the application HTTP router, on the same listener that serves request traffic (AC-7102-1, AC-7102-2, AC-7108-2).",
|
|
11
|
+
"Read from a per-dependency last-known state cache populated by the background evaluator; return 200 with status pass when every declared dependency cached state is pass, return 503 with status fail otherwise; response body includes the checks object with state and checkedAt per declared dependency (AC-7102-1, AC-7103-1, AC-7103-2, AC-7107-2, AC-7110-1).",
|
|
12
|
+
"Complete the handler evaluation within the readiness evaluation budget (default 1 second) regardless of any dependency real-endpoint responsiveness; no synchronous network call is issued from inside the handler (AC-7110-1).",
|
|
13
|
+
"Run the background dep-health evaluator on its declared cadence, evaluating every declared dependency at least once per interval independently of any other dependency state, so a hanging dep does not starve the others evaluations (AC-7110-2).",
|
|
14
|
+
"Refuse boot with a stable-coded error PROBE_INTERFACE_PATHS_MISSING when probeInterface.paths.readiness is absent AND observability-probe-endpoints is not composed on the same project; when probe-endpoints is composed, the resolved profile readiness path binds automatically and the essentials-side wiring is a no-op (no dual handler registration on the same path).",
|
|
15
|
+
"Refuse boot with a stable error code if the readiness dependency declaration is missing or if any entry lacks a name; the exact declared set is the exact set of keys in the probe response checks object (AC-7103-1, AC-7103-3)."
|
|
15
16
|
],
|
|
16
17
|
"internalStructure": "Two modules: a handler module exporting createReadinessHandler({ path, registry, budgetMs, now }) -> { path, handler } and an evaluator module exporting createEvaluator({ registry, cadenceMs, checkFor, now }) -> { start, stop, snapshot } where snapshot() returns the current { depName -> { state, checkedAt } } map the handler reads. The registry is the declared dependency set loaded at boot from configuration and refused if malformed. The checkFor function is a project-supplied per-dependency probe implementation the evaluator invokes on its own cadence with its own per-dependency timeout budget.",
|
|
17
18
|
"interfaces": [
|
|
18
19
|
{
|
|
19
20
|
"name": "createReadinessHandler",
|
|
20
21
|
"kind": "factory",
|
|
21
|
-
"description": "createReadinessHandler({ path, registry, budgetMs, now }) -> { path, handler }. Returns the configured readiness path and a handler that reads only from the evaluator
|
|
22
|
+
"description": "createReadinessHandler({ path, registry, budgetMs, now }) -> { path, handler }. Returns the configured readiness path and a handler that reads only from the evaluator snapshot(); never blocks on a network call. `path` is a REQUIRED configuration input with no shipped default; when it is missing the caller refuses boot with PROBE_INTERFACE_PATHS_MISSING."
|
|
22
23
|
},
|
|
23
24
|
{
|
|
24
25
|
"name": "createEvaluator",
|
|
@@ -28,16 +29,21 @@
|
|
|
28
29
|
{
|
|
29
30
|
"name": "dependencyRegistry",
|
|
30
31
|
"kind": "config",
|
|
31
|
-
"description": "Declared readiness dependency set loaded at boot: a list of { name, evaluateBudgetMs? } entries. The names are the probe response
|
|
32
|
+
"description": "Declared readiness dependency set loaded at boot: a list of { name, evaluateBudgetMs? } entries. The names are the probe response checks-object keys."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "readinessPath",
|
|
36
|
+
"kind": "config",
|
|
37
|
+
"description": "Configured readiness HTTP path supplied by the project under probeInterface.paths.readiness. There is no shipped default in essentials v2.0.0. When observability-probe-endpoints is composed, the resolved profile readiness path substitutes for this configuration entry automatically; essentials-alone projects supply it explicitly at boot."
|
|
32
38
|
},
|
|
33
39
|
{
|
|
34
40
|
"name": "checkFor",
|
|
35
41
|
"kind": "callback",
|
|
36
|
-
"description": "Project-supplied per-dependency probe: (name) -> Promise<{ state:
|
|
42
|
+
"description": "Project-supplied per-dependency probe: (name) -> Promise<{ state: pass or fail, checkedAt: <ISO-8601> }>. Called by the evaluator, not by the handler."
|
|
37
43
|
}
|
|
38
44
|
],
|
|
39
45
|
"dependencies": [],
|
|
40
|
-
"tradeoffs": "The cached-state pattern means the probe response is at worst one cadence interval stale; a dep that fails mid-cycle takes up to the cadence to reflect on the probe. That staleness is the cost of never hanging the probe handler. Projects that want tighter freshness turn down the cadence at the cost of extra background work; projects that never want the probe to falsely fail on a transient dep blip turn up the cadence at the cost of slower fail-open detection.",
|
|
46
|
+
"tradeoffs": "The cached-state pattern means the probe response is at worst one cadence interval stale; a dep that fails mid-cycle takes up to the cadence to reflect on the probe. That staleness is the cost of never hanging the probe handler. Path binding is now the operator or the composed observability-probe-endpoints blueprint decision, not an essentials default: the v2.0.0 breaking change is exactly this shift. Projects that want tighter freshness turn down the cadence at the cost of extra background work; projects that never want the probe to falsely fail on a transient dep blip turn up the cadence at the cost of slower fail-open detection.",
|
|
41
47
|
"createdAt": "2026-08-24T00:00:00Z",
|
|
42
|
-
"updatedAt": "2026-
|
|
48
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
43
49
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"usId": "observability-essentials-US-7101",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
4
|
"reqId": "observability-essentials-REQ-001",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "2.0.0",
|
|
6
6
|
"status": "approved",
|
|
7
7
|
"title": "Orchestrator restarts a stuck replica via the liveness probe without external dependency coupling",
|
|
8
8
|
"asA": "orchestrator running the deployed application under a supervising process (Kubernetes kubelet, systemd, or equivalent)",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"acceptanceCriteria": [
|
|
12
12
|
{
|
|
13
13
|
"id": "AC-7101-1",
|
|
14
|
-
"description": "The application serves the liveness endpoint at a stable HTTP path
|
|
14
|
+
"description": "The application serves the liveness endpoint at a stable HTTP path supplied by project configuration under `probeInterface.paths.liveness` (with no shipped default from v2.0.0); a GET returns 200 when the process is running its event loop and returns application/json with a status field equal to pass. When observability-probe-endpoints v1.1.0 or later is composed on the same project the resolved profile liveness path substitutes for this configuration entry automatically.",
|
|
15
15
|
"given": "the process is running normally with its event loop responsive",
|
|
16
16
|
"when": "an unauthenticated GET is issued against the liveness path",
|
|
17
17
|
"then": "the response status code is 200, the Content-Type is application/json, and the JSON body's status field equals pass",
|
|
@@ -35,11 +35,20 @@
|
|
|
35
35
|
"then": "the response status code is 200 and the JSON body's status field equals pass",
|
|
36
36
|
"testable": true,
|
|
37
37
|
"scope": "runtime"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "AC-7101-4",
|
|
41
|
+
"description": "When `probeInterface.paths.liveness` is absent from project configuration AND observability-probe-endpoints is not composed on the same project, the essentials blueprint refuses boot with a stable-coded error `PROBE_INTERFACE_PATHS_MISSING` naming the missing configuration key.",
|
|
42
|
+
"given": "a project applying essentials v2.0.0 alone with no probeInterface.paths.liveness in configuration",
|
|
43
|
+
"when": "the process attempts to boot",
|
|
44
|
+
"then": "the boot fails with the stable-coded error PROBE_INTERFACE_PATHS_MISSING and the error message names probeInterface.paths.liveness as the missing key",
|
|
45
|
+
"testable": true,
|
|
46
|
+
"scope": "runtime"
|
|
38
47
|
}
|
|
39
48
|
],
|
|
40
49
|
"tacIds": [
|
|
41
50
|
"TAC-801-observability-essentials-liveness-probe"
|
|
42
51
|
],
|
|
43
52
|
"createdAt": "2026-08-24T00:00:00Z",
|
|
44
|
-
"updatedAt": "2026-
|
|
53
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
45
54
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"usId": "observability-essentials-US-7102",
|
|
3
3
|
"prdId": "PRD-001",
|
|
4
4
|
"reqId": "observability-essentials-REQ-002",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "2.0.0",
|
|
6
6
|
"status": "approved",
|
|
7
7
|
"title": "Load balancer pulls an unready replica from rotation via the readiness probe without triggering a restart",
|
|
8
8
|
"asA": "load balancer or service mesh routing traffic across replicas of the deployed application",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"acceptanceCriteria": [
|
|
12
12
|
{
|
|
13
13
|
"id": "AC-7102-1",
|
|
14
|
-
"description": "The application serves the readiness endpoint at a stable HTTP path
|
|
14
|
+
"description": "The application serves the readiness endpoint at a stable HTTP path supplied by project configuration under `probeInterface.paths.readiness` (with no shipped default from v2.0.0), distinct from the liveness path; a GET returns 200 with a JSON body when every declared readiness dependency is passing and returns 503 with a JSON body when at least one declared readiness dependency is failing. When observability-probe-endpoints v1.1.0 or later is composed on the same project the resolved profile readiness path substitutes for this configuration entry automatically.",
|
|
15
15
|
"given": "the process is running and the readiness dependency set is declared",
|
|
16
16
|
"when": "an unauthenticated GET is issued against the readiness path against a healthy dependency set, then against a set with at least one failing dependency",
|
|
17
17
|
"then": "the first response has status code 200 with JSON body status equal to pass; the second response has status code 503 with JSON body status equal to fail; both bodies have Content-Type application/json",
|
|
@@ -35,11 +35,20 @@
|
|
|
35
35
|
"then": "the process exit code is not emitted, the process remains running throughout the window, and the liveness probe continues to return 200 with status pass",
|
|
36
36
|
"testable": true,
|
|
37
37
|
"scope": "runtime"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "AC-7102-4",
|
|
41
|
+
"description": "When `probeInterface.paths.readiness` is absent from project configuration AND observability-probe-endpoints is not composed on the same project, the essentials blueprint refuses boot with a stable-coded error `PROBE_INTERFACE_PATHS_MISSING` naming the missing configuration key.",
|
|
42
|
+
"given": "a project applying essentials v2.0.0 alone with no probeInterface.paths.readiness in configuration",
|
|
43
|
+
"when": "the process attempts to boot",
|
|
44
|
+
"then": "the boot fails with the stable-coded error PROBE_INTERFACE_PATHS_MISSING and the error message names probeInterface.paths.readiness as the missing key",
|
|
45
|
+
"testable": true,
|
|
46
|
+
"scope": "runtime"
|
|
38
47
|
}
|
|
39
48
|
],
|
|
40
49
|
"tacIds": [
|
|
41
50
|
"TAC-802-observability-essentials-readiness-probe"
|
|
42
51
|
],
|
|
43
52
|
"createdAt": "2026-08-24T00:00:00Z",
|
|
44
|
-
"updatedAt": "2026-
|
|
53
|
+
"updatedAt": "2026-09-04T00:00:00Z"
|
|
45
54
|
}
|
|
@@ -6,11 +6,18 @@ This file is the observability-essentials half of the cross-blueprint contract.
|
|
|
6
6
|
|
|
7
7
|
| Topic string | observability-essentials contribution | Origin | Composition note |
|
|
8
8
|
|---|---|---|---|
|
|
9
|
-
| `healthProbes` | ADR-801-observability-essentials-health-probes | Minted here; pre-cleared as unclaimed against application-spa (`clientRouting`, `theming`, `clientState`, `errorEnvelope`, `authModel`), application-api-rest (`errorEnvelope`, `authModel`, `apiVersioning`, `logging`), security-auth-magic-link (`authModel`), persistence-data-sqlite (`persistenceStore`, `migrationDiscipline`), delivery-ci-workflows (`ciGates`, `strictCoverageGate`), and the hello-panel walkthrough exemplar (`operatorPanel`) | The one HTTP health probe contract for the project: two endpoints (liveness /healthz, readiness /readyz), shared JSON body shape, served on the request-traffic listener. A composing blueprint that holds a different endpoint contract (a single /health endpoint, gRPC health protocol, probes on a separate admin port) contributes its own scope:global ADR on this exact string and lets composition surface the pairing. Expected resolution: one project-level ADR that fixes the endpoint contract |
|
|
10
|
-
| `readinessSemantics` | ADR-802-observability-essentials-readiness-semantics | Minted here; pre-cleared as unclaimed against application-spa, application-api-rest, security-auth-magic-link, persistence-data-sqlite, delivery-ci-workflows, and hello-panel | The one readiness aggregation and declaration scope for the project: strict-any-fail over an explicit boot-time-declared dependency set, evaluated against per-dep cached state. A composing blueprint that holds a different opinion (quorum aggregation, write-path-only readiness, graceful-degradation model) conflicts here by design. Expected resolution: one project-level ADR fixing the semantics |
|
|
11
9
|
| `statusPageContract` | ADR-803-observability-essentials-status-page-contract | Minted here; pre-cleared as unclaimed against application-spa, application-api-rest, security-auth-magic-link, persistence-data-sqlite, delivery-ci-workflows, and hello-panel | The one public status page contract for the project: declared component list plus fixed state enum plus stable-fielded incident notices. A composing blueprint that wants a different public contract (JSON endpoint at /status.json, historical uptime cells as v1 requirement, webhook-posted notices) conflicts here by design. Expected resolution: one project-level ADR fixing the public contract |
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
From v2.0.0 the observability-essentials blueprint claims ONE global topic (`statusPageContract`). Every other contribution is scope-local (ADR-801 health probes and ADR-802 readiness semantics are historical scope-local ADRs recording the self-supervised design intent; ADR-804 probe secrecy and ADR-805 notification outcome model do not contribute global topics; a composing blueprint that holds an opinion on probe auth policy or notification outcome shape authors its own project-level ADR if it wants to override).
|
|
12
|
+
|
|
13
|
+
### Historical global topics (dropped in v2.0.0)
|
|
14
|
+
|
|
15
|
+
The alignment ratified in `projects/rcf-lite-wsd/specs/rcf-lite-probe-path-alignment-spec-2026-09-04.md` moved probe-path ownership to `observability-probe-endpoints` as the sole shelf-wide claimant. The two rows below record what this blueprint used to claim; the ADRs stay on disk as scope-local historical context and their titles carry a "Historical: ... superseded by observability-probe-endpoints" prefix.
|
|
16
|
+
|
|
17
|
+
| Historical topic string | Was claimed by | Replaced by | Migration reference |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| `healthProbes` | ADR-801-observability-essentials-health-probes (v1.x, now historical) | `observability-probe-endpoints` ADR-1501 (sole shelf owner from probe-endpoints v1.0.0; sole shelf claimant from essentials v2.0.0) | spec section 4; TAC-801 v2.0.0 drops the `/healthz` default; REQ-001 restated path-neutral |
|
|
20
|
+
| `readinessSemantics` | ADR-802-observability-essentials-readiness-semantics (v1.x, now historical) | `observability-probe-endpoints` ADR-1502 (sole shelf owner from probe-endpoints v1.0.0; sole shelf claimant from essentials v2.0.0) | spec section 4; TAC-802 v2.0.0 drops the `/readyz` default; REQ-002 restated path-neutral |
|
|
14
21
|
|
|
15
22
|
Note on the delineation from the hello-panel walkthrough's `operatorPanel` topic: `operatorPanel` (owned by the hello-panel walkthrough exemplar) governs the project's PRIMARY operator drift-detection surface, an AUTHENTICATED surface for the operator. This blueprint's status page (ADR-803) governs the PUBLIC status surface for external readers. The two surfaces are deliberately distinct in audience and vocabulary; this blueprint MUST NOT touch `operatorPanel` and does not contribute an ADR on it.
|
|
16
23
|
|
|
@@ -35,14 +42,14 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
|
|
|
35
42
|
| hello-panel (walkthrough exemplar) | 4101-4899 | 4xx | doc-reserved; teaching exemplar in `packages/rcf-lite/docs/blueprint-authoring-walkthrough.md`, not shipped as a blueprint directory | `operatorPanel` |
|
|
36
43
|
| persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
37
44
|
| delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
|
|
38
|
-
| observability-essentials | 7101-7899 | 8xx | shipped
|
|
45
|
+
| observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
|
|
39
46
|
| security-secrets-management | 8101-8899 | 9xx | shipped v1.0.0 | `secretsSource` |
|
|
40
47
|
| security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
|
|
41
48
|
| security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
|
|
42
49
|
| security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
|
|
43
50
|
| deploy-cloudflare-workers | 12101-12899 | 13xx | shipped v1.0.0 | `deploymentTarget` |
|
|
44
51
|
| persistence-data-d1 | 13101-13899 | 14xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
|
|
45
|
-
| observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.
|
|
52
|
+
| observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
|
|
46
53
|
|
|
47
54
|
US 7101-7110 sit at the LOW end of the 7101-7899 band on purpose. A project-side story that mechanically derives from an observability-essentials REQs id into the number `7110` would collide against observability-essentials-US-7110 in this package; the band leaves headroom at the HIGH end (US 7181-7899) so a project's own stories anchored to observability-essentials REQs can allocate without conflict. The watchpost run4 lesson applies here too.
|
|
48
55
|
|
|
@@ -50,8 +57,8 @@ Row-status caveat: the delivery-ci-workflows seat shipped first (PR #95 merged a
|
|
|
50
57
|
|
|
51
58
|
## Shared expectations for future composing blueprints
|
|
52
59
|
|
|
53
|
-
- Reuse `healthProbes` exactly as spelled here when your blueprint holds an opinion on the health endpoint contract; contribute your own scope:global ADR on that string and let composition surface the pairing
|
|
54
|
-
- Reuse `readinessSemantics` exactly as spelled here when your blueprint holds an opinion on readiness aggregation or the declaration scope
|
|
60
|
+
- Reuse `healthProbes` exactly as spelled here when your blueprint holds an opinion on the health endpoint contract; contribute your own scope:global ADR on that string and let composition surface the pairing on the sole owner (`observability-probe-endpoints` from v1.0.0). This blueprint no longer claims the topic from v2.0.0.
|
|
61
|
+
- Reuse `readinessSemantics` exactly as spelled here when your blueprint holds an opinion on readiness aggregation or the declaration scope on the sole owner (`observability-probe-endpoints` from v1.0.0). This blueprint no longer claims the topic from v2.0.0.
|
|
55
62
|
- Reuse `statusPageContract` exactly as spelled here when your blueprint holds an opinion on the public status surface; a machine-readable JSON-endpoint blueprint or a historical-uptime blueprint conflicts here by design.
|
|
56
|
-
-
|
|
63
|
+
- From v2.0.0 this blueprint's decision states the body shape and dep-registry semantics for the two probe surfaces (as scope-local historical intent), the readiness dep registry and strict-any-fail readiness predicate for the essentials-alone case, and the declared-component fixed-enum status page as its ONLY global commitment. Compose compatible metrics-export, tracing, or authenticated-operator-dashboard blueprints, or expect the operator to supersede with one project-level ADR per topic.
|
|
57
64
|
- Global topics that plausibly belong to a future blueprint and are NOT claimed by any shipped blueprint: `messageSerialisation` and `deliverySemantics` (a message-consumer blueprint's natural globals), `caching` (unclaimed by every shipped blueprint), `metricsExport` and `tracingProtocol` (natural globals for a metrics or tracing blueprint that would compose alongside this one). Define any of these in your own package's topics doc, in this file's format, and consider whether the band-registry table above needs your slug added.
|
|
@@ -46,15 +46,15 @@ The design brief `w-2026-07-28-029` originally scoped observability as one of th
|
|
|
46
46
|
|
|
47
47
|
A project applies the observability-essentials blueprint on a fresh tree, declares its readiness dependency set (payments-provider, primary-store, sms-gateway) in configuration, declares its public component list (Payments, Notifications, Data) in configuration, wires TAC-801 through TAC-804 into project-authored FBSes, and lands on a deployed application where:
|
|
48
48
|
|
|
49
|
-
- The orchestrator hits
|
|
50
|
-
- The load balancer hits
|
|
49
|
+
- The orchestrator hits the configured liveness path on the request-traffic listener every N seconds; every hit gets 200 with the JSON body inside a millisecond budget; a stuck process is restarted within N seconds of wedging.
|
|
50
|
+
- The load balancer hits the configured readiness path on the request-traffic listener every N seconds; a healthy replica gets 200 and stays in rotation, a replica whose declared payments-provider dependency has gone offline gets 503 and is pulled from rotation without restart. The replica comes back to rotation when the dependency's cached state returns to pass.
|
|
51
51
|
- An external customer visits /status without a login, sees the three declared components (Payments: operational, Notifications: degraded, Data: operational) with the current state enum values as data attributes, sees the active incident notice above the component list with its title, body, severity, startedAt and componentIds fields, and does not see any hostname, replica id, database identifier, queue name, internal URL, build hash, request count, latency number, error rate, queue depth, or readiness dependency name anywhere on the page.
|
|
52
52
|
- Every notification the application attempts records exactly one outcome record on the durable sink with the notificationId, channel, recipient, outcome, attemptedAt, and (on failure) errorCode fields; the operator queries the sink by recipient identifier and time window and gets the outcome records that match; a recipient with no attempts in the window returns an empty result set.
|
|
53
53
|
- A downstream partial outage (a payments-provider that has gone slow) turns the readiness cached state for that dependency to fail; readiness probes return 503 within the readiness evaluation budget; liveness probes continue to return 200 within the tighter liveness budget; the load balancer pulls the affected replicas from rotation; the orchestrator does not restart them; the payments-provider recovers, the background evaluator refreshes the cached state to pass, readiness returns 200, and the replicas re-enter rotation without human intervention.
|
|
54
54
|
|
|
55
55
|
## Operator decisions that remain open after apply
|
|
56
56
|
|
|
57
|
-
- The liveness path
|
|
57
|
+
- The liveness path and the readiness path are project configuration from v2.0.0 (essentials-alone case) or supplied by the composed observability-probe-endpoints blueprint (Kubernetes profile default /live and /ready, loadBalancer profile default /health). The status page path default remains /status; the project overrides it at boot for compliance with a particular platform mandate.
|
|
58
58
|
- The readiness dependency set (which downstream deps a failure of makes this replica unfit to serve). Blueprint owns the strict-any-fail semantics and the declaration shape; project owns the concrete dep list.
|
|
59
59
|
- The public component list on the status page (name and order). Blueprint owns the vocabulary shape and the state enum; project owns the components themselves and the mapping from internal dep state to public component state.
|
|
60
60
|
- The active incident notice authoring workflow (how the operator posts a notice, where the notice store lives, who has permission to post). Blueprint owns the notice field set and the render contract; project owns the write path.
|
|
@@ -66,3 +66,9 @@ A project applies the observability-essentials blueprint on a fresh tree, declar
|
|
|
66
66
|
## Cost-honesty paragraph
|
|
67
67
|
|
|
68
68
|
Shipping this doc set costs the project the following. Every request path pays two probe endpoints on the same listener as request traffic; both handlers are trivial but still consume a small share of the router's dispatch cost. The background dep-health evaluator runs on its own cadence for the process lifetime; a project with N declared dependencies pays N per-dep evaluations per cadence, and each evaluation is a project-authored function that can spend as much time as it likes inside its own budget. The public status page is a first-class HTTP surface the project owns forever: renaming a declared component is a public-contract change; adding a new component is a public-contract change; the fixed state enum and fixed notice severity enum are commitments. The notification outcome sink adds a durable write per notification attempt; a project that sends millions of notifications a day pays proportionately, and the durable substrate has to handle the write rate. The three auth-exempt paths are a security invariant the project maintains across every auth middleware refactor. In return, the project gets: a restart signal decoupled from downstream health, a rotation signal that names which dep failed, a public surface that answers 'is this up' without human involvement, and an answer to 'did the customer get the notification' that is a query not an escalation.
|
|
69
|
+
|
|
70
|
+
## Composing with observability-probe-endpoints (v2.0.0)
|
|
71
|
+
|
|
72
|
+
From v2.0.0 the essentials blueprint stops teaching literal probe paths. What the guide taught in v1.x (`/healthz` for liveness, `/readyz` for readiness) is now a project-level configuration line: essentials-alone projects supply `probeInterface.paths.liveness` and `probeInterface.paths.readiness` in configuration, and the essentials wiring refuses boot with the stable-coded error `PROBE_INTERFACE_PATHS_MISSING` when either is absent. Projects that also apply `observability-probe-endpoints` v1.1.0 or later get the resolved profile paths (Kubernetes default `/live` and `/ready`, optional `/startup` when enabled, or `/health` on the loadBalancer profile) automatically; the essentials boot wiring becomes a no-op on the paths that probe-endpoints already binds so there is no double-registration of the same handler.
|
|
73
|
+
|
|
74
|
+
What this blueprint still owns after v2.0.0: the JSON body shape, the readiness dependency registry and its strict-any-fail predicate, the probe-secrecy rule, the public status page contract (`statusPageContract`, still `scope: global`), and the notification outcome sink. What moved: probe-path binding, and the `healthProbes` + `readinessSemantics` global topic claims. The compose test at `packages/rcf-lite/test/blueprint/probe-path-alignment.test.js` is the ratified truth for the three-way surface.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# observability-probe-endpoints blueprint (v1.1.0)
|
|
2
2
|
|
|
3
3
|
The tenth content blueprint on the rcf-build-lite blueprint mechanism, and the second in the `observability` category, sibling to the shipped `observability-essentials`. Scope: a health probe interface derived from an operator-declared target integration profile (`kubernetes`, `loadBalancer`, `uptimeMonitor`, `systemd`, `dockerHealthcheck`, `reverseProxy`, plus a `custom:<name>` slot). Each profile fixes the probe transport, path or command surface, response contract, and semantic distinction between liveness and readiness for the supervisor at hand. Kubernetes is the shipped default (HTTPGet `/live` and `/ready` on the request-traffic listener); every HTTP profile ships with a `probeListener.separatePort` opt-in for probe-traffic isolation from user traffic. Response contracts are minimal by construction; the profile validator refuses any override that would add a field beyond the enumerated set. Targeted at rcf-lite projects that must integrate with a specific EXTERNAL supervising system whose conventions drive the probe wire shape; not targeted at the self-supervised all-in-one observability case (observability-essentials owns that).
|
|
4
4
|
|
|
@@ -51,3 +51,7 @@ The probe surface always follows the operator-declared target integration profil
|
|
|
51
51
|
|
|
52
52
|
- **Custom-profile contract adherence.** Projects that author a `custom:<name>` profile against the profile contract are expected to satisfy the same transport/paths/responseContract/semanticModel shape the shipped profiles do; the profile contract validator (TAC-1501) refuses a partial profile at boot, which is where the mechanism reach lands. What the validator cannot compel is that a project-authored custom profile's response shape is minimal in the AC-14105 and AC-14106 sense (a custom profile could in principle enumerate a rich field set the validator would accept as complete). Recorded here rather than smuggled in as an AC that would only apply to the shipped profiles. Promotion signal: a `custom-profile-shape-lint` addition to the profile contract validator that enforces the minimalism rule per field-set-size heuristic (harder than it sounds; some legitimate custom profiles do have wider fields); or a project-side grep gate. Project-side workaround until then: reviewers of a `custom:<name>` profile eyeball the enumerated field set against the pattern the shipped six carry.
|
|
53
53
|
- **Kubernetes gRPC probe transport.** The `kubernetes` profile ships HTTPGet and TCPSocket transports (via TAC-1504's tcpAdapter selection) but not gRPC. A project on a gRPC-only mesh that wants the standard gRPC health protocol supersedes ADR-1503 with a project-level ADR selecting the gRPC transport, or authors a `custom:kubernetes-grpc` profile. Promotion signal: a shipped gRPC-transport handler in a v1.1 pass if enough rcf-lite projects reach for it. Project-side workaround: the `custom:<name>` slot is the mechanism escape hatch.
|
|
54
|
+
|
|
55
|
+
## Optional startup path (v1.1.0)
|
|
56
|
+
|
|
57
|
+
The Kubernetes profile gains an optional third path `startup` (default `/startup`) from v1.1.0. It is BOUND only when the operator sets `probeInterface.options.kubernetes.startup.enabled: true`; unset or `false`, the profile resolves as before with the two-path set (`/live`, `/ready`). The startup handler follows the same generation rules as the other Kubernetes-profile handlers (same `{"status":"pass"|"fail"}` body, same auth-exempt list emission, same listener topology). See US-14102 AC-14102-4 and US-14107 AC-14107-4 for the acceptance criteria, and the composing section in `guide/observability-probe-endpoints.md` for how essentials and api-rest defer their path opinions to this blueprint.
|
|
@@ -1,28 +1,108 @@
|
|
|
1
1
|
{
|
|
2
2
|
"slug": "observability-probe-endpoints",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"category": "observability",
|
|
5
5
|
"contributions": [
|
|
6
|
-
{
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
6
|
+
{
|
|
7
|
+
"id": "observability-probe-endpoints-REQ-001",
|
|
8
|
+
"kind": "req",
|
|
9
|
+
"path": "requirements/observability-probe-endpoints-req-001.json"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"id": "observability-probe-endpoints-REQ-002",
|
|
13
|
+
"kind": "req",
|
|
14
|
+
"path": "requirements/observability-probe-endpoints-req-002.json"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"id": "observability-probe-endpoints-REQ-003",
|
|
18
|
+
"kind": "req",
|
|
19
|
+
"path": "requirements/observability-probe-endpoints-req-003.json"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "observability-probe-endpoints-REQ-004",
|
|
23
|
+
"kind": "req",
|
|
24
|
+
"path": "requirements/observability-probe-endpoints-req-004.json"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "observability-probe-endpoints-REQ-005",
|
|
28
|
+
"kind": "req",
|
|
29
|
+
"path": "requirements/observability-probe-endpoints-req-005.json"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "observability-probe-endpoints-REQ-006",
|
|
33
|
+
"kind": "req",
|
|
34
|
+
"path": "requirements/observability-probe-endpoints-req-006.json"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "observability-probe-endpoints-REQ-007",
|
|
38
|
+
"kind": "req",
|
|
39
|
+
"path": "requirements/observability-probe-endpoints-req-007.json"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "observability-probe-endpoints-REQ-008",
|
|
43
|
+
"kind": "req",
|
|
44
|
+
"path": "requirements/observability-probe-endpoints-req-008.json"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "observability-probe-endpoints-US-14101",
|
|
48
|
+
"kind": "us",
|
|
49
|
+
"path": "user-stories/observability-probe-endpoints-us-14101.json"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "observability-probe-endpoints-US-14102",
|
|
53
|
+
"kind": "us",
|
|
54
|
+
"path": "user-stories/observability-probe-endpoints-us-14102.json"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "observability-probe-endpoints-US-14103",
|
|
58
|
+
"kind": "us",
|
|
59
|
+
"path": "user-stories/observability-probe-endpoints-us-14103.json"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"id": "observability-probe-endpoints-US-14104",
|
|
63
|
+
"kind": "us",
|
|
64
|
+
"path": "user-stories/observability-probe-endpoints-us-14104.json"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"id": "observability-probe-endpoints-US-14105",
|
|
68
|
+
"kind": "us",
|
|
69
|
+
"path": "user-stories/observability-probe-endpoints-us-14105.json"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"id": "observability-probe-endpoints-US-14106",
|
|
73
|
+
"kind": "us",
|
|
74
|
+
"path": "user-stories/observability-probe-endpoints-us-14106.json"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "observability-probe-endpoints-US-14107",
|
|
78
|
+
"kind": "us",
|
|
79
|
+
"path": "user-stories/observability-probe-endpoints-us-14107.json"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "observability-probe-endpoints-US-14108",
|
|
83
|
+
"kind": "us",
|
|
84
|
+
"path": "user-stories/observability-probe-endpoints-us-14108.json"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"id": "TAC-1501-observability-probe-endpoints-profile-resolver",
|
|
88
|
+
"kind": "tac",
|
|
89
|
+
"path": "tacs/tac-1501-observability-probe-endpoints-profile-resolver.json"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"id": "TAC-1502-observability-probe-endpoints-handler-set",
|
|
93
|
+
"kind": "tac",
|
|
94
|
+
"path": "tacs/tac-1502-observability-probe-endpoints-handler-set.json"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"id": "TAC-1503-observability-probe-endpoints-listener-topology",
|
|
98
|
+
"kind": "tac",
|
|
99
|
+
"path": "tacs/tac-1503-observability-probe-endpoints-listener-topology.json"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"id": "TAC-1504-observability-probe-endpoints-non-http-adapters",
|
|
103
|
+
"kind": "tac",
|
|
104
|
+
"path": "tacs/tac-1504-observability-probe-endpoints-non-http-adapters.json"
|
|
105
|
+
},
|
|
26
106
|
{
|
|
27
107
|
"id": "ADR-1501-observability-probe-endpoints-health-probes",
|
|
28
108
|
"kind": "adr",
|
|
@@ -37,8 +117,20 @@
|
|
|
37
117
|
"scope": "global",
|
|
38
118
|
"topic": "readinessSemantics"
|
|
39
119
|
},
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
|
|
120
|
+
{
|
|
121
|
+
"id": "ADR-1503-observability-probe-endpoints-kubernetes-default",
|
|
122
|
+
"kind": "adr",
|
|
123
|
+
"path": "adrs/adr-1503-observability-probe-endpoints-kubernetes-default.json"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"id": "ADR-1504-observability-probe-endpoints-separate-port-option",
|
|
127
|
+
"kind": "adr",
|
|
128
|
+
"path": "adrs/adr-1504-observability-probe-endpoints-separate-port-option.json"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"id": "ADR-1505-observability-probe-endpoints-external-response-secrecy",
|
|
132
|
+
"kind": "adr",
|
|
133
|
+
"path": "adrs/adr-1505-observability-probe-endpoints-external-response-secrecy.json"
|
|
134
|
+
}
|
|
43
135
|
]
|
|
44
136
|
}
|