instar 1.3.24 → 1.3.26

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.
@@ -0,0 +1,44 @@
1
+ /**
2
+ * handlers.ts — framework-agnostic dispatch (guidance-out) request handlers.
3
+ *
4
+ * Faithful port of handleList + handleCreate from the reference dispatch endpoint
5
+ * (the-portal/pages/api/instar/dispatches/index.ts), lifted out of Next.js into
6
+ * pure request→response functions over the FeedbackStore + the ported dispatch
7
+ * logic (dispatch.ts). The canonical front binds these; the operated deploy
8
+ * supplies the real store + the internal key. Reproduces the reference's exact
9
+ * status codes, auth, validation messages, and the version-compat filter.
10
+ *
11
+ * Note: unlike the public feedback receiver (which DEFAULTS an invalid type),
12
+ * dispatch create REJECTS an invalid type — it's an internal, authed endpoint.
13
+ */
14
+ import type { FeedbackStore } from '../store/FeedbackStore.js';
15
+ export interface DispatchListRequest {
16
+ headers: Record<string, string | string[] | undefined>;
17
+ query: {
18
+ since?: string;
19
+ type?: string;
20
+ };
21
+ }
22
+ export interface DispatchCreateRequest {
23
+ headers: Record<string, string | string[] | undefined>;
24
+ body: unknown;
25
+ }
26
+ export interface DispatchResponse {
27
+ status: number;
28
+ json: unknown;
29
+ }
30
+ /** Port of handleList: fingerprint-gate, since/type filter, version-compat filter, mapped output. */
31
+ export declare function handleDispatchList(req: DispatchListRequest, deps: {
32
+ store: FeedbackStore;
33
+ now: number;
34
+ }): DispatchResponse;
35
+ export interface DispatchCreateDeps {
36
+ store: FeedbackStore;
37
+ /** The internal API key the caller must present (x-internal-key or Bearer). */
38
+ internalKey: string;
39
+ now: number;
40
+ generateDispatchId?: () => string;
41
+ }
42
+ /** Port of handleCreate: internal-auth, validation (type REJECTED, priority defaulted), dedup-by-title, create. */
43
+ export declare function handleDispatchCreate(req: DispatchCreateRequest, deps: DispatchCreateDeps): DispatchResponse;
44
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/feedback-factory/dispatch/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,KAAK,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C;AACD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,IAAI,EAAE,OAAO,CAAC;CACf;AACD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAOD,qGAAqG;AACrG,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,gBAAgB,CAqC1H;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,aAAa,CAAC;IACrB,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;CACnC;AAED,mHAAmH;AACnH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,qBAAqB,EAAE,IAAI,EAAE,kBAAkB,GAAG,gBAAgB,CAoD3G"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * handlers.ts — framework-agnostic dispatch (guidance-out) request handlers.
3
+ *
4
+ * Faithful port of handleList + handleCreate from the reference dispatch endpoint
5
+ * (the-portal/pages/api/instar/dispatches/index.ts), lifted out of Next.js into
6
+ * pure request→response functions over the FeedbackStore + the ported dispatch
7
+ * logic (dispatch.ts). The canonical front binds these; the operated deploy
8
+ * supplies the real store + the internal key. Reproduces the reference's exact
9
+ * status codes, auth, validation messages, and the version-compat filter.
10
+ *
11
+ * Note: unlike the public feedback receiver (which DEFAULTS an invalid type),
12
+ * dispatch create REJECTS an invalid type — it's an internal, authed endpoint.
13
+ */
14
+ import { isValidDispatchType, isValidDispatchPriority, SEMVER_RE, DISPATCH_TYPES, filterDispatchesForVersion, normalizeDispatchTitle, } from './dispatch.js';
15
+ function header(headers, name) {
16
+ const v = headers[name];
17
+ return Array.isArray(v) ? v[0] : v;
18
+ }
19
+ /** Port of handleList: fingerprint-gate, since/type filter, version-compat filter, mapped output. */
20
+ export function handleDispatchList(req, deps) {
21
+ const ua = (header(req.headers, 'user-agent') || '').toLowerCase();
22
+ if (!ua.includes('instar/')) {
23
+ return { status: 400, json: { error: 'Invalid request format' } };
24
+ }
25
+ // since: only applied when it parses to a valid date (mirrors the reference).
26
+ let since;
27
+ if (req.query.since && !isNaN(new Date(req.query.since).getTime())) {
28
+ since = new Date(req.query.since).toISOString();
29
+ }
30
+ const type = req.query.type && isValidDispatchType(req.query.type) ? req.query.type : undefined;
31
+ let dispatches = deps.store.listDispatches({ since, type });
32
+ const version = header(req.headers, 'x-instar-version');
33
+ if (version && SEMVER_RE.test(version)) {
34
+ dispatches = filterDispatchesForVersion(dispatches, version);
35
+ }
36
+ return {
37
+ status: 200,
38
+ json: {
39
+ dispatches: dispatches.map((d) => ({
40
+ dispatchId: d.dispatchId,
41
+ type: d.type,
42
+ title: d.title,
43
+ content: d.content,
44
+ priority: d.priority,
45
+ minVersion: d.minVersion ?? null,
46
+ maxVersion: d.maxVersion ?? null,
47
+ createdAt: d.createdAt,
48
+ })),
49
+ count: dispatches.length,
50
+ asOf: new Date(deps.now).toISOString(),
51
+ },
52
+ };
53
+ }
54
+ /** Port of handleCreate: internal-auth, validation (type REJECTED, priority defaulted), dedup-by-title, create. */
55
+ export function handleDispatchCreate(req, deps) {
56
+ const provided = header(req.headers, 'x-internal-key')
57
+ || header(req.headers, 'authorization')?.replace('Bearer ', '');
58
+ if (provided !== deps.internalKey) {
59
+ return { status: 401, json: { error: 'Authentication required' } };
60
+ }
61
+ if (!req.body || typeof req.body !== 'object') {
62
+ return { status: 400, json: { error: 'Request body must be JSON' } };
63
+ }
64
+ const body = req.body;
65
+ if (!body.title || typeof body.title !== 'string' || body.title.trim().length < 3) {
66
+ return { status: 400, json: { error: 'title is required (min 3 characters)' } };
67
+ }
68
+ if (!body.content || typeof body.content !== 'string' || body.content.trim().length < 10) {
69
+ return { status: 400, json: { error: 'content is required (min 10 characters)' } };
70
+ }
71
+ if (!body.type || !isValidDispatchType(body.type)) {
72
+ return { status: 400, json: { error: `type must be one of: ${DISPATCH_TYPES.join(', ')}` } };
73
+ }
74
+ const priority = body.priority && isValidDispatchPriority(body.priority) ? body.priority : 'normal';
75
+ if (body.minVersion && !SEMVER_RE.test(body.minVersion)) {
76
+ return { status: 400, json: { error: 'minVersion must be valid semver' } };
77
+ }
78
+ if (body.maxVersion && !SEMVER_RE.test(body.maxVersion)) {
79
+ return { status: 400, json: { error: 'maxVersion must be valid semver' } };
80
+ }
81
+ const normalizedTitle = normalizeDispatchTitle(body.title);
82
+ const existing = deps.store.findDispatchByTitle(normalizedTitle);
83
+ if (existing) {
84
+ return { status: 200, json: { dispatchId: existing.dispatchId, created: false, duplicate: true } };
85
+ }
86
+ const dispatchId = (deps.generateDispatchId ?? (() => `dsp-${deps.now.toString(36)}-${Math.random().toString(36).slice(2, 6)}`))();
87
+ const record = {
88
+ dispatchId,
89
+ type: body.type,
90
+ title: normalizedTitle,
91
+ content: body.content.trim().slice(0, 50000),
92
+ priority: priority,
93
+ minVersion: body.minVersion || null,
94
+ maxVersion: body.maxVersion || null,
95
+ active: true,
96
+ createdAt: new Date(deps.now).toISOString(),
97
+ };
98
+ deps.store.createDispatch(record);
99
+ return { status: 201, json: { dispatchId, created: true, duplicate: false } };
100
+ }
101
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../../src/feedback-factory/dispatch/handlers.ts"],"names":[],"mappings":"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"}
@@ -52,11 +52,6 @@ export declare function verifySignature(args: {
52
52
  secret: string | undefined;
53
53
  now: number;
54
54
  }): boolean;
55
- /** Port of the input-validation block (:242–269): title ≥3, description ≥10, valid type, semver instarVersion. */
56
- export declare function validateFeedbackInput(body: Record<string, unknown>): {
57
- valid: boolean;
58
- error?: string;
59
- };
60
55
  /**
61
56
  * Port of the in-memory sliding-window rate limiter (checkRateLimit + prune) as an
62
57
  * injectable class. `now()` is injectable for deterministic tests; defaults to Date.now.
@@ -1 +1 @@
1
- {"version":3,"file":"defense.d.ts","sourceRoot":"","sources":["../../../src/feedback-factory/receiver/defense.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,eAAO,MAAM,WAAW,kFAAmF,CAAC;AAC5G,MAAM,MAAM,YAAY,GAAG,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;AAEtD,eAAO,MAAM,SAAS,QAA8B,CAAC;AACrD,eAAO,MAAM,cAAc,QAAyB,CAAC;AACrD,eAAO,MAAM,aAAa,QAAiD,CAAC;AAC5E,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD,eAAO,MAAM,WAAW;;;;;CAKvB,CAAC;AAEF,yGAAyG;AACzG,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAErF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAE/D;AAED,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAItH;AAED,+GAA+G;AAC/G,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CASnI;AAED,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAEpE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,OAAO,CAkBV;AAED,kHAAkH;AAClH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAcvG;AAED;;;GAGG;AACH,qBAAa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IANtB,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;gBAG/B,MAAM;;;;;KAAc,EACpB,GAAG,GAAE,MAAM,MAAyB;IAGvD,OAAO,CAAC,KAAK;IAWb,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE;CAsBhE"}
1
+ {"version":3,"file":"defense.d.ts","sourceRoot":"","sources":["../../../src/feedback-factory/receiver/defense.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,eAAO,MAAM,WAAW,kFAAmF,CAAC;AAC5G,MAAM,MAAM,YAAY,GAAG,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;AAEtD,eAAO,MAAM,SAAS,QAA8B,CAAC;AACrD,eAAO,MAAM,cAAc,QAAyB,CAAC;AACrD,eAAO,MAAM,aAAa,QAAiD,CAAC;AAC5E,eAAO,MAAM,eAAe,QAAsB,CAAC;AAEnD,eAAO,MAAM,WAAW;;;;;CAKvB,CAAC;AAEF,yGAAyG;AACzG,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAErF;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAE/D;AAED,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAItH;AAED,+GAA+G;AAC/G,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CASnI;AAED,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAEpE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,OAAO,CAkBV;AAUD;;;GAGG;AACH,qBAAa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IANtB,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;gBAG/B,MAAM;;;;;KAAc,EACpB,GAAG,GAAE,MAAM,MAAyB;IAGvD,OAAO,CAAC,KAAK;IAWb,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE;CAsBhE"}
@@ -81,22 +81,13 @@ export function verifySignature(args) {
81
81
  return false;
82
82
  }
83
83
  }
84
- /** Port of the input-validation block (:242–269): title ≥3, description ≥10, valid type, semver instarVersion. */
85
- export function validateFeedbackInput(body) {
86
- if (!body.type || !isValidType(body.type)) {
87
- return { valid: false, error: 'Invalid request format' };
88
- }
89
- if (!body.title || typeof body.title !== 'string' || body.title.trim().length < 3) {
90
- return { valid: false, error: 'Invalid request format' };
91
- }
92
- if (!body.description || typeof body.description !== 'string' || body.description.trim().length < 10) {
93
- return { valid: false, error: 'Invalid request format' };
94
- }
95
- if (body.instarVersion && !SEMVER_RE.test(body.instarVersion)) {
96
- return { valid: false, error: 'Invalid request format' };
97
- }
98
- return { valid: true };
99
- }
84
+ // NOTE: an earlier `validateFeedbackInput` helper lived here but diverged from the
85
+ // reference handleSubmit — it REJECTED an invalid `type` (the reference DEFAULTS it
86
+ // to 'other'), used a generic error message instead of the reference's specific
87
+ // per-field messages, and omitted the agentName/nodeVersion format checks. The
88
+ // faithful validation now lives inline in `handleFeedbackSubmit` (handlers.ts),
89
+ // which reproduces handleSubmit's exact order, messages, and type-default. The
90
+ // imperfect helper was removed to avoid two divergent validators.
100
91
  /**
101
92
  * Port of the in-memory sliding-window rate limiter (checkRateLimit + prune) as an
102
93
  * injectable class. `now()` is injectable for deterministic tests; defaults to Date.now.
@@ -1 +1 @@
1
- {"version":3,"file":"defense.js","sourceRoot":"","sources":["../../../src/feedback-factory/receiver/defense.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"defense.js","sourceRoot":"","sources":["../../../src/feedback-factory/receiver/defense.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * handlers.ts — framework-agnostic feedback-receiver request handler.
3
+ *
4
+ * Faithful port of `handleSubmit` from the reference receiver
5
+ * (the-portal/pages/api/instar/feedback.ts), lifted out of Next.js into a pure
6
+ * request→response function over the FeedbackStore interface + the ported intake
7
+ * defenses (defense.ts). The canonical front (Vercel function / Next route /
8
+ * instar server) is a thin binding that maps its req/res to this. This is the
9
+ * reusable "recipe"; the operated deploy supplies the framework binding + the
10
+ * real (Prisma) store.
11
+ *
12
+ * Reproduces handleSubmit's EXACT order, status codes, and error messages so a
13
+ * deployed agent's feedback sender behaves identically. Notably the reference
14
+ * DEFAULTS an invalid `type` to 'other' (does NOT reject it) — see the note in
15
+ * defense.ts about the superseded validateFeedbackInput helper.
16
+ */
17
+ import { type RateLimiter } from './defense.js';
18
+ import type { FeedbackStore } from '../store/FeedbackStore.js';
19
+ export interface FeedbackRequest {
20
+ headers: Record<string, string | string[] | undefined>;
21
+ body: unknown;
22
+ remoteAddress?: string;
23
+ }
24
+ export interface FeedbackResponse {
25
+ status: number;
26
+ headers?: Record<string, string>;
27
+ json: unknown;
28
+ }
29
+ export interface FeedbackHandlerDeps {
30
+ store: FeedbackStore;
31
+ rateLimiter: RateLimiter;
32
+ /** Normalized webhook secret (see normalizeWebhookSecret); undefined ⇒ unsigned-but-accepted. */
33
+ secret: string | undefined;
34
+ /** Injected clock (ms) for the HMAC replay window. */
35
+ now: number;
36
+ /** Injected id generator (defaults to the reference's `fb-<base36 time>-<rand>`). */
37
+ generateFeedbackId?: () => string;
38
+ }
39
+ /** Port of handleSubmit. Returns the status/headers/json the canonical front sends back. */
40
+ export declare function handleFeedbackSubmit(req: FeedbackRequest, deps: FeedbackHandlerDeps): FeedbackResponse;
41
+ //# sourceMappingURL=handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/feedback-factory/receiver/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,aAAa,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,iGAAiG;IACjG,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,qFAAqF;IACrF,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;CACnC;AAWD,4FAA4F;AAC5F,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,mBAAmB,GAAG,gBAAgB,CAsFtG"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * handlers.ts — framework-agnostic feedback-receiver request handler.
3
+ *
4
+ * Faithful port of `handleSubmit` from the reference receiver
5
+ * (the-portal/pages/api/instar/feedback.ts), lifted out of Next.js into a pure
6
+ * request→response function over the FeedbackStore interface + the ported intake
7
+ * defenses (defense.ts). The canonical front (Vercel function / Next route /
8
+ * instar server) is a thin binding that maps its req/res to this. This is the
9
+ * reusable "recipe"; the operated deploy supplies the framework binding + the
10
+ * real (Prisma) store.
11
+ *
12
+ * Reproduces handleSubmit's EXACT order, status codes, and error messages so a
13
+ * deployed agent's feedback sender behaves identically. Notably the reference
14
+ * DEFAULTS an invalid `type` to 'other' (does NOT reject it) — see the note in
15
+ * defense.ts about the superseded validateFeedbackInput helper.
16
+ */
17
+ import { extractSourceIp, validateAgentFingerprint, checkHoneypot, verifySignature, isValidType, SEMVER_RE, AGENT_NAME_RE, NODE_VERSION_RE, FEEDBACK_ID_RE, } from './defense.js';
18
+ function header(headers, name) {
19
+ const v = headers[name];
20
+ return Array.isArray(v) ? v[0] : v;
21
+ }
22
+ function defaultFeedbackId(now) {
23
+ return `fb-${now.toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
24
+ }
25
+ /** Port of handleSubmit. Returns the status/headers/json the canonical front sends back. */
26
+ export function handleFeedbackSubmit(req, deps) {
27
+ const { store, rateLimiter, secret, now } = deps;
28
+ const sourceIp = extractSourceIp(req.headers, req.remoteAddress);
29
+ // Layer 1: rate limit.
30
+ const rate = rateLimiter.check(sourceIp);
31
+ if (!rate.allowed) {
32
+ return {
33
+ status: 429,
34
+ headers: { 'Retry-After': String(rate.retryAfterSec) },
35
+ json: { error: 'Rate limit exceeded', retryAfterSec: rate.retryAfterSec },
36
+ };
37
+ }
38
+ // Layer 2: agent fingerprint (400, not 403 — don't reveal it's a fingerprint check).
39
+ const fp = validateAgentFingerprint(header(req.headers, 'user-agent'), header(req.headers, 'x-instar-version'));
40
+ if (!fp.valid) {
41
+ return { status: 400, json: { error: 'Invalid request format' } };
42
+ }
43
+ // Layer 3: honeypot — silently accept without storing (don't tip off the bot).
44
+ const body = (req.body ?? {});
45
+ if (checkHoneypot(body)) {
46
+ return { status: 200, json: { id: 'fb-received', received: true } };
47
+ }
48
+ // Layer 3.5: HMAC signature (non-blocking — unsigned still accepted, marked unverified).
49
+ const verified = verifySignature({
50
+ signature: header(req.headers, 'x-instar-signature'),
51
+ timestamp: header(req.headers, 'x-instar-timestamp'),
52
+ body: req.body,
53
+ secret,
54
+ now,
55
+ });
56
+ // Layer 4: input validation (exact reference order + messages).
57
+ if (!req.body || typeof req.body !== 'object') {
58
+ return { status: 400, json: { error: 'Request body must be JSON' } };
59
+ }
60
+ const title = body.title;
61
+ if (!title || typeof title !== 'string' || title.trim().length < 3) {
62
+ return { status: 400, json: { error: 'title is required (min 3 characters)' } };
63
+ }
64
+ const description = body.description;
65
+ if (!description || typeof description !== 'string' || description.trim().length < 10) {
66
+ return { status: 400, json: { error: 'description is required (min 10 characters)' } };
67
+ }
68
+ // The reference DEFAULTS an invalid type to 'other' — it does not reject.
69
+ const type = body.type && isValidType(body.type) ? body.type : 'other';
70
+ if (body.agentName && !AGENT_NAME_RE.test(body.agentName)) {
71
+ return { status: 400, json: { error: 'Invalid agentName format' } };
72
+ }
73
+ if (body.instarVersion && !SEMVER_RE.test(body.instarVersion)) {
74
+ return { status: 400, json: { error: 'Invalid instarVersion format (expected semver)' } };
75
+ }
76
+ if (body.nodeVersion && !NODE_VERSION_RE.test(body.nodeVersion)) {
77
+ return { status: 400, json: { error: 'Invalid nodeVersion format' } };
78
+ }
79
+ // feedbackId: use a valid agent-provided one, else generate.
80
+ const provided = body.feedbackId;
81
+ const feedbackId = typeof provided === 'string' && FEEDBACK_ID_RE.test(provided)
82
+ ? provided
83
+ : (deps.generateFeedbackId ?? (() => defaultFeedbackId(now)))();
84
+ // Layer 5: dedup — idempotent on a known feedbackId.
85
+ if (store.hasFeedback(feedbackId)) {
86
+ return { status: 200, json: { id: feedbackId, received: true, duplicate: true } };
87
+ }
88
+ store.addFeedback({
89
+ feedbackId,
90
+ type,
91
+ title: title.trim().slice(0, 500),
92
+ description: description.trim().slice(0, 10000),
93
+ agentName: (body.agentName || 'unknown').slice(0, 100),
94
+ instarVersion: (body.instarVersion || 'unknown').slice(0, 20),
95
+ nodeVersion: (body.nodeVersion || 'unknown').slice(0, 20),
96
+ os: (body.os || 'unknown').slice(0, 100),
97
+ context: typeof body.context === 'string' ? body.context.slice(0, 5000) : undefined,
98
+ sourceIp,
99
+ verified,
100
+ });
101
+ return { status: 200, json: { id: feedbackId, received: true } };
102
+ }
103
+ //# sourceMappingURL=handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../../src/feedback-factory/receiver/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,eAAe,EAAE,wBAAwB,EAAE,aAAa,EAAE,eAAe,EACzE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,GAEvE,MAAM,cAAc,CAAC;AA0BtB,SAAS,MAAM,CAAC,OAAmC,EAAE,IAAY;IAC/D,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAW;IACpC,OAAO,MAAM,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,oBAAoB,CAAC,GAAoB,EAAE,IAAyB;IAClF,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACjD,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;IAEjE,uBAAuB;IACvB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO;YACL,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,EAAE,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE;YACtD,IAAI,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE;SAC1E,CAAC;IACJ,CAAC;IAED,qFAAqF;IACrF,MAAM,EAAE,GAAG,wBAAwB,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAChH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,wBAAwB,EAAE,EAAE,CAAC;IACpE,CAAC;IAED,+EAA+E;IAC/E,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAC;IACzD,IAAI,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;IACtE,CAAC;IAED,yFAAyF;IACzF,MAAM,QAAQ,GAAG,eAAe,CAAC;QAC/B,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,oBAAoB,CAAC;QACpD,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,oBAAoB,CAAC;QACpD,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,MAAM;QACN,GAAG;KACJ,CAAC,CAAC;IAEH,gEAAgE;IAChE,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9C,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,2BAA2B,EAAE,EAAE,CAAC;IACvE,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACzB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,sCAAsC,EAAE,EAAE,CAAC;IAClF,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACrC,IAAI,CAAC,WAAW,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACtF,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,6CAA6C,EAAE,EAAE,CAAC;IACzF,CAAC;IACD,0EAA0E;IAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;IAEvE,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,SAAmB,CAAC,EAAE,CAAC;QACpE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,0BAA0B,EAAE,EAAE,CAAC;IACtE,CAAC;IACD,IAAI,IAAI,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,aAAuB,CAAC,EAAE,CAAC;QACxE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,gDAAgD,EAAE,EAAE,CAAC;IAC5F,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,WAAqB,CAAC,EAAE,CAAC;QAC1E,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE,EAAE,CAAC;IACxE,CAAC;IAED,6DAA6D;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC;IACjC,MAAM,UAAU,GAAG,OAAO,QAAQ,KAAK,QAAQ,IAAI,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC9E,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAElE,qDAAqD;IACrD,IAAI,KAAK,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC;IACpF,CAAC;IAED,KAAK,CAAC,WAAW,CAAC;QAChB,UAAU;QACV,IAAI;QACJ,KAAK,EAAG,KAAgB,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QAC7C,WAAW,EAAG,WAAsB,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;QAC3D,SAAS,EAAE,CAAE,IAAI,CAAC,SAAoB,IAAI,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QAClE,aAAa,EAAE,CAAE,IAAI,CAAC,aAAwB,IAAI,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QACzE,WAAW,EAAE,CAAE,IAAI,CAAC,WAAsB,IAAI,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QACrE,EAAE,EAAE,CAAE,IAAI,CAAC,EAAa,IAAI,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QACpD,OAAO,EAAE,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QACnF,QAAQ;QACR,QAAQ;KACT,CAAC,CAAC;IAEH,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC;AACnE,CAAC"}
@@ -14,6 +14,7 @@
14
14
  */
15
15
  import type { FeedbackItem, Cluster, ClusterResult } from '../processor/types.js';
16
16
  import type { ReopenDecision } from '../processor/reopen.js';
17
+ import type { DispatchRecord } from '../dispatch/dispatch.js';
17
18
  /** Read-only observability counters for the capture→cluster→reopen loop (spec §2.7). */
18
19
  export interface FeedbackMetrics {
19
20
  captured: number;
@@ -35,6 +36,19 @@ export interface FeedbackStore {
35
36
  applyReopen(clusterId: string, decision: ReopenDecision): void;
36
37
  /** Mark a feedback item processed + linked to its cluster. */
37
38
  markProcessed(feedbackId: string, clusterId: string): void;
39
+ /** True if a feedback item with this feedbackId already exists (the dedup check). */
40
+ hasFeedback(feedbackId: string): boolean;
41
+ /** Persist a newly-received feedback item (the receiver write). */
42
+ addFeedback(item: FeedbackItem): void;
43
+ /** Active dispatches matching an optional since/type filter, oldest-first (the dispatch list read). */
44
+ listDispatches(filter?: {
45
+ since?: string;
46
+ type?: string;
47
+ }): DispatchRecord[];
48
+ /** Find an existing dispatch by exact (normalized) title — the create-dedup check. */
49
+ findDispatchByTitle(title: string): DispatchRecord | undefined;
50
+ /** Persist a new dispatch. */
51
+ createDispatch(record: DispatchRecord): void;
38
52
  metrics(): FeedbackMetrics;
39
53
  }
40
54
  /**
@@ -58,6 +72,15 @@ export declare class InMemoryFeedbackStore implements FeedbackStore {
58
72
  mergeIntoCluster(clusterId: string, _item: FeedbackItem): void;
59
73
  applyReopen(clusterId: string, decision: ReopenDecision): void;
60
74
  markProcessed(feedbackId: string, clusterId: string): void;
75
+ hasFeedback(feedbackId: string): boolean;
76
+ addFeedback(item: FeedbackItem): void;
77
+ private dispatches;
78
+ listDispatches(filter?: {
79
+ since?: string;
80
+ type?: string;
81
+ }): DispatchRecord[];
82
+ findDispatchByTitle(title: string): DispatchRecord | undefined;
83
+ createDispatch(record: DispatchRecord): void;
61
84
  metrics(): FeedbackMetrics;
62
85
  /** Test helper: snapshot all clusters. */
63
86
  allClusters(): Cluster[];
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackStore.d.ts","sourceRoot":"","sources":["../../../src/feedback-factory/store/FeedbackStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,wFAAwF;AACxF,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,iGAAiG;IACjG,sBAAsB,IAAI,YAAY,EAAE,CAAC;IACzC,oEAAoE;IACpE,iBAAiB,IAAI,OAAO,EAAE,CAAC;IAC/B,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IACnD,oFAAoF;IACpF,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IACnE,iEAAiE;IACjE,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9D,kFAAkF;IAClF,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/D,8DAA8D;IAC9D,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3D,OAAO,IAAI,eAAe,CAAC;CAC5B;AAED;;;;;GAKG;AACH,qBAAa,qBAAsB,YAAW,aAAa;IACzD,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,MAAM,CAAwE;gBAE1E,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;KAAE;IAKtE,sBAAsB,IAAI,YAAY,EAAE;IAMxC,iBAAiB,IAAI,OAAO,EAAE;IAI9B,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAIlD,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI;IAYlE,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IAM9D,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI;IAW9D,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAM1D,OAAO,IAAI,eAAe;IAI1B,0CAA0C;IAC1C,WAAW,IAAI,OAAO,EAAE;CAGzB;AAED,YAAY,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"FeedbackStore.d.ts","sourceRoot":"","sources":["../../../src/feedback-factory/store/FeedbackStore.ts"],"names":[],"mappings":"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"}
@@ -77,6 +77,26 @@ export class InMemoryFeedbackStore {
77
77
  }
78
78
  this.counts.captured++;
79
79
  }
80
+ hasFeedback(feedbackId) {
81
+ return this.feedback.has(feedbackId);
82
+ }
83
+ addFeedback(item) {
84
+ this.feedback.set(item.feedbackId, { status: 'unprocessed', ...item });
85
+ }
86
+ dispatches = new Map();
87
+ listDispatches(filter) {
88
+ return [...this.dispatches.values()]
89
+ .filter((d) => d.active !== false)
90
+ .filter((d) => !filter?.since || String(d.createdAt ?? '') >= filter.since)
91
+ .filter((d) => !filter?.type || d.type === filter.type)
92
+ .sort((a, b) => String(a.createdAt ?? '').localeCompare(String(b.createdAt ?? '')));
93
+ }
94
+ findDispatchByTitle(title) {
95
+ return [...this.dispatches.values()].find((d) => d.title === title);
96
+ }
97
+ createDispatch(record) {
98
+ this.dispatches.set(record.dispatchId, { active: true, ...record });
99
+ }
80
100
  metrics() {
81
101
  return { ...this.counts };
82
102
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackStore.js","sourceRoot":"","sources":["../../../src/feedback-factory/store/FeedbackStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FeedbackStore.js","sourceRoot":"","sources":["../../../src/feedback-factory/store/FeedbackStore.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.24",
3
+ "version": "1.3.26",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-05-27T15:40:33.651Z",
5
- "instarVersion": "1.3.24",
4
+ "generatedAt": "2026-05-27T16:22:05.020Z",
5
+ "instarVersion": "1.3.26",
6
6
  "entryCount": 192,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,27 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ Eleventh increment of the **Feedback Factory Migration** (Dawn → Echo; spec `docs/specs/feedback-factory-migration.md`, approved). Ports the **receiver submit handler** — the actual "receive a report" request logic — out of the reference Next.js handler (`the-portal/pages/api/instar/feedback.ts`, `handleSubmit`) into a framework-agnostic function at `src/feedback-factory/receiver/handlers.ts`, plus the store operations it needs (`addFeedback` / `hasFeedback`).
8
+
9
+ It runs the full intake gauntlet (rate-limit → fingerprint → honeypot → signature → validation → dedup → store) and returns exactly the status codes and messages the reference returns, so a deployed agent's feedback sender behaves identically. The canonical front door (whatever framework hosts it) becomes a thin binding around this. **Not wired into any route yet** — no behavioral change.
10
+
11
+ Also corrects a fidelity slip found while building this: an earlier validation helper rejected an unknown report "type", but the real receiver quietly defaults an unknown type to "other". The faithful behavior now lives in the handler; the imperfect helper was removed.
12
+
13
+ ## What to Tell Your User
14
+
15
+ - The "receive a report" front-door logic is now ported, behaving exactly like Dawn's original down to the error messages — so when we stand up the new front door, field agents won't notice any difference.
16
+ - A small correctness fix went in too: a leftover validation helper was stricter than the real thing about report categories; it's now removed in favor of the faithful version.
17
+
18
+ ## Summary of New Capabilities
19
+
20
+ | Capability | How to Use |
21
+ |-----------|-----------|
22
+ | Receiver submit handler (TS port) | Internal `handleFeedbackSubmit` in `src/feedback-factory/receiver/handlers.ts` — framework-agnostic, not yet wired |
23
+ | Store receiver seam | `FeedbackStore.addFeedback` + `hasFeedback` |
24
+
25
+ ## Evidence
26
+
27
+ - Reference is TypeScript, so equivalence is by faithful transcription plus exhaustive both-sides-of-boundary tests (11 handler tests): rate-limit 429 with Retry-After; missing-fingerprint generic 400; honeypot silent-200-without-storing; exact title/description messages; **invalid type defaults to "other" (not rejected)** — the corrected behavior; malformed agentName/instarVersion/nodeVersion messages; success path marking unverified without a signature and verified with a valid HMAC; a valid agent-provided id honored with idempotent dedup; non-object body rejected. All 103 feedback-factory tests pass together.
@@ -0,0 +1,25 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ Twelfth increment of the **Feedback Factory Migration** (Dawn → Echo; spec `docs/specs/feedback-factory-migration.md`, approved). Ports the **dispatch request handlers** — the "send guidance back to agents" side — out of the reference Next.js endpoint (`the-portal/pages/api/instar/dispatches/index.ts`) into framework-agnostic functions at `src/feedback-factory/dispatch/handlers.ts`, plus the store operations they need (`listDispatches` / `findDispatchByTitle` / `createDispatch`).
8
+
9
+ List gates on the agent fingerprint, applies the since/type filter and the version-compat filter (so guidance only reaches the agent versions it applies to), and returns the mapped result. Create requires the internal key, validates the body, dedups by title, and creates. **Not wired into any route yet** — no behavioral change. This completes the front door's request layer (receive a report + send guidance both ported).
10
+
11
+ ## What to Tell Your User
12
+
13
+ - Both halves of the feedback loop's front door are now ported and behave exactly like Dawn's originals — catching reports, and sending version-targeted guidance back.
14
+ - That's the entire request + decision layer done. What's left to actually go live is the database wiring and the deploy — now being coordinated with Dawn.
15
+
16
+ ## Summary of New Capabilities
17
+
18
+ | Capability | How to Use |
19
+ |-----------|-----------|
20
+ | Dispatch handlers (TS port) | `handleDispatchList` + `handleDispatchCreate` in `src/feedback-factory/dispatch/handlers.ts` — framework-agnostic, not yet wired |
21
+ | Store dispatch seam | `FeedbackStore.listDispatches` / `findDispatchByTitle` / `createDispatch` |
22
+
23
+ ## Evidence
24
+
25
+ - Reference is TypeScript, so equivalence is by faithful transcription plus both-sides-of-boundary tests (8): list UA-gate 400; basic list with count + asOf; version-compat filter hiding a min-version dispatch from an older agent; type filter; create 401 without the key; Bearer-form auth accepted; exact validation messages for title/content/type/version; 201-then-200-duplicate dedup by title.
@@ -0,0 +1,32 @@
1
+ # Side-Effects Review — dispatch request handlers (Phase 1, increment 12)
2
+
3
+ **Slug:** `feedback-factory-dispatch-handlers`
4
+ **Date:** `2026-05-27`
5
+ **Author:** Echo (autonomous → interactive)
6
+ **Spec:** `docs/specs/feedback-factory-migration.md` (converged v2, approved by Justin 2026-05-26)
7
+ **Scope:** The framework-agnostic dispatch request handlers (faithful ports of `handleList` + `handleCreate`) + the store dispatch ops. Completes the front's request layer (receiver + dispatch). NOT the HTTP binding/deploy.
8
+
9
+ ## Summary of the change
10
+
11
+ Adds `src/feedback-factory/dispatch/handlers.ts` — `handleDispatchList` + `handleDispatchCreate`, faithful ports of the reference dispatch endpoint, as pure request→response functions over the FeedbackStore + the ported dispatch logic (dispatch.ts). Adds `FeedbackStore.listDispatches`/`findDispatchByTitle`/`createDispatch` + `InMemoryFeedbackStore` impls. Reproduces the reference exactly: list gates on the `instar/` UA, applies the since/type DB filter + the version-compat filter, returns the mapped `{dispatches, count, asOf}`; create requires the internal key (x-internal-key or Bearer), validates (title ≥3, content ≥10, **type REJECTED** if invalid, priority defaulted, min/maxVersion semver), dedups by normalized title, and returns 201/200-duplicate. **Not wired into any route yet** — no behavioral change.
12
+
13
+ Note the asymmetry with the public receiver: dispatch create REJECTS an invalid type (it's an internal, authed endpoint), whereas the public feedback receiver defaults it — both faithful to their respective references.
14
+
15
+ ## Seven-dimension review
16
+
17
+ 1. **Over/under-reach** — Pure request→response functions over the store. Not wired to any route. The internal-key auth is injected (the operated binding provides the real key).
18
+ 2. **Level-of-abstraction fit** — Reusable "recipe" → core; the framework binding + real store are operated-side. The version-compat filter reuses the already-tested `filterDispatchesForVersion`.
19
+ 3. **Signal vs Authority** — N/A; create is internal-authed (the reference's 401 gate is reproduced); list is the `instar/`-UA fingerprint gate.
20
+ 4. **Interactions** — `dispatch/handlers.ts` imports dispatch.ts + the store interface; nothing imports it yet. Store gains a dispatches Map (isolated from feedback/clusters).
21
+ 5. **Rollback cost** — Trivial: delete the handlers + store ops + tests.
22
+ 6. **Migration parity** — N/A. Core library code; no agent-installed file.
23
+ 7. **Failure modes** — (a) Response divergence → exact status/message/auth/order tested. (b) Version-compat filter wrong → reuses the 9/9-tested `filterDispatchesForVersion` + a hidden-from-older-agent handler test. (c) Dedup-by-title divergence → tested (201 then 200-duplicate). (d) Auth bypass → 401 tested for missing/wrong key; Bearer form tested.
24
+
25
+ ## Tests
26
+
27
+ - Tier-1 unit (CI): `tests/unit/feedback-factory/dispatch-handlers.test.ts` — 8 tests (list: UA-gate, basic list+asOf, version-compat hide, type filter; create: 401, Bearer-auth, validation messages, 201-then-dedup).
28
+ - No E2E this increment — the route binding + deploy are gated on the blocked app-placement + Prisma-adapter decisions.
29
+
30
+ ## Status note
31
+
32
+ With this, the **entire front + processor request/decision layer is ported** (receiver submit + dispatch list/create handlers, all the processor brain, the store seam + composition + observability). The only remaining feedback-factory work is genuinely blocked on external inputs: the real Prisma adapter (DB creds/schema), the framework binding + Vercel deploy (app-placement + Vercel project), agent-awareness (after live), and the operational cutover (Dawn + live systems).
@@ -0,0 +1,31 @@
1
+ # Side-Effects Review — receiver submit handler + a fidelity correction (Phase 1, increment 11)
2
+
3
+ **Slug:** `feedback-factory-receiver-handler`
4
+ **Date:** `2026-05-27`
5
+ **Author:** Echo (autonomous → interactive)
6
+ **Spec:** `docs/specs/feedback-factory-migration.md` (converged v2, approved by Justin 2026-05-26)
7
+ **Scope:** The framework-agnostic receiver submit handler (faithful port of `handleSubmit`), the store ops it needs (`addFeedback`/`hasFeedback`), AND a correction to increment-6's `validateFeedbackInput` (see below).
8
+
9
+ ## Summary of the change
10
+
11
+ Adds `src/feedback-factory/receiver/handlers.ts` — `handleFeedbackSubmit(req, deps) → {status, headers?, json}`, a faithful port of the reference `handleSubmit` (the-portal/pages/api/instar/feedback.ts) lifted out of Next.js into a pure request→response function over the FeedbackStore interface + the ported defenses. The canonical front (Vercel function / Next route / instar server) becomes a thin binding. Reproduces the reference's EXACT order, status codes (429/400/200), and error messages so deployed agents' feedback senders behave identically. Adds `FeedbackStore.addFeedback` + `hasFeedback` (the receiver write + dedup seam) + `InMemoryFeedbackStore` impls. **Not wired into any route yet** — no behavioral change. Notification (Telegram) is intentionally NOT in the core handler — it's an operated-side concern the binding adds.
12
+
13
+ ## Fidelity correction (increment 6)
14
+
15
+ Building this surfaced that increment-6's `validateFeedbackInput` (defense.ts) **diverged from the reference**: it REJECTED an invalid `type` (the reference DEFAULTS it to `'other'`), used a generic error message instead of the reference's specific per-field messages, and omitted the agentName/nodeVersion format checks. That helper was a premature abstraction — the reference validates inline. **Removed** `validateFeedbackInput` (+ its tests); the faithful validation now lives inline in `handleFeedbackSubmit` (exact messages, order, and the type-default). The other defense.ts functions (verifySignature, fingerprint, honeypot, RateLimiter, regexes) were faithful + are reused unchanged.
16
+
17
+ ## Seven-dimension review
18
+
19
+ 1. **Over/under-reach** — Pure request→response function + a self-contained `RateLimiter` (injected). The over-reach in increment 6 (rejecting valid-but-defaulted types) is REMOVED — the handler now matches the reference's leniency exactly. No route wired.
20
+ 2. **Level-of-abstraction fit** — The handler is reusable "recipe" → core package; the framework binding + Prisma store are operated-side. Notification kept out of core. Correct split.
21
+ 3. **Signal vs Authority** — N/A; returns a response. HMAC is non-blocking (unsigned still accepted, marked `verified:false`) — faithful to the reference.
22
+ 4. **Interactions** — `handlers.ts` imports defense.ts + the store interface; nothing imports `handlers.ts` yet. Removing `validateFeedbackInput` is safe — only its own test referenced it (verified by grep).
23
+ 5. **Rollback cost** — Trivial: delete handlers.ts + restore the helper. (But the helper was incorrect — keeping it removed is the right state.)
24
+ 6. **Migration parity** — N/A. Core library code; no agent-installed file. (The sender repoint is the separate, blocked cutover step.)
25
+ 7. **Failure modes** — (a) Response divergence from the reference → exact status/message/order tested incl. the type-default fidelity fix + non-object-body + dedup-idempotency. (b) HMAC verified flag wrong → tested signed vs unsigned. (c) Rate-limit non-determinism → injected clock. (d) feedbackId generation non-determinism → injected generator.
26
+
27
+ ## Tests
28
+
29
+ - Tier-1 unit (CI): `tests/unit/feedback-factory/handlers.test.ts` (11 — 429 / fingerprint-400 / honeypot-silent / exact title+desc messages / **type-default-to-other** / agentName+version messages / success+unverified / verified-with-HMAC / provided-id + dedup-idempotency / non-object-body), plus `store.test.ts` +1 (addFeedback/hasFeedback), and `defense.test.ts` updated (validateFeedbackInput removed).
30
+ - All 103 feedback-factory unit+integration tests green together.
31
+ - No E2E this increment — the route binding + deploy are gated on the blocked app-placement + Prisma-adapter decisions.