instar 1.3.241 → 1.3.243
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/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +1 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +1 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +2 -1
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +6 -1
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/middleware.d.ts +9 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +43 -2
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +9 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +64 -64
- package/src/scaffold/templates.ts +1 -0
- package/upgrades/1.3.242.md +26 -0
- package/upgrades/1.3.243.md +25 -0
- package/upgrades/apprenticeship-manual-cycle-write-path.eli16.md +9 -0
- package/upgrades/double-send-route-guard.eli16.md +26 -0
- package/upgrades/side-effects/apprenticeship-manual-cycle-write-path.md +52 -0
- package/upgrades/side-effects/double-send-route-guard.md +66 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# ELI16 — Double-send route guard
|
|
2
|
+
|
|
3
|
+
Some server routes can accidentally send an HTTP response and then keep running. If later code tries
|
|
4
|
+
to send another response, Express throws the familiar "Cannot set headers after they are sent to the
|
|
5
|
+
client" error. The original bug is usually a missing `return` after an early `res.json()` or
|
|
6
|
+
`res.status(...).json()` branch.
|
|
7
|
+
|
|
8
|
+
This change adds two protections.
|
|
9
|
+
|
|
10
|
+
First, the server now installs a duplicate-response guard before routes run. If a handler has already
|
|
11
|
+
committed a response and later tries to send another JSON/send-style response, the guard logs the
|
|
12
|
+
duplicate with a stack and suppresses the second send instead of letting it throw through the request
|
|
13
|
+
path.
|
|
14
|
+
|
|
15
|
+
Second, the central Express error handler now checks whether the response was already sent. If an
|
|
16
|
+
error arrives after a route has already replied, it logs the late error with stack context and returns
|
|
17
|
+
without trying to send a second 500 response.
|
|
18
|
+
|
|
19
|
+
There is also a source-level audit test for the classic missing-return shape: an early branch that
|
|
20
|
+
sends a response without returning, followed by a later direct response in the same route handler. The
|
|
21
|
+
test includes a bad fixture to prove the detector catches the pattern, then scans the current server
|
|
22
|
+
route sources to keep that shape out.
|
|
23
|
+
|
|
24
|
+
This does not change successful API responses. It only changes what happens after code tries to send
|
|
25
|
+
again after a response is already committed: the server logs the mistake and preserves the first
|
|
26
|
+
response.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Side-Effects Review - Apprenticeship manual cycle write path
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `apprenticeship-manual-cycle-write-path`
|
|
4
|
+
**Date:** 2026-06-03
|
|
5
|
+
**Author:** codey
|
|
6
|
+
|
|
7
|
+
## Summary of the change
|
|
8
|
+
|
|
9
|
+
Current `JKHeadley/main` already had `POST /apprenticeship/cycles`, so this change does not add a second route. It finishes the manual/overseer write path around that existing route:
|
|
10
|
+
|
|
11
|
+
- `src/server/routes.ts` now validates that manual cycle POST bodies are objects and that `channel`, when present, is one of the four store-supported values.
|
|
12
|
+
- `src/server/CapabilityIndex.ts` now surfaces the apprenticeship cycle endpoints in `/capabilities`.
|
|
13
|
+
- `src/scaffold/templates.ts` adds a CLAUDE.md awareness blurb for manual cycle recording.
|
|
14
|
+
- `src/core/PostUpdateMigrator.ts` mirrors that blurb for existing agents that do not yet have the Apprenticeship Program section.
|
|
15
|
+
- `src/data/builtin-manifest.json` is regenerated after the route/source changes.
|
|
16
|
+
- `upgrades/next/apprenticeship-manual-cycle-write-path.md` records the release-note fragment required by the publish gate.
|
|
17
|
+
- Route and capability tests cover strict channel validation, channel persistence, manual overseer cycle capture, and discovery.
|
|
18
|
+
|
|
19
|
+
## Side effects and blast radius
|
|
20
|
+
|
|
21
|
+
The only behavior change on the write path is stricter HTTP validation. A malformed manual request with an unknown channel now receives HTTP 400 instead of being written as `unknown`. The lower-level `ApprenticeshipCycleStore.record()` behavior is unchanged, so legacy rows and automated/non-HTTP callers still normalize invalid or missing channels to `unknown`.
|
|
22
|
+
|
|
23
|
+
The route remains persistence-only. It does not mutate apprenticeship instance status, does not run lifecycle gates, and does not decide whether a cycle was good. It only writes the row to the cycle store, and existing role-coverage logic interprets those rows afterward.
|
|
24
|
+
|
|
25
|
+
Capability discovery changes only metadata returned by `/capabilities`; no new auth surface or prefix classification is introduced. `/apprenticeship` was already a public capability prefix, so no `INTERNAL_PREFIXES` entry is needed or appropriate.
|
|
26
|
+
|
|
27
|
+
The template and migrator changes alter generated/updated CLAUDE.md guidance text. They do not execute operational work. Existing installs that already have an Apprenticeship Program section are still protected by the current idempotency marker and will not be double-patched by this migration.
|
|
28
|
+
|
|
29
|
+
## Risks considered
|
|
30
|
+
|
|
31
|
+
- **Breaking automated mentor ticks:** low. The automated call site writes through the store, not the HTTP route, and does not provide a channel today. Store defaulting remains unchanged.
|
|
32
|
+
- **Rejecting useful manual records because of a typo:** intentional. Manual/overseer HTTP writes should fail loudly when the channel is not one of the program-defined channels.
|
|
33
|
+
- **Capability configured status drift:** low. The capability now reports configured when either the instance program or cycle store is wired, matching the fact that cycle routes can be alive independently of the instance object in tests and boot wiring.
|
|
34
|
+
- **Template guidance becoming stale:** medium over time. This is mitigated by listing the same enum values exported by the store today and keeping the text concise.
|
|
35
|
+
|
|
36
|
+
## Test evidence
|
|
37
|
+
|
|
38
|
+
Focused verification:
|
|
39
|
+
|
|
40
|
+
- `npx vitest run tests/integration/apprenticeship-routes.test.ts tests/unit/CapabilityIndex.test.ts tests/e2e/apprenticeship-lifecycle.test.ts`
|
|
41
|
+
- Result: 3 files passed, 31 tests passed.
|
|
42
|
+
|
|
43
|
+
Planned final checks before push:
|
|
44
|
+
|
|
45
|
+
- `pnpm lint`
|
|
46
|
+
- `pnpm build`
|
|
47
|
+
- `node dist/cli.js dev:preflight`
|
|
48
|
+
- `pnpm test:smoke`
|
|
49
|
+
|
|
50
|
+
## Rollback cost
|
|
51
|
+
|
|
52
|
+
Rollback is a normal code revert. Reverting restores the previous permissive HTTP behavior, removes the capability endpoint entries, and removes the new generated/migrated awareness line. No database migration is introduced, and no existing cycle rows need transformation.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Side-Effects Review — Double-send route guard
|
|
2
|
+
|
|
3
|
+
Slug: `double-send-route-guard`
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
|
|
7
|
+
Adds a last-resort Express duplicate-response guard and hardens the shared error handler against
|
|
8
|
+
late errors after a response has already been committed. Adds regression coverage for both runtime
|
|
9
|
+
paths and a source-level audit test for the classic missing-return route pattern.
|
|
10
|
+
|
|
11
|
+
## Decision inventory
|
|
12
|
+
|
|
13
|
+
- New runtime decision: if `res.headersSent` or `res.writableEnded` is already true, suppress a later
|
|
14
|
+
`res.json`, `res.send`, `res.sendStatus`, `res.redirect`, `res.download`, or `res.sendFile` call
|
|
15
|
+
and log it.
|
|
16
|
+
- New error-handler decision: if an error reaches `errorHandler` after the response is committed, log
|
|
17
|
+
the late error and do not attempt a second 500 response.
|
|
18
|
+
- New test-time decision: a route source audit flags a direct early branch response without a return
|
|
19
|
+
when a later direct handler response exists.
|
|
20
|
+
|
|
21
|
+
## Over-block
|
|
22
|
+
|
|
23
|
+
The guard only activates after the response is already committed. It does not block the first
|
|
24
|
+
response, does not reject requests, and does not change status codes on normal paths. It may suppress
|
|
25
|
+
a second response attempt that a caller previously saw as a thrown server error, but that second
|
|
26
|
+
response was never valid HTTP behavior.
|
|
27
|
+
|
|
28
|
+
## Under-block
|
|
29
|
+
|
|
30
|
+
The guard does not make route fallthrough logically correct; it prevents the process/request path from
|
|
31
|
+
throwing on the second send and preserves stack evidence. The source audit focuses on the high-signal
|
|
32
|
+
classic pattern and intentionally does not try to prove every possible nested control-flow path.
|
|
33
|
+
Reviewers still need to inspect unusual async flows.
|
|
34
|
+
|
|
35
|
+
## Level-of-abstraction fit
|
|
36
|
+
|
|
37
|
+
The runtime protection belongs in Express middleware because duplicate sends are a response-layer
|
|
38
|
+
failure that can happen in any route. The source audit belongs in tests because it is a structural
|
|
39
|
+
authoring guard, not a production decision point.
|
|
40
|
+
|
|
41
|
+
## Signal vs authority
|
|
42
|
+
|
|
43
|
+
The source audit is authority in CI for the narrow syntactic pattern it detects. The runtime guard is
|
|
44
|
+
authority only over a response that is already committed; at that point there is no valid second
|
|
45
|
+
response to authorize. It logs enough stack context for follow-up instead of silently hiding the
|
|
46
|
+
underlying route bug.
|
|
47
|
+
|
|
48
|
+
## Adjacent interactions
|
|
49
|
+
|
|
50
|
+
- `requestTimeout` already checks `!res.headersSent`; this change does not alter timeout budgets.
|
|
51
|
+
- Dashboard, auth, machine, and API routes are covered because the middleware is installed before
|
|
52
|
+
route registration.
|
|
53
|
+
- Express error middleware keeps returning normal 500 JSON for errors before a response is committed.
|
|
54
|
+
- Direct low-level `res.end()` is not monkey-patched to avoid interfering with Express internals
|
|
55
|
+
during legitimate first sends.
|
|
56
|
+
|
|
57
|
+
## Rollback
|
|
58
|
+
|
|
59
|
+
Rollback is straightforward: remove `duplicateResponseGuard` wiring, remove the middleware export,
|
|
60
|
+
restore the old `errorHandler` implementation, and remove the two unit tests. No data migration,
|
|
61
|
+
config migration, or user action is involved.
|
|
62
|
+
|
|
63
|
+
## Evidence
|
|
64
|
+
|
|
65
|
+
- `npx vitest run tests/unit/duplicate-response-guard.test.ts tests/unit/route-double-send-audit.test.ts`
|
|
66
|
+
- `npx tsc --noEmit`
|