Forward Express app extension points through HalEngineConfig - #85
lore-agent[bot] wants to merge 10 commits into
Conversation
Three failing acceptance tests for issue #38: - createApp rootRoutes: GET / via rootRoutes handler returns 404 (should be 200) because rootRoutes is absent from HalAppOptions. - createApp rootRoutes coexistence: rootRoutes /health returns 404 (should be {source:'root'}) for same reason. - createHalEngine forwarding: GET /hal/ping returns 404 (should be 200) because createHalEngine does not pass transport.additionalRoutes to createApp. Adds App Extension Points section to specs/hal-engine-architecture/spec.md with the three cited statements and DoD in .lore/dod.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔍 Lore Spec Impact — advisoryThis PR touches 17 statement(s) across 2 spec(s), and changes the validating tests alongside every one of them. HAL Engine on npm · 7 statement(s)
The logger a consumer supplies is the one that gets used
validated by The logger a consumer supplies is the one that gets used
validated by The logger a consumer supplies is the one that gets used
validated by Two config options that were declared and dropped
validated by Two config options that were declared and dropped
validated by Two config options that were declared and dropped
validated by Two config options that were declared and dropped
validated by Weaker signals (10) — linked by a spec, not proven by a test runHAL Engine chat routes · 10 statement(s)
How the routes are mounted
validated by How the routes are mounted
validated by How the routes are mounted
validated by How the routes are mounted
validated by How the routes are mounted
validated by How the routes are mounted
validated by How the routes are mounted
validated by How the routes are mounted
validated by How the routes are mounted
validated by How the routes are mounted
validated by 28 new statement(s) have no test link yet. Deterministic · graph baseline unknown (no ingested test run has stamped this repo) — line-precise coupling skipped · no tests run by this check |
…t fields Add `rootRoutes?: (router: Router) => void` to `HalAppOptions` in `createApp.ts`, mounted after the basePath router and before the 404 catch-all. Forward `additionalRoutes`, `rootRoutes`, and `errorHandler` from `HalEngineConfig.transport` to `createApp` in `createHalEngine`. Remove now-unnecessary `as any` cast from config.test.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…est uncited tests Six tests added in the previous round had no spec-link citation; the re-lint/require-spec-link rule fails the build on any uncited test. Add an Engine Lifecycle section to the architecture spec with one statement per test, each carrying the required ([validated by ...]) link. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previous round added tests to src/config.test.ts, shifting seven existing line-number anchors in specs/hal-engine-npm-release/spec.md by one. CI's spec-anchor check reported all seven as stale/rotten. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
check-doc-blocks.mjs requires each <!-- doc-block: ... --> comment to be immediately followed by a ```typescript fence (no blank line). Eight fences in specs/hal-engine-architecture/spec.md had an intervening blank line, causing the Documented code blocks CI step to fail with 16 findings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add CHANGELOG.md entry for the three new transport options (additionalRoutes, rootRoutes, errorHandler). Update README.md transport interface listing with the three new fields. Update example/full-config.ts with commented examples of all three, then regenerate the full-config doc-block in docs/getting-started.md via npm run docs:fix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
re-lint/max-comment-lines treats consecutive trailing // comments as a block; reduce to a single line on errorHandler only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
check-doc-blocks.mjs requires the marker comment and the typescript fence to be on consecutive lines; blank lines between them were causing 10 findings (5 marker/fence mismatches, 5 unmarked fences). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
createAppalready declaredadditionalRoutesanderrorHandleronHalAppOptions, butcreateHalEnginenever forwarded them tocreateApp, and there was no way for a consumer to mount routes at/— every forwarded route landed underbasePath. The practical consequence: a consumer who wanted to serve a front-end bundle beside the API either ran a second service or hand-built their own Express app, bypassing the transport layer entirely. Adding a route aftercreateHalEnginereturned also did not work becausecreateAppregisters a terminal 404 catch-all before returning, and Express matches routes in registration order.This change adds
rootRoutes?: (router: Router) => voidtoHalAppOptionsinsrc/transport/createApp.ts. The callback receives a freshRoutermounted after thebasePathrouter and before the catch-all 404, so a handler there can serveGET /whileGET {basePath}/healthstill answers independently.src/config.tsis extended to declareadditionalRoutes,rootRoutes, anderrorHandleronHalEngineConfig['transport']and forward all three through tocreateApp. TheadditionalRoutesanderrorHandlerfields existed onHalAppOptionsbefore this branch; the only runtime gap was thatcreateHalEnginenever passed them.rootRoutesis new at both layers.Neither callback is gated by
auth.http; both inherit the CORS, JSON body-parsing, and cookie-parsing middleware thatcreateAppmounts unconditionally. The post-construction limitation is preserved and now tested: a route added toengine.appaftercreateHalEnginereturns always answers 404 because the catch-all was registered first.The ticket's strategy called for
directimplementation —createAppandcreateHalEngineare both callable today, and fixing the forwarding gap is mechanical. No deviation from that strategy.Three acceptance tests define done, all in the "Done when these pass" list in
.lore/dod.md:createApp.test.tsline 128:mounts a rootRoutes handler at / before the catch-all 404— arootRoutescallback servingGET /coexists with the engine'sGET /hal/health.createApp.test.tsline 143:lets rootRoutes at /health and the basePath health answer independently— the same path prefix at root and underbasePathroutes to each handler separately.config.test.tsline 109:forwards transport.additionalRoutes to createApp so the route mounts under basePath—createHalEnginewithtransport.additionalRoutesregisteringGET /pingmakesGET /hal/pinganswer 200.All three cite their statements in
specs/hal-engine-architecture/spec.mdwith inline([validated by ...])links. The spec also gained a new## Engine Lifecyclesection that cites the six pre-existingconfig.test.tstests that previously lacked spec links, closing there-lint/require-spec-linkgap those tests had opened.specs/hal-engine-architecture/spec.mdgains### App extension pointsstating the two mount points, that neither is covered byauth.http, that both inherit CORS and body/cookie parsing, thatengine.appcannot be extended aftercreateHalEnginereturns, and the default error behaviour and GDPR / NIS-2 notes the ticket required.Documentation changes:
README.mdanddocs/getting-started.mdshow all three newtransportfields with one-line comments. Thegetting-started.mdlisting is generated fromexample/full-config.tsunder<!-- doc-block: example/full-config.ts#full-config -->; the three fields were added there and the doc block regenerated withnpm run docs:fix.CHANGELOG.mdcarries an[Unreleased]entry written for an npm reader rather than a git log reader.Items from the ticket's acceptance criteria that are out of scope for this branch and remain open: a safe default JSON error handler inside the engine ("Answer unhandled HTTP errors with a safe JSON response"), per-route authentication in the engine, and deferring the 404 or any post-hoc extension of
engine.app.Refs #38
Lore-Task: 8eb920ee-7d28-4b4d-a591-f8a0865a7f69