rcf-lite 0.17.0 → 0.19.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.
Files changed (161) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/blueprints/application-api-rest/README.md +5 -1
  3. package/blueprints/application-api-rest/blueprint.json +12 -4
  4. package/blueprints/application-api-rest/contributions/adrs/adr-304-application-api-rest-logging.json +3 -3
  5. package/blueprints/application-api-rest/contributions/requirements/application-api-rest-req-006.json +4 -4
  6. package/blueprints/application-api-rest/contributions/tacs/tac-306-application-api-rest-operability.json +9 -8
  7. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2103.json +3 -3
  8. package/blueprints/application-api-rest/contributions/user-stories/application-api-rest-us-2108.json +27 -27
  9. package/blueprints/application-api-rest/docs/topics.md +6 -4
  10. package/blueprints/application-api-rest/guide/application-api-rest.md +5 -1
  11. package/blueprints/application-error-handling/README.md +42 -0
  12. package/blueprints/application-error-handling/assets/schemas/error-record.schema.json +17 -0
  13. package/blueprints/application-error-handling/blueprint.json +27 -0
  14. package/blueprints/application-error-handling/contributions/adrs/adr-1701-application-error-handling-record-shape.json +25 -0
  15. package/blueprints/application-error-handling/contributions/adrs/adr-1702-application-error-handling-classification-vocabulary.json +20 -0
  16. package/blueprints/application-error-handling/contributions/adrs/adr-1703-application-error-handling-transport-mapping.json +20 -0
  17. package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-001.json +15 -0
  18. package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-002.json +15 -0
  19. package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-003.json +15 -0
  20. package/blueprints/application-error-handling/contributions/requirements/application-error-handling-req-004.json +15 -0
  21. package/blueprints/application-error-handling/contributions/tacs/tac-1701-application-error-handling-boundary.json +45 -0
  22. package/blueprints/application-error-handling/contributions/tacs/tac-1702-application-error-handling-record-factory.json +40 -0
  23. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16101.json +25 -0
  24. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16102.json +25 -0
  25. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16103.json +34 -0
  26. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16104.json +25 -0
  27. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16105.json +25 -0
  28. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16106.json +25 -0
  29. package/blueprints/application-error-handling/contributions/user-stories/application-error-handling-us-16107.json +25 -0
  30. package/blueprints/application-error-handling/docs/topics.md +24 -0
  31. package/blueprints/application-error-handling/guide/application-error-handling.md +35 -0
  32. package/blueprints/application-spa/blueprint.json +12 -2
  33. package/blueprints/application-spa/docs/topics.md +4 -2
  34. package/blueprints/delivery-ci-workflows/docs/topics.md +2 -2
  35. package/blueprints/deploy-cloudflare-workers/docs/topics.md +2 -2
  36. package/blueprints/email-smtp-resend/docs/topics.md +2 -2
  37. package/blueprints/observability-essentials/README.md +6 -2
  38. package/blueprints/observability-essentials/blueprint.json +133 -33
  39. package/blueprints/observability-essentials/contributions/adrs/adr-801-observability-essentials-health-probes.json +4 -4
  40. package/blueprints/observability-essentials/contributions/adrs/adr-802-observability-essentials-readiness-semantics.json +4 -4
  41. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-001.json +4 -4
  42. package/blueprints/observability-essentials/contributions/requirements/observability-essentials-req-002.json +4 -4
  43. package/blueprints/observability-essentials/contributions/tacs/tac-801-observability-essentials-liveness-probe.json +10 -9
  44. package/blueprints/observability-essentials/contributions/tacs/tac-802-observability-essentials-readiness-probe.json +17 -11
  45. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7101.json +12 -3
  46. package/blueprints/observability-essentials/contributions/user-stories/observability-essentials-us-7102.json +12 -3
  47. package/blueprints/observability-essentials/docs/topics.md +15 -8
  48. package/blueprints/observability-essentials/guide/observability-essentials.md +9 -3
  49. package/blueprints/observability-logging/README.md +44 -0
  50. package/blueprints/observability-logging/assets/samples/log-line.json +13 -0
  51. package/blueprints/observability-logging/blueprint.json +27 -0
  52. package/blueprints/observability-logging/contributions/adrs/adr-1601-observability-logging-line-shape.json +25 -0
  53. package/blueprints/observability-logging/contributions/adrs/adr-1602-observability-logging-correlation-id-header.json +25 -0
  54. package/blueprints/observability-logging/contributions/adrs/adr-1603-observability-logging-redaction-categories.json +25 -0
  55. package/blueprints/observability-logging/contributions/adrs/adr-1604-observability-logging-level-vocabulary.json +20 -0
  56. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-001.json +15 -0
  57. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-002.json +15 -0
  58. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-003.json +15 -0
  59. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-004.json +15 -0
  60. package/blueprints/observability-logging/contributions/requirements/observability-logging-req-005.json +15 -0
  61. package/blueprints/observability-logging/contributions/tacs/tac-1601-observability-logging-logger-factory.json +46 -0
  62. package/blueprints/observability-logging/contributions/tacs/tac-1602-observability-logging-redaction-boundary.json +27 -0
  63. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15101.json +34 -0
  64. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15102.json +43 -0
  65. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15103.json +34 -0
  66. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15104.json +25 -0
  67. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15105.json +34 -0
  68. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15106.json +25 -0
  69. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15107.json +25 -0
  70. package/blueprints/observability-logging/contributions/user-stories/observability-logging-us-15108.json +25 -0
  71. package/blueprints/observability-logging/docs/topics.md +21 -0
  72. package/blueprints/observability-logging/guide/observability-logging.md +36 -0
  73. package/blueprints/observability-probe-endpoints/README.md +5 -1
  74. package/blueprints/observability-probe-endpoints/blueprint.json +116 -24
  75. package/blueprints/observability-probe-endpoints/contributions/adrs/adr-1503-observability-probe-endpoints-kubernetes-default.json +5 -5
  76. package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14102.json +11 -2
  77. package/blueprints/observability-probe-endpoints/contributions/user-stories/observability-probe-endpoints-us-14107.json +11 -2
  78. package/blueprints/observability-probe-endpoints/docs/topics.md +6 -6
  79. package/blueprints/observability-probe-endpoints/guide/observability-probe-endpoints.md +10 -0
  80. package/blueprints/persistence-data-d1/docs/topics.md +2 -2
  81. package/blueprints/persistence-data-sqlite/docs/topics.md +2 -2
  82. package/blueprints/security-auth-clerk/docs/topics.md +2 -2
  83. package/blueprints/security-auth-keycloak/docs/topics.md +2 -2
  84. package/blueprints/security-auth-magic-link/docs/topics.md +2 -2
  85. package/blueprints/security-auth-oauth2/docs/topics.md +2 -2
  86. package/blueprints/security-secrets-management/docs/topics.md +2 -2
  87. package/fixtures/canary-manifest.json +6 -6
  88. package/guidance/harness-template.md +8 -0
  89. package/guidance/managed/agent-instructions-block.hash +1 -1
  90. package/guidance/managed/agent-instructions-block.md +8 -0
  91. package/package.json +1 -1
  92. package/rcf/code-nodes/cn-074.json +19 -0
  93. package/rcf/code-nodes/cn-075.json +15 -0
  94. package/rcf/code-nodes/cn-076.json +14 -0
  95. package/rcf/code-nodes/cn-077.json +14 -0
  96. package/rcf/code-nodes/cn-078.json +15 -0
  97. package/rcf/code-nodes/cn-079.json +14 -0
  98. package/rcf/code-nodes/cn-080.json +15 -0
  99. package/rcf/code-nodes/cn-081.json +15 -0
  100. package/rcf/code-nodes/cn-082.json +15 -0
  101. package/rcf/code-nodes/cn-083.json +14 -0
  102. package/rcf/code-nodes/cn-084.json +15 -0
  103. package/rcf/code-nodes/cn-085.json +14 -0
  104. package/rcf/code-nodes/cn-086.json +16 -0
  105. package/rcf/code-nodes/cn-087.json +14 -0
  106. package/rcf/code-nodes/cn-088.json +14 -0
  107. package/rcf/code-nodes/cn-089.json +14 -0
  108. package/rcf/code-nodes/cn-090.json +14 -0
  109. package/rcf/code-nodes/cn-091.json +14 -0
  110. package/rcf/code-nodes/cn-092.json +15 -0
  111. package/rcf/code-nodes/cn-093.json +15 -0
  112. package/rcf/code-nodes/cn-094.json +14 -0
  113. package/rcf/code-nodes/cn-095.json +14 -0
  114. package/rcf/code-nodes/cn-096.json +14 -0
  115. package/rcf/code-nodes/cn-097.json +14 -0
  116. package/rcf/fbs/fbs-024.json +24 -0
  117. package/rcf/fbs/fbs-025.json +25 -0
  118. package/rcf/fbs/fbs-026.json +27 -0
  119. package/rcf/fbs/fbs-027.json +25 -0
  120. package/rcf/fbs/fbs-028.json +27 -0
  121. package/rcf/fbs/fbs-029.json +27 -0
  122. package/rcf/fbs/fbs-030.json +27 -0
  123. package/rcf/fbs/fbs-031.json +27 -0
  124. package/rcf/fbs/fbs-032.json +27 -0
  125. package/rcf/fbs/fbs-033.json +27 -0
  126. package/rcf/fbs/fbs-034.json +27 -0
  127. package/rcf/requirements/req-012.json +22 -0
  128. package/rcf/requirements/req-013.json +22 -0
  129. package/rcf/requirements/req-014.json +22 -0
  130. package/rcf/requirements/req-015.json +21 -0
  131. package/rcf/test-suites/ts-034.json +32 -0
  132. package/rcf/test-suites/ts-035.json +23 -0
  133. package/rcf/test-suites/ts-036.json +65 -0
  134. package/rcf/test-suites/ts-037.json +55 -0
  135. package/rcf/test-suites/ts-038.json +41 -0
  136. package/rcf/test-suites/ts-039.json +41 -0
  137. package/rcf/test-suites/ts-040.json +57 -0
  138. package/rcf/test-suites/ts-041.json +57 -0
  139. package/rcf/test-suites/ts-042.json +57 -0
  140. package/rcf/test-suites/ts-043.json +49 -0
  141. package/rcf/test-suites/ts-044.json +41 -0
  142. package/rcf/user-stories/us-1201.json +34 -0
  143. package/rcf/user-stories/us-1202.json +25 -0
  144. package/rcf/user-stories/us-1203.json +43 -0
  145. package/rcf/user-stories/us-1204.json +25 -0
  146. package/rcf/user-stories/us-1301.json +43 -0
  147. package/rcf/user-stories/us-1302.json +43 -0
  148. package/rcf/user-stories/us-1401.json +43 -0
  149. package/rcf/user-stories/us-1402.json +43 -0
  150. package/rcf/user-stories/us-1403.json +43 -0
  151. package/rcf/user-stories/us-1404.json +43 -0
  152. package/rcf/user-stories/us-1501.json +43 -0
  153. package/releases/releases.yaml +21 -1
  154. package/src/blueprint/apply.js +8 -0
  155. package/src/blueprint/companions.js +485 -0
  156. package/src/blueprint/index.js +17 -0
  157. package/src/blueprint/loader.js +243 -1
  158. package/src/blueprint/remove-resolution.js +104 -0
  159. package/src/cli/blueprint.js +350 -0
  160. package/src/cli/doctor.js +76 -1
  161. package/src/cli/validate.js +7 -0
package/CHANGELOG.md CHANGED
@@ -6,6 +6,66 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.19.0] - 2026-09-04
10
+
11
+ Core companions train. Two new general-enterprise-practice blueprints land on the shipped core shelf, an additive companion-suggestion mechanism baked into the manifest, and the standards-derived-blueprint discipline written into the authoring standard as section 8a.
12
+
13
+ ### Added
14
+
15
+ - **`observability-logging` v1.0.0 on the shelf.** New core blueprint (`blueprints/observability-logging/`), category `observability`, US band `15101-15899`, ADR/TAC suffix block `16xx`. Contributes five REQs, eight USs, two TACs (`TAC-1601-observability-logging-logger-factory`, `TAC-1602-observability-logging-redaction-boundary`), four ADRs. Declares `providesRoles: ["logging"]`. `ADR-1601-observability-logging-line-shape` is the shelf-canonical `scope: global` claimant on the `logging` global topic (transferred from `application-api-rest-ADR-304`, which is retained on api-rest as historical context without `scope: global` from api-rest v2.1.0). Ships the ECS-neutral single-line JSON emission contract, correlation identifier acceptance / propagation / reflection, PII redaction at the emission boundary by named category, operator-elicited minimum level per environment, and a hermetic in-memory capture mode for tests.
16
+
17
+ - **`application-error-handling` v1.0.0 on the shelf.** New core blueprint (`blueprints/application-error-handling/`), category `application`, US band `16101-16899`, ADR/TAC suffix block `17xx`. Contributes four REQs, seven USs, two TACs (`TAC-1701-application-error-handling-boundary`, `TAC-1702-application-error-handling-record-factory`), three ADRs. Declares `providesRoles: ["errorHandling"]` and `suggestedCompanions: [{role: "logging", ...}]`. `ADR-1701-application-error-handling-record-shape` mints the `errorHandling` global topic (distinct from `errorEnvelope`, which stays with `application-api-rest` as the REST wire shape). Ships process-level and framework-level boundaries, the shared internal error record shape (code, category, message, correlationId, cause chain, redacted context), the transient / permanent / unknown classification vocabulary, and delegation of the wire mapping through a substitutable `transportWriter` interface.
18
+
19
+ - **Companion-suggestion mechanism (spec section 2).** Two additive optional top-level fields on `blueprint.json`: `providesRoles: string[]` (lower camelCase; paired scope:global ADR on the topic string is required) and `suggestedCompanions: [{role, reason}]` (reason has em-dash and emoji refusals to keep operator-facing prose plain). A blueprint declaring neither still loads clean (every shelf blueprint outside this train). Deterministic tier ladder resolver (applied provider > registered library provider > core-shelf provider) with a project-level pin file `rcf/companions.json` (schemaVersion 1, current pin per role, `pinnedAt` ISO-8601, rides git) overriding the library + shelf tiers. Two library candidates for one role with no pin refuse exit 3 with a three-path resolution message (adopt at apply via `--companion`, pin project-wide via `rcf define blueprint companions set`, or `rcf define blueprint library remove` one of the libraries). Backward-compatible: a service blueprint that does not declare `suggestedCompanions[]` produces an empty resolution and prints no block.
20
+
21
+ - **New CLI verbs and flags on `rcf define blueprint`.** `--companion <role>=<slug>` on `add` (repeatable) accepts `<libraryPrefix>:<slug>` for a library provider or a bare kebab slug for a shelf provider, preflight-refuses exit 2 when the named provider does not declare `providesRoles` containing the role (`--companion <role>=<slug>: blueprint '<slug>' does not declare providesRoles containing '<role>'.`), and writes the accepted pins to `rcf/companions.json`. `--no-companion-suggestions` on `add` suppresses both the preflight pin phase and the post-apply resolved suggestion block. `rcf define blueprint companions <slug>` prints the resolved companion set for an applied service blueprint with origin annotations (`already applied` / `pinned via rcf/companions.json` / `registered library '<prefix>' (overrides shelf provider <slug>)` / `shelf fallback (no registered library provides this role)`); refuses exit 3 on ambiguous libraries. `rcf define blueprint companions set <role> <slug>` writes a project-level pin; `unset <role>` removes it. `--json` on all three sub-verbs emits a machine-readable envelope preserving `suggestedCompanions[]` order.
22
+
23
+ - **Apply-time suggestion block.** After a successful `rcf define blueprint add` on a service blueprint that declares `suggestedCompanions[]`, stdout carries a `Suggested companions this blueprint recommends alongside it:` header followed by one line per role in the shape ` <role> -> <resolved-provider> (<origin>)`, then a `Apply either with: rcf define blueprint add <slug>` footer. The apply itself never adopts a companion (that is the operator's decision). Suppressed by `--no-companion-suggestions`.
24
+
25
+ - **`rcf define validate` refuses exit 3 on an unresolvable pin (spec section 5).** When `rcf/companions.json` pins a role to a slug that no applied blueprint, no registered library and no shelf blueprint provides, validate exits 3 with the ratified message shape `rcf/companions.json pins role '<role>' to '<slug>' but no such provider is applied, registered or on the shelf.`. An absent companions.json is not itself an error.
26
+
27
+ - **Standards-derived-blueprint discipline as authoring standard section 8a.** The rule is documented in `packages/rcf-lite/docs/blueprint-authoring.md` section 8a: MUST clauses become ACs where the clause binds a testable runtime or artefact behaviour; a MUST that binds an operator choice (choice-shaped) may land as a `recommendedDefault: true` ADR carrying the clause id on `standardsTraceClause`; SHOULD clauses become recommended ADR defaults; MAY clauses become elicited ADR choices; not-carried clauses stay allowed with a named reason. Three additive optional per-ADR-contribution fields on `blueprint.json`: `recommendedDefault: boolean`, `elicited: boolean`, `standardsTraceClause: string` (the standard clause identifier verbatim, or the sentinel `"generic enterprise practice"`). One additive optional blueprint-level field: `standardsTrace: [{id, version}]`. When `standardsTrace[]` is declared, every ADR contribution MUST carry a non-null `standardsTraceClause` (loader refusal shape: `blueprint '<slug>' declares standardsTrace but ADR contribution '<id>' has no standardsTraceClause; every ADR must reference a standard clause or the sentinel 'generic enterprise practice'.`, exit 2 at the CLI edge). No cross-check on clause severity to kind mapping (amendment A2 Baz 2026-09-04T12:20:31Z): the discipline is prose in section 8a, not code.
28
+
29
+ - **Roles registry (section 6a).** `logging` (shelf provider `observability-logging`), `errorHandling` (shelf provider `application-error-handling`). New roles land in the registry with a chunk-zero-style edit at ratification time, no loader change.
30
+
31
+ - **Companion-suggestion paragraph on the managed agent-instructions block.** `guidance/managed/agent-instructions-block.md` gains one paragraph under `How to talk to your operator` telling the agent to surface resolved companions verbally, prefer the library provider over the shelf when a library is registered, and never apply a companion without the operator's explicit go. `packages/rcf-lite/guidance/managed/agent-instructions-block.hash` regenerated to `129f4018f526ececaef7ae5bea19ecd72be03a957e2cf2ee3323e85f117f6cba`.
32
+
33
+ ### Changed
34
+
35
+ - **`application-api-rest`: 2.0.0 -> 2.1.0** (minor bump: additive `suggestedCompanions[{role: "logging", ...}, {role: "errorHandling", ...}]`; `ADR-304-application-api-rest-logging` retained on the blueprint without `scope: global` and re-titled `Historical: ... (superseded by observability-logging-ADR-1601 as the shelf-canonical logging global-topic owner from api-rest v2.1.0)`; `docs/topics.md` records the transfer and adds the two new blueprints to the shelf-wide band registry).
36
+ - **`application-spa`: 1.4.0 -> 1.5.0** (minor bump: additive `suggestedCompanions[{role: "logging", ...}, {role: "errorHandling", ...}]`; `docs/topics.md` shelf-wide band registry adds the two new blueprints).
37
+
38
+ ### Migration notes
39
+
40
+ - A project on `application-api-rest` v2.0.0 re-applies at v2.1.0 with `rcf define blueprint add <path-to>/blueprints/application-api-rest`; the apply is a minor bump (new suggestedCompanions field, ADR-304 retained without scope:global). Existing chains that referenced `ADR-304-application-api-rest-logging` in their own docs keep the reference intact (the contribution is retained, only its global-topic claim was dropped).
41
+ - A project that had superseded the `logging` topic at project level under v1.x keeps the supersede as historical context; `observability-logging` is the shelf-canonical claimant from this train onward, and a project that wants to align on the shelf provider re-applies both blueprints and drops any redundant historical resolution with `rcf define blueprint remove-resolution <adr-id>`.
42
+ - A project on `application-spa` v1.4.0 re-applies at v1.5.0 for the additive `suggestedCompanions` field.
43
+ - A project that wants the shelf `logging` role: `rcf define blueprint add <path-to>/blueprints/observability-logging`.
44
+ - A project that wants the shelf `errorHandling` role: `rcf define blueprint add <path-to>/blueprints/application-error-handling`.
45
+ - Dex's WSD library adopts the mechanism as a minor bump (0.4.0 -> 0.5.0 named as the adoption target in spec section 7): `wsd-logging` adds `providesRoles: ["logging"]`; `wsd-error-handling` adds `providesRoles: ["errorHandling"]`; `wsd-api-rest` adds `suggestedCompanions: [{role: "logging", ...}, {role: "errorHandling", ...}]`. Optional `standardsTrace[]` adoption formalises the prose standards-trace tables the library already ships.
46
+
47
+ ## [0.18.0] - 2026-09-04
48
+
49
+ Core shelf probe-path alignment. One shelf blueprint owns the probe-path binding across the whole shelf: `observability-probe-endpoints` v1.1.0 is the sole `scope: global` claimant on `healthProbes` and `readinessSemantics` and gains an optional Kubernetes-profile `/startup` path (off by default, enabled per project by `probeInterface.options.kubernetes.startup.enabled: true`). `observability-essentials` v2.0.0 drops its two `scope: global` topic claims, drops the shipped `/healthz` and `/readyz` defaults from TAC-801/802 (`path` becomes required config with no default), and adds the stable-coded `PROBE_INTERFACE_PATHS_MISSING` boot refusal for essentials-alone projects that forget the config. `application-api-rest` v2.0.0 drops the literal `/healthz/live`, `/healthz/ready`, and `/healthz/startup` bindings from REQ-006, US-2108, TAC-306, and the US-2103 versioning exemption, deferring to the resolved probe path set the probe-endpoints blueprint emits via TAC-1501 `getExemptPathSet` (or to the project-supplied `probeInterface.paths` in the essentials-alone case). `rcf doctor` grows a `probe-path-owner` check that fires when more than one applied blueprint teaches probe paths, and `rcf define blueprint remove-resolution <adr-id>` is the paired remedy verb that drops a single `manifest.resolutions[]` entry by its `resolvedByAdrId`. Spec: `projects/rcf-lite-wsd/specs/rcf-lite-probe-path-alignment-spec-2026-09-04.md` (amendments A1 to A3). Chain: REQ-012 with US-1201/1202/1203/1204 and TS-034/035/036/037 on the rcf-lite own tree.
50
+
51
+ ### Added
52
+
53
+ - **`rcf define blueprint remove-resolution <adr-id>`.** Drops a single `manifest.resolutions[]` entry by its `resolvedByAdrId`; writes nothing else and leaves the project-level ADR file at `rcf/adrs/<adr-id>.json` in place as historical context. Refuses exit 2 when `<adr-id>` is malformed or names no ADR on the project tree. Idempotent on re-run: when `<adr-id>` is a well-formed ADR id that still names an ADR on the tree but is no longer on any resolutions[] entry, prints `nothing to remove` and exits 0. This is the verb the `probe-path-owner` doctor check and spec section 9 name as the redundant-resolution remedy; before this change the message named a verb that did not exist. Chain: US-1204 with TS-037 on REQ-012 for the rcf-lite own tree; spec amendment A2 (2026-09-04, under the envelope after gate d-2026-09-04-016 finding 1); work item `w-2026-09-03-dave-021`.
54
+
55
+ - **Core shelf probe-path alignment (spec 2026-09-04).** One owner on the shelf for the probe-path binding. `observability-probe-endpoints` v1.1.0 is the sole shelf-wide `scope: global` claimant on `healthProbes` and `readinessSemantics` and adds an optional third Kubernetes-profile path `startup` (default `/startup`, off by default, enabled per project by `probeInterface.options.kubernetes.startup.enabled: true`) with paired ACs on US-14102 (AC-14102-4: three-path resolution) and US-14107 (AC-14107-4: three-entry auth-exempt list). `observability-essentials` v2.0.0 drops its `scope: global` claims on `healthProbes` and `readinessSemantics` (ADR-801 and ADR-802 become scope-local historical ADRs with a title change; content body stays for reader context per spec section 4), restates REQ-001/002 path-neutral, drops the `/healthz` and `/readyz` defaults from TAC-801/802 (`path` becomes required config with no shipped default), and gains AC-7101-4 and AC-7102-4 covering the stable-coded `PROBE_INTERFACE_PATHS_MISSING` boot refusal for essentials-alone projects. `application-api-rest` v2.0.0 drops the literal `/healthz/live`, `/healthz/ready`, and `/healthz/startup` bindings from REQ-006, US-2108 (all eight ACs), TAC-306, and US-2103 (versioning-exemption AC), deferring to the resolved probe path set that `observability-probe-endpoints` emits via TAC-1501 `getExemptPathSet` (or the project-supplied `probeInterface.paths` in the essentials-alone case). The three-way alignment is verified by `packages/rcf-lite/test/blueprint/probe-path-alignment.test.js`: 15 tests covering the nine assertions of spec section 7 across the six permutations of applying the three amended blueprints. `rcf doctor` gains a `probe-path-owner` check that fires when more than one applied blueprint teaches probe paths (spec section 9). Chain: REQ-012 with US-1201/1202/1203 and TS-034/035/036 on the rcf-lite own chain records the WHAT of the alignment for the dogfood tree. Trace: `projects/rcf-lite-wsd/specs/rcf-lite-probe-path-alignment-spec-2026-09-04.md` (sections 1 through 11); origin: Dex WSD escalation 2026-09-03; work item `w-2026-09-03-dave-021`.
56
+
57
+ ### Changed
58
+
59
+ - **`observability-probe-endpoints`: 1.0.0 -> 1.1.0** (minor bump per blueprint-authoring section 8: additive, no scope:global topic change).
60
+ - **`observability-essentials`: 1.0.0 -> 2.0.0** (major bump: drops two `scope: global` topic claims and reshapes REQ/TAC bodies).
61
+ - **`application-api-rest`: 1.0.0 -> 2.0.0** (major bump: shape change to REQ-006 and US-2108 AC set removes literal probe paths).
62
+
63
+ ### Migration notes
64
+
65
+ - A project that applied only `observability-essentials` v1.x: re-applying to v2.0.0 requires one line of configuration per environment (`probeInterface.paths.liveness` and `probeInterface.paths.readiness`) to satisfy the essentials boot wiring, unless the project also composes `observability-probe-endpoints` v1.1.0 or later (which supplies the paths automatically).
66
+ - A project that applied both `observability-essentials` v1.x and `observability-probe-endpoints` v1.0.0 with a project-level ADR superseding both on `healthProbes` and `readinessSemantics`: after re-apply, the resolutions are redundant historical context; `rcf doctor`'s `probe-path-owner` check flags them with the `rcf define blueprint remove-resolution` hint.
67
+ - A project that applied `application-api-rest` v1.x: FBSes and TCs that bind literal `/healthz/live`, `/healthz/ready`, or `/healthz/startup` strings need one edit each to bind the resolved path set; `rcf audit coverage --strict` catches project-side TCs that still hold the literal strings after re-apply.
68
+
9
69
  ## [0.17.0] - 2026-09-04
10
70
 
11
71
  The e2e verification contract for browser-facing projects. Verify pins `@playwright/mcp@0.0.80` with a preflight print and a `--playwright-mcp-version` override for emergency use; the effective pin lands on the report's runStats. Doctor gains four browser-facing checks (`playwright-present`, `browser-present`, `playwright-mcp-reachable`, `playwright-mcp-redundant`) routed by an applied blueprint's `browserSurface`, with a one-line skip on API-only projects. Init writes a Playwright MCP entry only when no scope-visible signature exists, falling back to a distinctly named `playwright-rcf` project-scope entry when it cannot prove absence, and opt-out via `--no-playwright-mcp`. `application-spa` v1.4.0 and `delivery-ci-workflows` v2.2.0 ship the paired `browserSurface` stories and the illustrative e2e job as a documentation contract per spec 2026-09-03 amendment A2; the runtime materialiser lands in a follow-up train.
@@ -1,4 +1,4 @@
1
- # REST API blueprint (v1.0.0)
1
+ # application-api-rest blueprint (v2.0.0)
2
2
 
3
3
  The second content blueprint on the rcf-build-lite blueprint mechanism (design brief v2, ratified; Phase 3 of the blueprint programme). Scope: a REST service, single deployable, versioned wire contract, no UI in scope. Composes with the application-spa blueprint by design, including two deliberate scope:global conflicts.
4
4
 
@@ -38,3 +38,7 @@ ADR-301 errorEnvelope, ADR-302 authModel, ADR-303 apiVersioning, ADR-304 logging
38
38
  ## Quality bar
39
39
 
40
40
  OpenAPI 3.1 generated from source with three-axis drift validation in the build; three k8s probes with specified schemas, security-auth-magic-link and log-noise exclusions, and documented failure modes; four auth classes enforced in middleware with x-auth-class contract validation; RFC 7807 on every failure path including pre-routing ones; cursor pagination with write-stability; strict unknown-parameter rejection; idempotency-key replay semantics with declared TTL; per-class rate limits with honest Retry-After; structured JSON logs, RED metrics, and OpenTelemetry spans off one shared request context; forward-only migrations with named reverts and a live /v1/_meta report; secrets never logged, PII redacted by stated policy, TLS outside development, CORS deny-by-default. Every bar is carried by ACs in the doc set, not by this README.
41
+
42
+ ## Breaking change in v2.0.0 (2026-09-04)
43
+
44
+ This blueprint no longer binds literal probe path strings. The three probe surfaces (liveness, readiness, startup) are served at the RESOLVED paths supplied by either the composed observability-probe-endpoints blueprint (Kubernetes profile default `/live`, `/ready`, and, when enabled, `/startup`; loadBalancer profile default `/health`) or by project configuration under `probeInterface.paths` in the essentials-alone case. REQ-006, US-2108 (all eight ACs), TAC-306, and US-2103 (versioning-exemption AC) were reshaped. Spec: `projects/rcf-lite-wsd/specs/rcf-lite-probe-path-alignment-spec-2026-09-04.md` section 5. Migration: project FBSes and TCs that bind literal `/healthz/live`, `/healthz/ready`, or `/healthz/startup` strings become one edit each to bind the resolved path set; `rcf audit coverage --strict` catches project-side TCs that still hold the literal strings after re-apply. See CHANGELOG.md.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "slug": "application-api-rest",
3
- "version": "1.0.0",
3
+ "version": "2.1.0",
4
4
  "category": "application",
5
5
  "contributions": [
6
6
  {
@@ -237,9 +237,7 @@
237
237
  {
238
238
  "id": "ADR-304-application-api-rest-logging",
239
239
  "kind": "adr",
240
- "path": "adrs/adr-304-application-api-rest-logging.json",
241
- "scope": "global",
242
- "topic": "logging"
240
+ "path": "adrs/adr-304-application-api-rest-logging.json"
243
241
  },
244
242
  {
245
243
  "id": "ADR-305-application-api-rest-pagination",
@@ -261,5 +259,15 @@
261
259
  "kind": "adr",
262
260
  "path": "adrs/adr-308-application-api-rest-rate-limiting.json"
263
261
  }
262
+ ],
263
+ "suggestedCompanions": [
264
+ {
265
+ "role": "logging",
266
+ "reason": "Every request pipeline pass writes a request-scoped log line; a logging companion supplies the factory the pipeline calls, and the shelf logging blueprint (observability-logging) is the fallback when no library provider is registered."
267
+ },
268
+ {
269
+ "role": "errorHandling",
270
+ "reason": "The error translator writes the wire envelope from the internal record; an error-handling companion supplies the record factory and the boundary that constructs it, and the shelf application-error-handling blueprint is the fallback when no library provider is registered."
271
+ }
264
272
  ]
265
273
  }
@@ -2,12 +2,12 @@
2
2
  "adrId": "ADR-304-application-api-rest-logging",
3
3
  "prdId": "PRD-001",
4
4
  "tadId": "TAD-001",
5
- "version": "1.0.0",
5
+ "version": "2.1.0",
6
6
  "status": "accepted",
7
- "title": "Structured JSON lines with request-scoped correlation as the project's primary logging shape",
7
+ "title": "Historical: structured JSON lines with request-scoped correlation as the project's primary logging shape (superseded by observability-logging-ADR-1601 as the shelf-canonical logging global-topic owner from api-rest v2.1.0)",
8
8
  "context": "A project has one primary logging shape; aggregation, alerting, retention, and redaction tooling are all built against it, and mixed shapes halve the value of every query. The decision covers the line format, the mandatory fields, and where correlation ids live.",
9
9
  "decision": "Logs are single-line JSON objects. Mandatory base fields: timestamp, level, message, service name. Every request-scoped line additionally carries the request id, and the trace id when a trace context exists. Request completion lines carry method, path template, status, duration, and auth class at the class's declared level. Redaction (application-api-rest-REQ-016) applies before emission. Prose, multi-line, and printf-style lines are not emitted by application code (application-api-rest-REQ-012, application-api-rest-US-2114).",
10
- "consequences": "Every operational question that logs can answer becomes a structured query keyed on the same ids the metrics and traces carry. The cost is log discipline in code review (no stray console prose) and marginally larger lines; both are prices the observability requirements already commit to. Any blueprint contributing log-emitting components to the same project joins this shape or the operator supersedes it project-wide.",
10
+ "consequences": "Every operational question that logs can answer becomes a structured query keyed on the same ids the metrics and traces carry. The cost is log discipline in code review (no stray console prose) and marginally larger lines; both are prices the observability requirements already commit to. Any blueprint contributing log-emitting components to the same project joins this shape or the operator supersedes it project-wide. From api-rest v2.1.0 the shelf-wide `logging` global topic is claimed only by `observability-logging` (ADR-1601-observability-logging-line-shape). The structured-JSON-with-correlation intent recorded here remains the intent for api-rest's server-side emission; the shelf-canonical topic owner is elsewhere. Projects that had superseded `logging` at project level in v1.x retain their supersede as historical context (see rcf define blueprint remove-resolution for the drop path when the resolution is genuinely redundant).",
11
11
  "alternativesConsidered": [
12
12
  {
13
13
  "name": "Human-readable prose lines",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "reqId": "application-api-rest-REQ-006",
3
3
  "prdId": "PRD-001",
4
- "title": "Kubernetes probe endpoints: liveness, readiness, and startup with specified schemas and exclusions",
5
- "description": "The service exposes three probe endpoints. GET /healthz/live returns 200 whenever the process can serve any request and performs no dependency checks. GET /healthz/ready returns 200 only when declared downstream dependencies (database, cache, queues) are reachable, and 503 with a body listing the failed checks otherwise. GET /healthz/startup returns 200 once initialisation (migrations, cache warm, config load) is complete. Each probe has a specified response schema, sits outside the auth middleware, is excluded from info-level metrics and log noise, and has a documented failure mode.",
4
+ "title": "Probe endpoints: liveness, readiness, and startup with specified schemas and exclusions (paths resolved by the composed observability-probe-endpoints blueprint or by project configuration)",
5
+ "description": "The service exposes three probe endpoints: liveness, readiness, and startup, with specified response schemas and exclusions. The liveness probe returns 200 whenever the process can serve any request and performs no dependency checks. The readiness probe returns 200 only when declared downstream dependencies (database, cache, queues) are reachable, and 503 with a body listing the failed checks otherwise. The startup probe returns 200 once initialisation (migrations, cache warm, config load) is complete and a non-200 with the pending steps before that. Each probe has a specified response schema, sits outside the auth middleware and rate limiter, is excluded from info-level metrics and log noise, and has a documented failure mode. The probe PATHS are supplied by the composed `observability-probe-endpoints` blueprint (Kubernetes profile default: `/live`, `/ready`, and, when enabled, `/startup`), or by project-level configuration under `probeInterface.paths` in the essentials-alone case; this blueprint does not bind literal paths. When probe-endpoints is composed the auth-middleware installer consumes the exempt path set that probe-endpoints emits and no other, so the auth-exempt entries exactly match the resolved probe path set.",
6
6
  "category": "functional",
7
7
  "domain": "operability",
8
8
  "priority": "must",
@@ -11,8 +11,8 @@
11
11
  "blueprint:application-api-rest",
12
12
  "category:06-probe-endpoints"
13
13
  ],
14
- "version": "1.0.0",
14
+ "version": "2.0.0",
15
15
  "status": "approved",
16
16
  "createdAt": "2026-08-19T10:00:00Z",
17
- "updatedAt": "2026-08-19T10:00:00Z"
17
+ "updatedAt": "2026-09-04T00:00:00Z"
18
18
  }
@@ -2,16 +2,17 @@
2
2
  "tacId": "TAC-306-application-api-rest-operability",
3
3
  "prdId": "PRD-001",
4
4
  "tadId": "TAD-001",
5
- "version": "1.0.0",
5
+ "version": "2.0.0",
6
6
  "status": "approved",
7
- "name": "Operability: probes, lifecycle, migrations, and the meta endpoint",
7
+ "name": "Operability: probes (at resolved paths), lifecycle, migrations, and the meta endpoint",
8
8
  "purpose": "Owns what an orchestrator and an operator need from the outside: the three probe endpoints, the initialisation lifecycle they report on, the forward-only migration machinery, and the /v1/_meta version report.",
9
9
  "responsibilities": [
10
- "Serve /healthz/live, /healthz/ready, and /healthz/startup with their specified schemas, exclusions, and documented failure modes (application-api-rest-REQ-006).",
11
- "Run the initialisation sequence (config load, migrations, cache warm) and expose its progress to the startup probe (AC-2108-4).",
10
+ "Serve the three probe surfaces (liveness, readiness, startup) at their resolved paths, with the specified schemas, exclusions, and documented failure modes; the path resolution is delegated to observability-probe-endpoints when composed (Kubernetes profile default /live, /ready, and, when enabled, /startup) or to project-level probeInterface.paths configuration when composed with observability-essentials alone (application-api-rest-REQ-006).",
11
+ "Run the initialisation sequence (config load, migrations, cache warm) and expose its progress to the resolved startup probe when the startup path is bound (AC-2108-4).",
12
12
  "Register and execute declared readiness checks against downstream dependencies, reporting per-check results in the ready body (AC-2108-2, AC-2108-3).",
13
13
  "Apply migrations strictly forward with named reverts and deterministic ordering (application-api-rest-REQ-014).",
14
- "Serve /v1/_meta reporting the live schema version and application version, sourced from the migration record, under a declared auth class (application-api-rest-US-2118)."
14
+ "Serve /v1/_meta reporting the live schema version and application version, sourced from the migration record, under a declared auth class (application-api-rest-US-2118).",
15
+ "Consume the resolved probe path set (produced by observability-probe-endpoints via TAC-1501 getExemptPathSet or derived from project probeInterface.paths configuration) as the exact auth-exempt list for the probe surfaces; refuse any hand-authored auth-exempt entry that duplicates or diverges from the resolved set (AC-2108-5)."
15
16
  ],
16
17
  "internalStructure": "A lifecycle coordinator owning initialisation state, a check registry the readiness probe iterates, and the migration runner; probe handlers are thin reads over this state, never performing work themselves.",
17
18
  "interfaces": [
@@ -23,7 +24,7 @@
23
24
  {
24
25
  "name": "probe endpoints",
25
26
  "kind": "http",
26
- "description": "The three /healthz/* endpoints and /v1/_meta, with their specced response schemas."
27
+ "description": "The three probe surfaces (liveness, readiness, startup) at their resolved paths, and /v1/_meta, with their specified response schemas. The path resolution is delegated to observability-probe-endpoints or to project-level probeInterface.paths configuration; this TAC binds NO literal path strings for the probe surfaces from v2.0.0."
27
28
  }
28
29
  ],
29
30
  "dependencies": [
@@ -40,7 +41,7 @@
40
41
  "description": "Probe outcomes land in the dedicated probe metric."
41
42
  }
42
43
  ],
43
- "tradeoffs": "Probe handlers reading pre-computed state (rather than checking dependencies inline) keeps probes cheap and non-amplifying under orchestrator polling, at the cost of a bounded staleness window in readiness reporting; the check interval is the tuning knob and is declared configuration.",
44
+ "tradeoffs": "Probe handlers reading pre-computed state (rather than checking dependencies inline) keeps probes cheap and non-amplifying under orchestrator polling, at the cost of a bounded staleness window in readiness reporting; the check interval is the tuning knob and is declared configuration. Path resolution is delegated so a project can compose the api-rest blueprint with either observability-probe-endpoints (elicit-and-adapt path set) or observability-essentials alone (project-supplied path set) without editing this TAC; the v2.0.0 breaking change is exactly this delegation.",
44
45
  "createdAt": "2026-08-19T10:00:00Z",
45
- "updatedAt": "2026-08-19T10:00:00Z"
46
+ "updatedAt": "2026-09-04T00:00:00Z"
46
47
  }
@@ -2,7 +2,7 @@
2
2
  "usId": "application-api-rest-US-2103",
3
3
  "prdId": "PRD-001",
4
4
  "reqId": "application-api-rest-REQ-003",
5
- "version": "1.0.0",
5
+ "version": "2.0.0",
6
6
  "status": "approved",
7
7
  "title": "Path-versioned contract with announced deprecation and a stated drop policy",
8
8
  "asA": "API consumer maintaining a long-lived integration",
@@ -14,7 +14,7 @@
14
14
  "description": "Every business endpoint lives under a major-version path prefix (/v1/...); only the probe endpoints and the documentation endpoints sit outside it.",
15
15
  "given": "the generated OpenAPI path inventory",
16
16
  "when": "paths are checked for the version prefix",
17
- "then": "every path is version-prefixed except /healthz/*, /openapi.*, and /docs",
17
+ "then": "every path is version-prefixed except the resolved probe paths, /openapi.*, and /docs",
18
18
  "testable": true,
19
19
  "scope": "runtime"
20
20
  },
@@ -59,5 +59,5 @@
59
59
  "TAC-304-application-api-rest-resource-layer"
60
60
  ],
61
61
  "createdAt": "2026-08-19T10:00:00Z",
62
- "updatedAt": "2026-08-19T10:00:00Z"
62
+ "updatedAt": "2026-09-04T00:00:00Z"
63
63
  }
@@ -2,62 +2,62 @@
2
2
  "usId": "application-api-rest-US-2108",
3
3
  "prdId": "PRD-001",
4
4
  "reqId": "application-api-rest-REQ-006",
5
- "version": "1.0.0",
5
+ "version": "2.0.0",
6
6
  "status": "approved",
7
- "title": "Liveness, readiness, and startup probes that tell the orchestrator the truth",
7
+ "title": "Liveness, readiness, and startup probes that tell the orchestrator the truth, at the resolved paths",
8
8
  "asA": "platform operator running the service under Kubernetes",
9
- "iWant": "three probe endpoints that each answer their one question honestly and cheaply",
9
+ "iWant": "three probe endpoints (at their resolved paths) that each answer their one question honestly and cheaply",
10
10
  "soThat": "the orchestrator restarts, routes, and rolls out instances on real signals",
11
11
  "acceptanceCriteria": [
12
12
  {
13
13
  "id": "AC-2108-1",
14
- "description": "GET /healthz/live returns 200 with the specified response schema whenever the process can serve any request, and performs no dependency checks whatsoever.",
15
- "given": "a running instance with a deliberately unreachable database",
16
- "when": "/healthz/live is called",
14
+ "description": "GET on the resolved liveness path returns 200 with the specified response schema whenever the process can serve any request, and performs no dependency checks whatsoever.",
15
+ "given": "a running instance with a deliberately unreachable database and the liveness path resolved either by observability-probe-endpoints (Kubernetes profile default /live) or by project configuration",
16
+ "when": "the resolved liveness path is called",
17
17
  "then": "it returns 200 against the specified schema, unaffected by the dependency outage",
18
18
  "testable": true,
19
19
  "scope": "runtime"
20
20
  },
21
21
  {
22
22
  "id": "AC-2108-2",
23
- "description": "GET /healthz/ready returns 200 only when every declared downstream dependency check (database, cache, queues) passes.",
24
- "given": "an instance with all declared dependencies reachable",
25
- "when": "/healthz/ready is called",
23
+ "description": "GET on the resolved readiness path returns 200 only when every declared downstream dependency check (database, cache, queues) passes.",
24
+ "given": "an instance with all declared dependencies reachable and the readiness path resolved (Kubernetes profile default /ready) or supplied by project configuration",
25
+ "when": "the resolved readiness path is called",
26
26
  "then": "it returns 200 with the specified schema listing each check as passing",
27
27
  "testable": true,
28
28
  "scope": "runtime"
29
29
  },
30
30
  {
31
31
  "id": "AC-2108-3",
32
- "description": "GET /healthz/ready returns 503 with a body enumerating the failed checks by name when any declared dependency is unreachable.",
33
- "given": "an instance with one declared dependency down",
34
- "when": "/healthz/ready is called",
32
+ "description": "GET on the resolved readiness path returns 503 with a body enumerating the failed checks by name when any declared dependency is unreachable.",
33
+ "given": "an instance with one declared dependency down and the readiness path resolved as above",
34
+ "when": "the resolved readiness path is called",
35
35
  "then": "it returns 503 and the body names the failing check while still listing the passing ones",
36
36
  "testable": true,
37
37
  "scope": "runtime"
38
38
  },
39
39
  {
40
40
  "id": "AC-2108-4",
41
- "description": "GET /healthz/startup returns 200 only after initialisation (migrations applied, cache warmed, config loaded) completes, and a non-200 with the pending steps before that.",
42
- "given": "an instance mid-initialisation and the same instance after initialisation",
43
- "when": "/healthz/startup is called in each state",
41
+ "description": "GET on the resolved startup path returns 200 only after initialisation (migrations applied, cache warmed, config loaded) completes, and a non-200 with the pending steps before that. The startup path is available when the composed observability-probe-endpoints blueprint enables it via `probeInterface.options.kubernetes.startup.enabled: true` or the project supplies `probeInterface.paths.startup` in configuration.",
42
+ "given": "an instance mid-initialisation and the same instance after initialisation, with the startup path resolved (Kubernetes profile default /startup when enabled) or supplied by project configuration",
43
+ "when": "the resolved startup path is called in each state",
44
44
  "then": "the mid-initialisation call is non-200 naming pending steps; the post-initialisation call is 200",
45
45
  "testable": true,
46
46
  "scope": "runtime"
47
47
  },
48
48
  {
49
49
  "id": "AC-2108-5",
50
- "description": "All three probes sit outside the auth middleware and outside rate limiting: they succeed with no credentials and are never 401, 403, or 429.",
51
- "given": "a running instance",
52
- "when": "each probe is called with no credentials at sustained frequency",
53
- "then": "every call is answered on probe semantics alone, never with an auth or rate-limit status",
50
+ "description": "All three probes sit outside the auth middleware and outside rate limiting: the auth-middleware installer consumes exactly the resolved probe path set (the same list observability-probe-endpoints emits via TAC-1501 getExemptPathSet, or the exact set derived from `probeInterface.paths` in the essentials-alone case), so each probe succeeds with no credentials and is never 401, 403, or 429; adjacent routes never fall under the same exemption.",
51
+ "given": "a running instance with the resolved probe path set exposed to the auth-middleware installer",
52
+ "when": "each probe is called with no credentials at sustained frequency AND an adjacent user-traffic route is also called unauthenticated",
53
+ "then": "every probe call is answered on probe semantics alone, never with an auth or rate-limit status; the adjacent route returns the auth middleware unauthenticated response",
54
54
  "testable": true,
55
55
  "scope": "runtime"
56
56
  },
57
57
  {
58
58
  "id": "AC-2108-6",
59
- "description": "Probe requests do not appear in info-level request logs and are excluded from RED endpoint metrics; probe outcomes are recorded under their own dedicated metric.",
60
- "given": "a period of steady probe traffic",
59
+ "description": "Probe requests (at their resolved paths) do not appear in info-level request logs and are excluded from RED endpoint metrics; probe outcomes are recorded under their own dedicated metric.",
60
+ "given": "a period of steady probe traffic on the resolved probe paths",
61
61
  "when": "info-level logs and endpoint metrics are inspected",
62
62
  "then": "probe requests appear in neither, and the dedicated probe-outcome metric carries their results",
63
63
  "testable": true,
@@ -65,18 +65,18 @@
65
65
  },
66
66
  {
67
67
  "id": "AC-2108-7",
68
- "description": "Each probe's response schema and failure mode are documented in the generated spec: what a failure body contains and what an operator should conclude from it.",
69
- "given": "the generated OpenAPI document",
68
+ "description": "The generated OpenAPI document names the three probe surfaces (liveness, readiness, startup) and their resolved paths, plus each probes success and failure schemas and its documented failure mode; the resolved paths are computed at documentation-generation time from the composed observability-probe-endpoints blueprint or from project configuration.",
69
+ "given": "the generated OpenAPI document produced for a project that has resolved its probe paths",
70
70
  "when": "the three probe entries are read",
71
- "then": "each declares its success and failure schemas and its documented failure mode",
71
+ "then": "each declares its success and failure schemas and its documented failure mode; every entry path is the resolved path (no legacy literal probe-path prefix appears in the generated document)",
72
72
  "testable": true,
73
73
  "scope": "runtime"
74
74
  },
75
75
  {
76
76
  "id": "AC-2108-8",
77
- "description": "Readiness reflects recovery: when a failed dependency becomes reachable again, /healthz/ready returns to 200 without a process restart.",
77
+ "description": "Readiness reflects recovery: when a failed dependency becomes reachable again, GET on the resolved readiness path returns to 200 without a process restart.",
78
78
  "given": "an instance whose dependency outage has been restored",
79
- "when": "/healthz/ready is called after restoration",
79
+ "when": "the resolved readiness path is called after restoration",
80
80
  "then": "it returns 200 without the process having restarted",
81
81
  "testable": true,
82
82
  "scope": "runtime"
@@ -86,5 +86,5 @@
86
86
  "TAC-306-application-api-rest-operability"
87
87
  ],
88
88
  "createdAt": "2026-08-19T10:00:00Z",
89
- "updatedAt": "2026-08-19T10:00:00Z"
89
+ "updatedAt": "2026-09-04T00:00:00Z"
90
90
  }
@@ -9,7 +9,7 @@ This file is the application-api-rest half of the cross-blueprint contract; the
9
9
  | `errorEnvelope` | ADR-301-application-api-rest-error-envelope | Reused verbatim from the application-spa vocabulary | DELIBERATE pairing: application-spa contributes ADR-204-application-spa-error-envelope on this topic. Applying both blueprints to one project surfaces the conflict for operator resolution. Expected resolution: one project-level ADR adopting RFC 7807 end to end, superseding both halves |
10
10
  | `authModel` | ADR-302-application-api-rest-auth-model | Reused verbatim from the application-spa vocabulary | DELIBERATE pairing with SPA's ADR-205-application-spa-auth-model (cookie-based sessions, client half). Expected resolution: one project-level ADR fixing the credential transport and mapping the client session model onto the four server classes |
11
11
  | `apiVersioning` | ADR-303-application-api-rest-api-versioning | Minted here; pre-cleared as unclaimed in the application-spa vocabulary | The one versioning strategy for the project's wire contract. Any blueprint contributing a versioned API surface must join or supersede this decision |
12
- | `logging` | ADR-304-application-api-rest-logging | Minted here; pre-cleared as unclaimed in the application-spa vocabulary | The project's primary logging shape. Any blueprint contributing log-emitting server components conflicts here by design |
12
+ | `logging` (retained historical) | ADR-304-application-api-rest-logging (no scope:global from v2.1.0) | Transferred to observability-logging-ADR-1601 as the shelf-canonical owner from v2.1.0 | The project's primary logging shape now sits on the shelf logging blueprint; the api-rest ADR-304 is retained as historical context and the api-rest blueprint no longer claims the global topic. Apply observability-logging 1.0.0 or later (or a registered library-side provider) to satisfy the `logging` role api-rest suggests |
13
13
 
14
14
  Rules for new topics (inherited from the application-spa vocabulary, restated as law): lower camel case, one concept per topic, no version suffixes. A topic names the decision area, not the chosen answer. Do not mint variants of existing strings (`errorShape`, `auth`, `apiVersion`, `logShape` are all wrong).
15
15
 
@@ -22,20 +22,22 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
22
22
  | Blueprint | US band | ADR/TAC suffix block | Status | Global topics |
23
23
  |---|---|---|---|---|
24
24
  | application-spa | 1101-1899 | 2xx | shipped v1.3.0 | `clientRouting`, `theming`, `clientState`, `errorEnvelope`, `authModel` |
25
- | application-api-rest | 2101-2899 | 3xx | shipped v1.0.0 | `errorEnvelope`, `authModel`, `apiVersioning`, `logging` |
25
+ | application-api-rest | 2101-2899 | 3xx | shipped v2.1.0 (suggestedCompanions added) | `errorEnvelope`, `authModel`, `apiVersioning` |
26
26
  | security-auth-magic-link | 3101-3899 | 5xx | shipped v1.0.0 | `authModel` |
27
27
  | email-smtp-resend | 4101-4899 | 4xx | shipped v1.0.0 | none |
28
28
  | 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` |
29
29
  | persistence-data-sqlite | 5101-5899 | 6xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
30
30
  | delivery-ci-workflows | 6101-6899 | 7xx | shipped v2.0.0 (renamed from ci-pipeline) | `ciGates`, `strictCoverageGate`, `releaseArtefacts` |
31
- | observability-essentials | 7101-7899 | 8xx | shipped v1.0.0 | `healthProbes`, `readinessSemantics`, `statusPageContract` |
31
+ | observability-essentials | 7101-7899 | 8xx | shipped v2.0.0 | `statusPageContract` |
32
32
  | security-secrets-management | 8101-8899 | 9xx | shipped v1.0.0 | `secretsSource` |
33
33
  | security-auth-clerk | 9101-9899 | 10xx | shipped v1.0.0 | `authModel` |
34
34
  | security-auth-oauth2 | 10101-10899 | 11xx | shipped v1.0.0 | `authModel` |
35
35
  | security-auth-keycloak | 11101-11899 | 12xx | shipped v1.0.0 | `authModel` |
36
36
  | deploy-cloudflare-workers | 12101-12899 | 13xx | shipped v1.0.0 | `deploymentTarget` |
37
37
  | persistence-data-d1 | 13101-13899 | 14xx | shipped v1.0.0 | `persistenceStore`, `migrationDiscipline` |
38
- | observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.0.0 | `healthProbes`, `readinessSemantics` |
38
+ | observability-probe-endpoints | 14101-14899 | 15xx | shipped v1.1.0 | `healthProbes`, `readinessSemantics` |
39
+ | observability-logging | 15101-15899 | 16xx | shipped v1.0.0 | `logging` |
40
+ | application-error-handling | 16101-16899 | 17xx | shipped v1.0.0 | `errorHandling` |
39
41
 
40
42
  Suffix-family ids (ADR, TAC): SPA numbers in the 2xx range, this package takes 3xx (ADR-301 to ADR-308, TAC-301 to TAC-306); the next blueprint should take 4xx.
41
43
 
@@ -26,7 +26,7 @@ Any project whose primary surface is an HTTP API meant to be consumed by clients
26
26
 
27
27
  ## What a good outcome looks like
28
28
 
29
- Attack the finished service from the outside and try to catch it lying: fetch /docs and call an endpoint straight from the spec, send garbage JSON, reuse an idempotency key with a different body, hammer a public endpoint past its limit, kill the database and watch /healthz/ready tell the truth while /healthz/live stays up, grep the logs for the bearer token you just used. A build that honours this doc set answers every one of those correctly. That is the measure: what an integrating client and an on-call engineer get out of the box.
29
+ Attack the finished service from the outside and try to catch it lying: fetch /docs and call an endpoint straight from the spec, send garbage JSON, reuse an idempotency key with a different body, hammer a public endpoint past its limit, kill the database and watch the resolved readiness path tell the truth while the resolved liveness path stays up, grep the logs for the bearer token you just used. A build that honours this doc set answers every one of those correctly. That is the measure: what an integrating client and an on-call engineer get out of the box.
30
30
 
31
31
  ## Your decisions that remain open
32
32
 
@@ -39,3 +39,7 @@ Attack the finished service from the outside and try to catch it lying: fetch /d
39
39
  ## Cost honesty
40
40
 
41
41
  This doc set makes an API slower to declare done, on purpose: 117 criteria is the price of "no endpoint ships undocumented, unmeasured, or unguarded". If you are prototyping a throwaway integration, that price is wrong; skip the blueprint rather than opting out of half of it. If other people's code will call this service, the price is the product.
42
+
43
+ ## Composing with observability-probe-endpoints and observability-essentials (v2.0.0)
44
+
45
+ From v2.0.0 this blueprint no longer binds literal probe path strings. The three probe surfaces (liveness, readiness, startup) are served at the RESOLVED paths supplied by either the composed observability-probe-endpoints blueprint (Kubernetes profile default `/live`, `/ready`, and, when enabled, `/startup`; `loadBalancer` profile default `/health`) or by project configuration under `probeInterface.paths` in the essentials-alone case. The auth-middleware installer consumes exactly the exempt path set that observability-probe-endpoints emits via TAC-1501 `getExemptPathSet` (or the exact set derived from `probeInterface.paths` in the essentials-alone case); adjacent routes never fall under the same exemption. The generated OpenAPI document names each probe surface and its resolved path at documentation-generation time. The three-way composition invariants live in `packages/rcf-lite/test/blueprint/probe-path-alignment.test.js`.
@@ -0,0 +1,42 @@
1
+ # Error-handling blueprint (v1.0.0)
2
+
3
+ Transport-agnostic error-handling contract for a rcf-lite application. General enterprise practice, no vendor lock-in. Mints the `errorHandling` global topic on `ADR-1701-application-error-handling-record-shape` (distinct from `errorEnvelope`, which stays with application-api-rest as the REST wire shape). Provides the `errorHandling` role for the companion-suggestion mechanism. Suggests the `logging` companion so emission threads through the applied logging factory.
4
+
5
+ ## Apply
6
+
7
+ ```
8
+ rcf define blueprint add <path-to>/blueprints/application-error-handling
9
+ ```
10
+
11
+ Applies namespaced contributions into the project tree and records `manifest.blueprints[]`.
12
+
13
+ ## Anatomy
14
+
15
+ | Piece | Where | What |
16
+ |---|---|---|
17
+ | Metadata | `blueprint.json` | Slug, version 1.0.0, category `application`, `providesRoles: ["errorHandling"]`, `suggestedCompanions: [{role: "logging", ...}]`, and the 16 contributions with scope/topic on `ADR-1701` |
18
+ | Doc set | `contributions/` | 4 REQs, 7 USs (9 ACs), 2 TACs, 3 ADRs, schema-valid and namespaced |
19
+ | Record schema | `assets/schemas/error-record.schema.json` | JSON Schema for the internal record shape |
20
+ | Guide | `guide/application-error-handling.md` | Operator-facing: when to reach, when not, mechanism-reach gaps |
21
+ | Coordination vocabulary | `docs/topics.md` | The `errorHandling` global topic distinct from `errorEnvelope`, the shelf-wide id band registry update |
22
+
23
+ ## What it contributes, and what it deliberately does not
24
+
25
+ Contributed: REQ, US (with inline ACs), TAC, ADR. Adherence is expressed as ACs; the blueprint ships no test files.
26
+
27
+ Deliberately not contributed: a transport wire envelope (application-api-rest owns REST via `errorEnvelope`; a future gRPC or message-consumer blueprint claims its own); a retry policy implementation (the record carries category; the applying platform's retry surface reads it); a substitute for the logging companion's own field-level redaction (the record's context field is redacted through the applied logging companion's redaction boundary, per AC-16104-1).
28
+
29
+ ## The one global decision
30
+
31
+ `ADR-1701-application-error-handling-record-shape` ships `scope: global` on topic `errorHandling`. This is the project's internal error record shape (six fields: code, category, message, correlationId, cause, context). A composing blueprint that wants a different internal record shape conflicts here by design. `errorHandling` is distinct from `errorEnvelope` (owned by application-api-rest for REST); the internal record is one project decision above every transport-specific wire envelope.
32
+
33
+ See `docs/topics.md` for the exact strings, the distinction from `errorEnvelope`, and the AC id band allocation (16101-16899, ADR/TAC suffix block 17xx).
34
+
35
+ ## Quality bar
36
+
37
+ Process-level uncaught-exception boundary and framework-level pipeline boundary both registered; every record constructed through TAC-1702's factory with code and category required; context redacted at construction time using the applied logging companion's redaction categories; cause chain preserved across nested wrappings; classification vocabulary transient / permanent / unknown (elicited additions per project); transport response mapping delegated through the substitutable transportWriter interface (ADR-1703); emission routed through the applied logging companion factory with a documented stderr fallback when no companion is applied. Every bar is carried by ACs in the doc set.
38
+
39
+ ## Known mechanism-reach gaps
40
+
41
+ - **Boundary coverage.** The blueprint cannot prove every code path routes through the boundary; a bare `console.error` or a `process.exit` from any code path bypasses the boundary. Project-side workaround: a grep gate as a project-authored TC bound to `AC-16106-1`.
42
+ - **Classification integrity.** The vocabulary is enforced at the factory (code + category required), but the correctness of the category the caller chose is not machine-checkable. A caller who classifies every failure as `unknown` still passes the shape gate; the blueprint's guide names the diagnostic pattern.
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://rcf-lite/blueprints/application-error-handling/schemas/error-record.schema.json",
4
+ "title": "Internal error record",
5
+ "description": "The shape TAC-1702's factory returns and every downstream consumer reads. Frozen; see ADR-1701.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["code", "category", "message", "correlationId", "context"],
9
+ "properties": {
10
+ "code": { "type": "string", "minLength": 1, "description": "Project-elicited machine-readable identifier." },
11
+ "category": { "type": "string", "minLength": 1, "description": "One of the ADR-1702 classification vocabulary." },
12
+ "message": { "type": "string", "minLength": 1, "description": "Human-readable message; no PII." },
13
+ "correlationId": { "type": ["string", "null"], "description": "Stamped from the ambient logging context at construction." },
14
+ "cause": { "anyOf": [ { "type": "null" }, { "$ref": "#" } ], "description": "Nested record for the wrapped cause, or null." },
15
+ "context": { "type": "object", "description": "Redacted at construction using the applied logging companion's redaction categories." }
16
+ }
17
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "slug": "application-error-handling",
3
+ "version": "1.0.0",
4
+ "category": "application",
5
+ "providesRoles": ["errorHandling"],
6
+ "suggestedCompanions": [
7
+ { "role": "logging", "reason": "The internal error record emits through the logging companion, not direct stdout or stderr writes; a logging companion supplies the factory the boundary calls." }
8
+ ],
9
+ "contributions": [
10
+ { "id": "application-error-handling-REQ-001", "kind": "req", "path": "requirements/application-error-handling-req-001.json" },
11
+ { "id": "application-error-handling-REQ-002", "kind": "req", "path": "requirements/application-error-handling-req-002.json" },
12
+ { "id": "application-error-handling-REQ-003", "kind": "req", "path": "requirements/application-error-handling-req-003.json" },
13
+ { "id": "application-error-handling-REQ-004", "kind": "req", "path": "requirements/application-error-handling-req-004.json" },
14
+ { "id": "application-error-handling-US-16101", "kind": "us", "path": "user-stories/application-error-handling-us-16101.json" },
15
+ { "id": "application-error-handling-US-16102", "kind": "us", "path": "user-stories/application-error-handling-us-16102.json" },
16
+ { "id": "application-error-handling-US-16103", "kind": "us", "path": "user-stories/application-error-handling-us-16103.json" },
17
+ { "id": "application-error-handling-US-16104", "kind": "us", "path": "user-stories/application-error-handling-us-16104.json" },
18
+ { "id": "application-error-handling-US-16105", "kind": "us", "path": "user-stories/application-error-handling-us-16105.json" },
19
+ { "id": "application-error-handling-US-16106", "kind": "us", "path": "user-stories/application-error-handling-us-16106.json" },
20
+ { "id": "application-error-handling-US-16107", "kind": "us", "path": "user-stories/application-error-handling-us-16107.json" },
21
+ { "id": "TAC-1701-application-error-handling-boundary", "kind": "tac", "path": "tacs/tac-1701-application-error-handling-boundary.json" },
22
+ { "id": "TAC-1702-application-error-handling-record-factory", "kind": "tac", "path": "tacs/tac-1702-application-error-handling-record-factory.json" },
23
+ { "id": "ADR-1701-application-error-handling-record-shape", "kind": "adr", "path": "adrs/adr-1701-application-error-handling-record-shape.json", "scope": "global", "topic": "errorHandling" },
24
+ { "id": "ADR-1702-application-error-handling-classification-vocabulary", "kind": "adr", "path": "adrs/adr-1702-application-error-handling-classification-vocabulary.json", "recommendedDefault": true, "elicited": true, "standardsTraceClause": "generic enterprise practice" },
25
+ { "id": "ADR-1703-application-error-handling-transport-mapping", "kind": "adr", "path": "adrs/adr-1703-application-error-handling-transport-mapping.json", "recommendedDefault": true, "elicited": false, "standardsTraceClause": "generic enterprise practice" }
26
+ ]
27
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "adrId": "ADR-1701-application-error-handling-record-shape",
3
+ "prdId": "PRD-001",
4
+ "tadId": "TAD-001",
5
+ "version": "1.0.0",
6
+ "status": "accepted",
7
+ "title": "Internal error record shape: code, category, message, correlationId, cause chain, redacted context",
8
+ "context": "Without a shared record shape, every consumer of error data (log ingestion pipelines, alerting rules, wire-response mappers, retry policies) invents its own view. The record loses information at each hop and downstream tools reconstruct it from string parsing. The 'errorHandling' global topic is minted here (distinct from 'errorEnvelope', which stays with application-api-rest as the REST wire shape): errorHandling is the internal record shape and the uncaught-exception boundary; errorEnvelope is the wire format one transport chooses to translate the record into.",
9
+ "decision": "The internal error record has exactly six fields: code (string, machine-readable identifier the project elicits at record creation; the vocabulary is project-side), category (one of the ADR-1702 classification vocabulary), message (human-readable string, no PII), correlationId (stamped from the ambient logging context at construction time; may be null), cause (nested record for the wrapped cause, or null), context (redacted object per the applied logging companion's redaction categories). Records are constructed only through TAC-1702's factory; the factory refuses code or category missing.",
10
+ "consequences": "Log-side queries by code, category or correlationId all work off the shared field names. The wire-response mapper (ADR-1703) writes one envelope from the record without a per-project mapping table. The retry policy reads category at one place. The cause chain is preserved across wrappings without any consumer's per-layer knowledge. A future transport blueprint (gRPC, message consumer) claims its OWN transport-specific errorEnvelope topic; the internal record shape stays one project decision above.",
11
+ "alternativesConsidered": [
12
+ {
13
+ "name": "Free-form record with a message-plus-metadata bag",
14
+ "summary": "The record has message and a metadata object; every consumer looks up its own fields.",
15
+ "reasonNotChosen": "Loses the shared vocabulary and forces every consumer to invent field names; the failure mode is a per-consumer view that drifts silently."
16
+ },
17
+ {
18
+ "name": "Merge errorHandling and errorEnvelope into one global topic",
19
+ "summary": "One topic governs both the internal record and the wire envelope.",
20
+ "reasonNotChosen": "Conflates two decisions the mechanism gets to make separately: the internal record shape is one decision (this blueprint owns it); the wire envelope is a transport-specific decision (application-api-rest owns errorEnvelope for REST). Merging them forces a project to change the wire when it changes the internal record and vice versa."
21
+ }
22
+ ],
23
+ "createdAt": "2026-09-04T12:20:00Z",
24
+ "updatedAt": "2026-09-04T12:20:00Z"
25
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "adrId": "ADR-1702-application-error-handling-classification-vocabulary",
3
+ "prdId": "PRD-001",
4
+ "tadId": "TAD-001",
5
+ "version": "1.0.0",
6
+ "status": "accepted",
7
+ "title": "Classification vocabulary: transient, permanent, unknown by recommended default; operator elicits additions",
8
+ "context": "Retry policies are the difference between a self-healing system and a burning one. Classification at the source (where the code knows whether the failure was a transient network blip or a permanent authorisation refusal) puts the decision where the information is; classifying downstream on the wire is the source of most retry-storm outages. The recommended default set is deliberately small; per-domain additions land through elicited additions.",
9
+ "decision": "The recommended default classification vocabulary is transient, permanent, unknown. Every constructed record carries one string from this set. The applying operator elicits additional categories at apply (kebab or dotted-namespace grammar; refused with a boot error otherwise); elicited additions apply alongside the defaults. The transport response mapper reads the category and applies the per-class contract.",
10
+ "consequences": "Retry policies wire once against the shared vocabulary; per-project additions (rate-limited, quota-exceeded, dependency-degraded) fit in the same mechanism. The three defaults cover the majority of real-world classification decisions; a project that finds itself using unknown for everything has a diagnostic gap the classification is meant to catch.",
11
+ "alternativesConsidered": [
12
+ {
13
+ "name": "Enumerate an exhaustive vocabulary",
14
+ "summary": "The blueprint ships every possible category (auth, timeout, dependency, quota, ...) as recommended defaults.",
15
+ "reasonNotChosen": "Reliably fights every project's domain vocabulary; the three defaults plus elicited additions gives a working floor and a project-side extension path in the same round."
16
+ }
17
+ ],
18
+ "createdAt": "2026-09-04T12:20:00Z",
19
+ "updatedAt": "2026-09-04T12:20:00Z"
20
+ }