instar 1.3.484 → 1.3.486
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/dashboard/index.html +4 -1
- package/dist/core/MessagingToneGate.d.ts +23 -2
- package/dist/core/MessagingToneGate.d.ts.map +1 -1
- package/dist/core/MessagingToneGate.js +15 -1
- package/dist/core/MessagingToneGate.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +21 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +22 -0
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/TelegramRelay.d.ts +1 -0
- package/dist/core/TelegramRelay.d.ts.map +1 -1
- package/dist/core/TelegramRelay.js +9 -1
- package/dist/core/TelegramRelay.js.map +1 -1
- package/dist/core/raw-file-path.d.ts +33 -0
- package/dist/core/raw-file-path.d.ts.map +1 -0
- package/dist/core/raw-file-path.js +105 -0
- package/dist/core/raw-file-path.js.map +1 -0
- package/dist/messaging/OutboundAdvisory.d.ts +152 -0
- package/dist/messaging/OutboundAdvisory.d.ts.map +1 -0
- package/dist/messaging/OutboundAdvisory.js +453 -0
- package/dist/messaging/OutboundAdvisory.js.map +1 -0
- package/dist/messaging/TelegramAdapter.d.ts +6 -0
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +4 -1
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/messaging/pending-relay-store.d.ts +7 -0
- package/dist/messaging/pending-relay-store.d.ts.map +1 -1
- package/dist/messaging/pending-relay-store.js +9 -3
- package/dist/messaging/pending-relay-store.js.map +1 -1
- package/dist/monitoring/delivery-failure-sentinel.d.ts +6 -1
- package/dist/monitoring/delivery-failure-sentinel.d.ts.map +1 -1
- package/dist/monitoring/delivery-failure-sentinel.js +15 -3
- package/dist/monitoring/delivery-failure-sentinel.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +7 -1
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/scheduler/JobScheduler.d.ts.map +1 -1
- package/dist/scheduler/JobScheduler.js +8 -0
- package/dist/scheduler/JobScheduler.js.map +1 -1
- package/dist/server/AgentServer.d.ts +1 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +22 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/PeerStreamProxy.d.ts +7 -0
- package/dist/server/PeerStreamProxy.d.ts.map +1 -1
- package/dist/server/PeerStreamProxy.js +11 -2
- package/dist/server/PeerStreamProxy.js.map +1 -1
- package/dist/server/WebSocketManager.d.ts +10 -1
- package/dist/server/WebSocketManager.d.ts.map +1 -1
- package/dist/server/WebSocketManager.js +27 -3
- package/dist/server/WebSocketManager.js.map +1 -1
- package/dist/server/routes.d.ts +12 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +216 -3
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +67 -67
- package/src/scaffold/templates.ts +7 -1
- package/src/templates/scripts/telegram-reply.sh +202 -10
- package/upgrades/1.3.485.md +31 -0
- package/upgrades/1.3.486.md +38 -0
- package/upgrades/side-effects/outbound-advisory-inform-only.md +252 -0
- package/upgrades/side-effects/pool-stream-cross-machine-fix.md +94 -0
|
@@ -48,5 +48,6 @@ export interface RelayDeps {
|
|
|
48
48
|
*/
|
|
49
49
|
export declare function relayOutbound(topicId: number, text: string, opts: {
|
|
50
50
|
silent?: boolean;
|
|
51
|
+
kindMetadata?: Record<string, unknown>;
|
|
51
52
|
} | undefined, deps: RelayDeps): Promise<RelayResult | null>;
|
|
52
53
|
//# sourceMappingURL=TelegramRelay.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TelegramRelay.d.ts","sourceRoot":"","sources":["../../src/core/TelegramRelay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,iFAAiF;IACjF,WAAW,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACjC,mEAAmE;IACnE,aAAa,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,mEAAmE;IACnE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,iEAAiE;IACjE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"TelegramRelay.d.ts","sourceRoot":"","sources":["../../src/core/TelegramRelay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,iFAAiF;IACjF,WAAW,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACjC,mEAAmE;IACnE,aAAa,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,mEAAmE;IACnE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,iEAAiE;IACjE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,SAAS,EAC9E,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAyD7B"}
|
|
@@ -44,7 +44,15 @@ export async function relayOutbound(topicId, text, opts, deps) {
|
|
|
44
44
|
const resp = await fetchImpl(`${url}/telegram/reply/${topicId}`, {
|
|
45
45
|
method: 'POST',
|
|
46
46
|
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${deps.authToken}` },
|
|
47
|
-
|
|
47
|
+
// Forward the kind metadata so an automated send keeps its kind across
|
|
48
|
+
// the hop and the HOLDER's gate/audit see accurate context (spec
|
|
49
|
+
// outbound-jargon-filepath-gap §2.5). The preflight already ran on the
|
|
50
|
+
// ORIGINATING machine — it never re-runs here.
|
|
51
|
+
body: JSON.stringify({
|
|
52
|
+
text,
|
|
53
|
+
...(opts?.silent ? { silent: true } : {}),
|
|
54
|
+
...(opts?.kindMetadata ? { metadata: opts.kindMetadata } : {}),
|
|
55
|
+
}),
|
|
48
56
|
signal: ac.signal,
|
|
49
57
|
});
|
|
50
58
|
if (!resp.ok) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TelegramRelay.js","sourceRoot":"","sources":["../../src/core/TelegramRelay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAwBH;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAAe,EACf,IAAY,EACZ,
|
|
1
|
+
{"version":3,"file":"TelegramRelay.js","sourceRoot":"","sources":["../../src/core/TelegramRelay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* raw-file-path — deterministic detector for literal filesystem paths in
|
|
3
|
+
* user-facing messages.
|
|
4
|
+
*
|
|
5
|
+
* Sibling of `localhost-link.ts`, held to the same linear-regex discipline —
|
|
6
|
+
* but unlike the localhost guard this is a pure SIGNAL, never a block
|
|
7
|
+
* (spec: docs/specs/outbound-jargon-filepath-gap.md §2.3). A literal repo
|
|
8
|
+
* path shown to a user ("/Users/justin/...", ".instar/config.json",
|
|
9
|
+
* "src/core/Foo.ts") is something the user usually can't act on; the
|
|
10
|
+
* existing B2_FILE_PATH judgment belongs to the LLM authority, and on
|
|
11
|
+
* automated sends the preflight advisory informs the SENDER. This detector
|
|
12
|
+
* only surfaces the observation.
|
|
13
|
+
*
|
|
14
|
+
* Hard requirements (r2 convergence):
|
|
15
|
+
* - ReDoS-safe: linear, non-backtracking patterns; bounded segment count
|
|
16
|
+
* and length; an indexOf prescreen so the regex only runs when a path is
|
|
17
|
+
* plausibly present.
|
|
18
|
+
* - Never matches inside an `http(s)://` URL — URLs containing paths are
|
|
19
|
+
* the legitimate form to preserve.
|
|
20
|
+
* - Bounded match echo: the returned match is the regex token (whose char
|
|
21
|
+
* class already stops at whitespace/quote/`?`/`#`/`)`), truncated to
|
|
22
|
+
* 120 chars, so a secret adjacent to a path can never ride into
|
|
23
|
+
* logs/advisories/transcripts.
|
|
24
|
+
* - Callers wrap every call fail-OPEN: a throw skips the signal, never
|
|
25
|
+
* withholds a message and never 500s a route.
|
|
26
|
+
*/
|
|
27
|
+
export interface RawFilePathResult {
|
|
28
|
+
detected: boolean;
|
|
29
|
+
/** First offending path, bounded to 120 chars — safe to echo in advisories/audits. */
|
|
30
|
+
match?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function detectRawFilePath(text: string): RawFilePathResult;
|
|
33
|
+
//# sourceMappingURL=raw-file-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raw-file-path.d.ts","sourceRoot":"","sources":["../../src/core/raw-file-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAmCH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA2BD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAsBjE"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* raw-file-path — deterministic detector for literal filesystem paths in
|
|
3
|
+
* user-facing messages.
|
|
4
|
+
*
|
|
5
|
+
* Sibling of `localhost-link.ts`, held to the same linear-regex discipline —
|
|
6
|
+
* but unlike the localhost guard this is a pure SIGNAL, never a block
|
|
7
|
+
* (spec: docs/specs/outbound-jargon-filepath-gap.md §2.3). A literal repo
|
|
8
|
+
* path shown to a user ("/Users/justin/...", ".instar/config.json",
|
|
9
|
+
* "src/core/Foo.ts") is something the user usually can't act on; the
|
|
10
|
+
* existing B2_FILE_PATH judgment belongs to the LLM authority, and on
|
|
11
|
+
* automated sends the preflight advisory informs the SENDER. This detector
|
|
12
|
+
* only surfaces the observation.
|
|
13
|
+
*
|
|
14
|
+
* Hard requirements (r2 convergence):
|
|
15
|
+
* - ReDoS-safe: linear, non-backtracking patterns; bounded segment count
|
|
16
|
+
* and length; an indexOf prescreen so the regex only runs when a path is
|
|
17
|
+
* plausibly present.
|
|
18
|
+
* - Never matches inside an `http(s)://` URL — URLs containing paths are
|
|
19
|
+
* the legitimate form to preserve.
|
|
20
|
+
* - Bounded match echo: the returned match is the regex token (whose char
|
|
21
|
+
* class already stops at whitespace/quote/`?`/`#`/`)`), truncated to
|
|
22
|
+
* 120 chars, so a secret adjacent to a path can never ride into
|
|
23
|
+
* logs/advisories/transcripts.
|
|
24
|
+
* - Callers wrap every call fail-OPEN: a throw skips the signal, never
|
|
25
|
+
* withholds a message and never 500s a route.
|
|
26
|
+
*/
|
|
27
|
+
/** Truncation cap for the echoed match (privacy bound on adjacent content). */
|
|
28
|
+
const MATCH_ECHO_MAX = 120;
|
|
29
|
+
/** Defensive input cap — callers already cap analyzed text (64KB at the
|
|
30
|
+
* preflight route); this keeps the detector itself bounded regardless. */
|
|
31
|
+
const INPUT_MAX = 64 * 1024;
|
|
32
|
+
/**
|
|
33
|
+
* Path-segment char class: stops at whitespace, quotes, `?`, `#`, `)`,
|
|
34
|
+
* backticks and other prose punctuation by construction. Bounded segment
|
|
35
|
+
* length (1–64) and bounded segment count keep the scan linear.
|
|
36
|
+
*
|
|
37
|
+
* Three alternatives, all anchored on a real separator so prose like
|
|
38
|
+
* "and/or" or "TCP/IP" cannot match:
|
|
39
|
+
* A) absolute or home paths with at least two segments: /Users/justin/x, ~/.config/foo
|
|
40
|
+
* B) dot-directory relative paths: .instar/config.json, .claude/hooks/x
|
|
41
|
+
* C) repo-relative paths under well-known dirs: src/core/Foo.ts, logs/server.log
|
|
42
|
+
*/
|
|
43
|
+
const SEG = '[A-Za-z0-9._-]{1,64}';
|
|
44
|
+
const RAW_FILE_PATH_RE = new RegExp(
|
|
45
|
+
// A: "/seg/seg..." or "~/seg/seg..." (>= 2 segments so "/tmp" alone or a
|
|
46
|
+
// lone slash in prose stays legal)
|
|
47
|
+
`(?:(?:~)?/${SEG}(?:/${SEG}){1,12}` +
|
|
48
|
+
// B: ".instar/...", ".claude/...", ".github/...", ".husky/..." (single
|
|
49
|
+
// segment after the dot-dir is enough — ".instar/config.json")
|
|
50
|
+
`|\\.(?:instar|claude|github|husky|vscode|config)/${SEG}(?:/${SEG}){0,12}` +
|
|
51
|
+
// C: repo-relative under well-known top-level dirs; require the word
|
|
52
|
+
// boundary via a non-path char or string start (handled in code, not
|
|
53
|
+
// lookbehind, to keep the pattern simple and linear)
|
|
54
|
+
`|(?:src|docs|tests|scripts|logs|state|upgrades|dist|node_modules)/${SEG}(?:/${SEG}){0,12})`, 'g');
|
|
55
|
+
/**
|
|
56
|
+
* True when `index` sits inside a scheme-bearing URL token: the
|
|
57
|
+
* whitespace-delimited token containing the match start carries "://"
|
|
58
|
+
* before the match. Linear scan-back, bounded by the token itself.
|
|
59
|
+
*/
|
|
60
|
+
function insideUrl(text, index) {
|
|
61
|
+
let start = index;
|
|
62
|
+
while (start > 0 && !/\s/.test(text[start - 1]))
|
|
63
|
+
start--;
|
|
64
|
+
const prefix = text.slice(start, index);
|
|
65
|
+
// `://` fully before the match, OR the match starts at the second slash of
|
|
66
|
+
// a scheme separator (prefix ends with `:/` — e.g. match begins at
|
|
67
|
+
// "/example.com/…" inside "https://example.com/…").
|
|
68
|
+
return prefix.includes('://') || /:\/$/.test(prefix);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* For alternative C (bare repo-relative prefixes like "src/"), require a
|
|
72
|
+
* word boundary on the left so "missrc/foo" or "RandomLogs/x" can't match.
|
|
73
|
+
* Alternatives A/B self-anchor on '/', '~' or '.'.
|
|
74
|
+
*/
|
|
75
|
+
function hasWordBoundaryLeft(text, index) {
|
|
76
|
+
if (index === 0)
|
|
77
|
+
return true;
|
|
78
|
+
return !/[A-Za-z0-9._\-/]/.test(text[index - 1]);
|
|
79
|
+
}
|
|
80
|
+
export function detectRawFilePath(text) {
|
|
81
|
+
if (typeof text !== 'string' || text.length === 0)
|
|
82
|
+
return { detected: false };
|
|
83
|
+
const input = text.length > INPUT_MAX ? text.slice(0, INPUT_MAX) : text;
|
|
84
|
+
// indexOf prescreen — the regex only runs when a path separator exists.
|
|
85
|
+
if (!input.includes('/'))
|
|
86
|
+
return { detected: false };
|
|
87
|
+
RAW_FILE_PATH_RE.lastIndex = 0;
|
|
88
|
+
let m;
|
|
89
|
+
while ((m = RAW_FILE_PATH_RE.exec(input)) !== null) {
|
|
90
|
+
const token = m[0];
|
|
91
|
+
const at = m.index;
|
|
92
|
+
// Never flag a path that lives inside an http(s):// URL.
|
|
93
|
+
if (insideUrl(input, at))
|
|
94
|
+
continue;
|
|
95
|
+
// Bare repo-relative alternative needs a real word boundary.
|
|
96
|
+
const firstChar = token[0];
|
|
97
|
+
if (firstChar !== '/' && firstChar !== '~' && firstChar !== '.') {
|
|
98
|
+
if (!hasWordBoundaryLeft(input, at))
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
return { detected: true, match: token.slice(0, MATCH_ECHO_MAX) };
|
|
102
|
+
}
|
|
103
|
+
return { detected: false };
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=raw-file-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raw-file-path.js","sourceRoot":"","sources":["../../src/core/raw-file-path.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OutboundAdvisory — the inform-only preflight surface for automated senders.
|
|
3
|
+
*
|
|
4
|
+
* Spec: docs/specs/outbound-jargon-filepath-gap.md (§2.4, §2.4(5), §2.4(6)).
|
|
5
|
+
*
|
|
6
|
+
* Three responsibilities, all strictly non-blocking:
|
|
7
|
+
*
|
|
8
|
+
* 1. **Advisory composition** (`composeAdvisories`) — run the deterministic
|
|
9
|
+
* detectors (jargon, raw-file-path, localhost-link) over a candidate text
|
|
10
|
+
* and return static-guidance advisories. No LLM call, fail-OPEN per
|
|
11
|
+
* detector, guidance keyed by code (never derived from message content —
|
|
12
|
+
* injection-pinned), detector match rendered only as an inert bounded
|
|
13
|
+
* token by the consumer.
|
|
14
|
+
*
|
|
15
|
+
* 2. **Audit** (`recordPreflight` / `recordAck`) — the SERVER is the single
|
|
16
|
+
* writer of `logs/outbound-advisory.jsonl`: one O_APPEND write per line,
|
|
17
|
+
* `{ts, topicId, jobSlug, kind, textHash, advisories, action}` with
|
|
18
|
+
* action `clean | advised | acked`. Size-rotated (single rollover to
|
|
19
|
+
* `.1` at the byte cap). The script writes NOTHING here.
|
|
20
|
+
*
|
|
21
|
+
* 3. **Repeated-ignore escalation** — the load-bearing bound on the design's
|
|
22
|
+
* worst failure mode (a sender silently dropping its own flagged
|
|
23
|
+
* message). Fed by an in-memory write-time index (no poller, no file
|
|
24
|
+
* scan; resets on restart are accepted best-effort observability):
|
|
25
|
+
* - per-SIGNATURE (jobSlug, topicId, sorted code set) unresolved-advised
|
|
26
|
+
* count in a rolling window, NOT reset by interleaved clean rows for
|
|
27
|
+
* other messages (the reset-gaming case);
|
|
28
|
+
* - a signature resolves on an `acked` with the same codes, or a `clean`
|
|
29
|
+
* preflight of the same message — "same message" judged by token-set
|
|
30
|
+
* similarity (the fix re-send is near-identical), never by exact hash
|
|
31
|
+
* alone;
|
|
32
|
+
* - a per-jobSlug AGGREGATE (across topics, higher threshold) covers
|
|
33
|
+
* one-shot senders whose topics vary;
|
|
34
|
+
* - a preemptive-ack consumer: N consecutive acked-with-NONEMPTY
|
|
35
|
+
* advisories per signature raises too (a job habitually overriding
|
|
36
|
+
* instead of fixing is operator-relevant).
|
|
37
|
+
* Escalation INFORMS THE OPERATOR (one deduped Attention item with the
|
|
38
|
+
* FIXED sourceContext 'outbound-advisory-escalation' so the per-source
|
|
39
|
+
* topic budget genuinely binds — P17). It never gates the sender.
|
|
40
|
+
*/
|
|
41
|
+
export type AdvisoryCode = 'JARGON' | 'RAW_FILE_PATH' | 'LOCALHOST_LINK';
|
|
42
|
+
export interface Advisory {
|
|
43
|
+
code: AdvisoryCode;
|
|
44
|
+
/** Bounded inert detector match (≤120 chars) — data, never instructions. */
|
|
45
|
+
match?: string;
|
|
46
|
+
/** STATIC guidance keyed by code — never derived from message content. */
|
|
47
|
+
guidance: string;
|
|
48
|
+
}
|
|
49
|
+
/** Analyzed-text cap (consistent with the pipeline's downstream rejects). */
|
|
50
|
+
export declare const PREFLIGHT_TEXT_CAP: number;
|
|
51
|
+
/**
|
|
52
|
+
* Run the deterministic detectors over a candidate text. Each detector is
|
|
53
|
+
* individually fail-OPEN: a throw skips that signal and never withholds.
|
|
54
|
+
*/
|
|
55
|
+
export declare function composeAdvisories(text: string): Advisory[];
|
|
56
|
+
export type AdvisoryAction = 'clean' | 'advised' | 'acked';
|
|
57
|
+
export interface AdvisoryAuditEntry {
|
|
58
|
+
ts: string;
|
|
59
|
+
topicId: number;
|
|
60
|
+
jobSlug: string;
|
|
61
|
+
kind: string;
|
|
62
|
+
textHash: string;
|
|
63
|
+
advisories: string[];
|
|
64
|
+
action: AdvisoryAction;
|
|
65
|
+
}
|
|
66
|
+
export interface AttentionRaiser {
|
|
67
|
+
(item: {
|
|
68
|
+
id: string;
|
|
69
|
+
title: string;
|
|
70
|
+
summary: string;
|
|
71
|
+
category: string;
|
|
72
|
+
priority: 'HIGH' | 'NORMAL' | 'LOW';
|
|
73
|
+
description?: string;
|
|
74
|
+
sourceContext?: string;
|
|
75
|
+
}): Promise<unknown> | unknown;
|
|
76
|
+
}
|
|
77
|
+
export interface OutboundAdvisoryAuditOptions {
|
|
78
|
+
/** Absolute path of the JSONL audit file (e.g. <root>/logs/outbound-advisory.jsonl). */
|
|
79
|
+
logPath: string;
|
|
80
|
+
/** Size-rotation cap in bytes (single rollover to `.1`). Default 10MB. */
|
|
81
|
+
maxLogBytes?: number;
|
|
82
|
+
/** Per-signature unresolved-advised threshold (live-read). Default 3. */
|
|
83
|
+
getIgnoreThreshold?: () => number;
|
|
84
|
+
/** Per-jobSlug aggregate threshold (live-read). Default 5. */
|
|
85
|
+
getSlugThreshold?: () => number;
|
|
86
|
+
/** Operator-inform surface. Absent → escalation is a no-op (audit still writes). */
|
|
87
|
+
raiseAttention?: AttentionRaiser;
|
|
88
|
+
}
|
|
89
|
+
/** Fixed sourceContext — P17: the per-source topic budget must genuinely bind. */
|
|
90
|
+
export declare const ADVISORY_ESCALATION_SOURCE = "outbound-advisory-escalation";
|
|
91
|
+
export declare function sha256Hex(text: string): string;
|
|
92
|
+
export declare class OutboundAdvisoryAudit {
|
|
93
|
+
private logPath;
|
|
94
|
+
private maxLogBytes;
|
|
95
|
+
private getIgnoreThreshold;
|
|
96
|
+
private getSlugThreshold;
|
|
97
|
+
private raiseAttention;
|
|
98
|
+
/** Write-time index — per-signature state (key: slug|topic|codes). */
|
|
99
|
+
private signatures;
|
|
100
|
+
/** Recent PREFLIGHT-written rows (clean/advised) for §2.1 spoof correlation.
|
|
101
|
+
* Keyed slug|topic → last preflight ts. Acked rows never land here —
|
|
102
|
+
* a send's own ack must not self-license it. */
|
|
103
|
+
private recentPreflights;
|
|
104
|
+
/** Per-slug escalation dedup for the aggregate bound. */
|
|
105
|
+
private escalatedSlugs;
|
|
106
|
+
constructor(opts: OutboundAdvisoryAuditOptions);
|
|
107
|
+
/**
|
|
108
|
+
* Record a PREFLIGHT outcome (the preflight route is the caller).
|
|
109
|
+
* action is derived: advisories present → 'advised', none → 'clean'.
|
|
110
|
+
* Never throws — audit failure must never affect delivery.
|
|
111
|
+
*/
|
|
112
|
+
recordPreflight(entry: {
|
|
113
|
+
topicId: number;
|
|
114
|
+
jobSlug: string;
|
|
115
|
+
kind: string;
|
|
116
|
+
text: string;
|
|
117
|
+
advisories: string[];
|
|
118
|
+
}): AdvisoryAction;
|
|
119
|
+
/**
|
|
120
|
+
* Record an ACK (the /telegram/reply route is the single writer of 'acked'
|
|
121
|
+
* — it fires when a send carries metadata.advisoryAck). Resolves the
|
|
122
|
+
* signature's unresolved episodes when the codes match; counts consecutive
|
|
123
|
+
* non-empty-advisory acks for the preemptive-ack consumer.
|
|
124
|
+
*/
|
|
125
|
+
recordAck(entry: {
|
|
126
|
+
topicId: number;
|
|
127
|
+
jobSlug: string;
|
|
128
|
+
kind: string;
|
|
129
|
+
text: string;
|
|
130
|
+
advisories: string[];
|
|
131
|
+
}): void;
|
|
132
|
+
/**
|
|
133
|
+
* §2.1 spoof correlation: was there a PREFLIGHT-written (clean/advised)
|
|
134
|
+
* row for this slug+topic recently? Acked rows deliberately don't count.
|
|
135
|
+
*/
|
|
136
|
+
hasRecentPreflight(jobSlug: string, topicId: number, windowMs?: number): boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Bounded tail read for GET /messaging/advisory-log — reads the last
|
|
139
|
+
* `maxBytes` of the file (default 256KB), NEVER the whole file, and
|
|
140
|
+
* returns up to `limit` newest parsed entries.
|
|
141
|
+
*/
|
|
142
|
+
readTail(limit?: number, maxBytes?: number): AdvisoryAuditEntry[];
|
|
143
|
+
private signature;
|
|
144
|
+
private pruneEpisodes;
|
|
145
|
+
private prunePreflights;
|
|
146
|
+
private resolveNearIdentical;
|
|
147
|
+
private maybeEscalateIgnore;
|
|
148
|
+
private maybeEscalatePreemptiveAck;
|
|
149
|
+
private appendLine;
|
|
150
|
+
private rotateIfNeeded;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=OutboundAdvisory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OutboundAdvisory.d.ts","sourceRoot":"","sources":["../../src/messaging/OutboundAdvisory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAWH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAEzE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAgBD,6EAA6E;AAC7E,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CA6C1D;AAID,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,IAAI,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;QACpC,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,4BAA4B;IAC3C,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;IAClC,8DAA8D;IAC9D,gBAAgB,CAAC,EAAE,MAAM,MAAM,CAAC;IAChC,oFAAoF;IACpF,cAAc,CAAC,EAAE,eAAe,CAAC;CAClC;AAED,kFAAkF;AAClF,eAAO,MAAM,0BAA0B,iCAAiC,CAAC;AAqDzE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,kBAAkB,CAAe;IACzC,OAAO,CAAC,gBAAgB,CAAe;IACvC,OAAO,CAAC,cAAc,CAAyB;IAE/C,sEAAsE;IACtE,OAAO,CAAC,UAAU,CAAqC;IACvD;;qDAEiD;IACjD,OAAO,CAAC,gBAAgB,CAA6B;IACrD,yDAAyD;IACzD,OAAO,CAAC,cAAc,CAAqB;gBAE/B,IAAI,EAAE,4BAA4B;IAQ9C;;;;OAIG;IACH,eAAe,CAAC,KAAK,EAAE;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,GAAG,cAAc;IAyClB;;;;;OAKG;IACH,SAAS,CAAC,KAAK,EAAE;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,GAAG,IAAI;IA6BR;;;OAGG;IACH,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,SAA6B,GAAG,OAAO;IAKpG;;;;OAIG;IACH,QAAQ,CAAC,KAAK,SAAK,EAAE,QAAQ,SAAa,GAAG,kBAAkB,EAAE;IA+BjE,OAAO,CAAC,SAAS;IAwBjB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,mBAAmB;IA+D3B,OAAO,CAAC,0BAA0B;IAuBlC,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,cAAc;CAUvB"}
|