@senpi/runtime 3.0.123 → 3.0.124
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/actions/action-events.d.ts +7 -21
- package/dist/actions/action-events.d.ts.map +1 -1
- package/dist/actions/action-events.js +26 -54
- package/dist/actions/action-events.js.map +1 -1
- package/dist/actions/action-runtime-module.d.ts.map +1 -1
- package/dist/actions/action-runtime-module.js +7 -38
- package/dist/actions/action-runtime-module.js.map +1 -1
- package/dist/actions/close-position/close-position.action.d.ts.map +1 -1
- package/dist/actions/close-position/close-position.action.js +15 -122
- package/dist/actions/close-position/close-position.action.js.map +1 -1
- package/dist/actions/decision-engine.d.ts.map +1 -1
- package/dist/actions/decision-engine.js +2 -15
- package/dist/actions/decision-engine.js.map +1 -1
- package/dist/actions/event-derivation.d.ts +2 -71
- package/dist/actions/event-derivation.d.ts.map +1 -1
- package/dist/actions/event-derivation.js +8 -251
- package/dist/actions/event-derivation.js.map +1 -1
- package/dist/actions/open-position/open-position.action.d.ts +2 -17
- package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
- package/dist/actions/open-position/open-position.action.js +47 -162
- package/dist/actions/open-position/open-position.action.js.map +1 -1
- package/dist/actions/position-tracker/position-tracker.action.d.ts +1 -2
- package/dist/actions/position-tracker/position-tracker.action.d.ts.map +1 -1
- package/dist/actions/position-tracker/position-tracker.action.js +17 -62
- package/dist/actions/position-tracker/position-tracker.action.js.map +1 -1
- package/dist/actions/store/types.d.ts +2 -9
- package/dist/actions/store/types.d.ts.map +1 -1
- package/dist/actions/store/types.js.map +1 -1
- package/dist/actions/types.d.ts +0 -13
- package/dist/actions/types.d.ts.map +1 -1
- package/dist/actions/types.js +0 -13
- package/dist/actions/types.js.map +1 -1
- package/dist/cli/guide-commands.d.ts.map +1 -1
- package/dist/cli/guide-commands.js +0 -3
- package/dist/cli/guide-commands.js.map +1 -1
- package/dist/dsl/engine-client/event-mapping.d.ts.map +1 -1
- package/dist/dsl/engine-client/event-mapping.js +0 -14
- package/dist/dsl/engine-client/event-mapping.js.map +1 -1
- package/dist/dsl/events/build-closed-event.d.ts +1 -16
- package/dist/dsl/events/build-closed-event.d.ts.map +1 -1
- package/dist/dsl/events/build-closed-event.js +0 -6
- package/dist/dsl/events/build-closed-event.js.map +1 -1
- package/dist/dsl/events/handlers.d.ts +0 -7
- package/dist/dsl/events/handlers.d.ts.map +1 -1
- package/dist/dsl/events/handlers.js +7 -37
- package/dist/dsl/events/handlers.js.map +1 -1
- package/dist/dsl/monitor/create-monitor.d.ts +2 -6
- package/dist/dsl/monitor/create-monitor.d.ts.map +1 -1
- package/dist/dsl/monitor/create-monitor.js +9 -15
- package/dist/dsl/monitor/create-monitor.js.map +1 -1
- package/dist/dsl/monitor/dsl-failure-events.d.ts +0 -2
- package/dist/dsl/monitor/dsl-failure-events.d.ts.map +1 -1
- package/dist/dsl/monitor/dsl-failure-events.js +1 -2
- package/dist/dsl/monitor/dsl-failure-events.js.map +1 -1
- package/dist/dsl/monitor/process-one-position.d.ts +0 -1
- package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
- package/dist/dsl/monitor/process-one-position.js +25 -59
- package/dist/dsl/monitor/process-one-position.js.map +1 -1
- package/dist/dsl/plugin/index.d.ts +2 -8
- package/dist/dsl/plugin/index.d.ts.map +1 -1
- package/dist/dsl/plugin/index.js +6 -8
- package/dist/dsl/plugin/index.js.map +1 -1
- package/dist/health/types.d.ts +0 -13
- package/dist/health/types.d.ts.map +1 -1
- package/dist/health/types.js +0 -12
- package/dist/health/types.js.map +1 -1
- package/dist/index.d.ts +4 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +42 -254
- package/dist/index.js.map +1 -1
- package/dist/runtime/action-registry.d.ts.map +1 -1
- package/dist/runtime/action-registry.js +3 -4
- package/dist/runtime/action-registry.js.map +1 -1
- package/dist/runtime/domain-events.d.ts.map +1 -1
- package/dist/runtime/domain-events.js +0 -7
- package/dist/runtime/domain-events.js.map +1 -1
- package/dist/runtime/lifecycle-events.d.ts +1 -9
- package/dist/runtime/lifecycle-events.d.ts.map +1 -1
- package/dist/runtime/lifecycle-events.js +2 -11
- package/dist/runtime/lifecycle-events.js.map +1 -1
- package/dist/runtime/reconcile-run.d.ts +3 -13
- package/dist/runtime/reconcile-run.d.ts.map +1 -1
- package/dist/runtime/reconcile-run.js +3 -4
- package/dist/runtime/reconcile-run.js.map +1 -1
- package/dist/runtime/reconcile-state.d.ts +0 -8
- package/dist/runtime/reconcile-state.d.ts.map +1 -1
- package/dist/runtime/reconcile-state.js +1 -4
- package/dist/runtime/reconcile-state.js.map +1 -1
- package/dist/runtime/run.d.ts +0 -1
- package/dist/runtime/run.d.ts.map +1 -1
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/runtime-schema.js +3 -3
- package/dist/runtime/runtime-schema.js.map +1 -1
- package/dist/runtime/runtime.d.ts +0 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +3 -27
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/supervisor/long-running-supervisor.d.ts +0 -13
- package/dist/runtime/supervisor/long-running-supervisor.d.ts.map +1 -1
- package/dist/runtime/supervisor/long-running-supervisor.js +0 -1
- package/dist/runtime/supervisor/long-running-supervisor.js.map +1 -1
- package/dist/runtime/validate-dsl-position-tracking.d.ts.map +1 -1
- package/dist/runtime/validate-dsl-position-tracking.js +1 -2
- package/dist/runtime/validate-dsl-position-tracking.js.map +1 -1
- package/dist/runtime-api/handlers/ingest-signals.d.ts.map +1 -1
- package/dist/runtime-api/handlers/ingest-signals.js +0 -1
- package/dist/runtime-api/handlers/ingest-signals.js.map +1 -1
- package/dist/runtime-api/handlers/types.d.ts +0 -5
- package/dist/runtime-api/handlers/types.d.ts.map +1 -1
- package/dist/runtime-api/intake/intake-events.d.ts +1 -1
- package/dist/runtime-api/intake/intake-events.d.ts.map +1 -1
- package/dist/runtime-api/intake/intake-events.js +3 -9
- package/dist/runtime-api/intake/intake-events.js.map +1 -1
- package/dist/runtime-api/intake/intake-mount.d.ts.map +1 -1
- package/dist/runtime-api/intake/intake-mount.js +19 -4
- package/dist/runtime-api/intake/intake-mount.js.map +1 -1
- package/dist/runtime-api/intake/process-error-post.d.ts +1 -6
- package/dist/runtime-api/intake/process-error-post.d.ts.map +1 -1
- package/dist/runtime-api/intake/process-error-post.js +1 -5
- package/dist/runtime-api/intake/process-error-post.js.map +1 -1
- package/dist/runtime-api/intake/process-signal-post.d.ts +1 -7
- package/dist/runtime-api/intake/process-signal-post.d.ts.map +1 -1
- package/dist/runtime-api/intake/process-signal-post.js +0 -5
- package/dist/runtime-api/intake/process-signal-post.js.map +1 -1
- package/dist/runtime-api/intake/scaffold-error-router.js.map +1 -1
- package/dist/runtime-api/intake/scanner-launcher.d.ts.map +1 -1
- package/dist/runtime-api/intake/scanner-launcher.js +0 -15
- package/dist/runtime-api/intake/scanner-launcher.js.map +1 -1
- package/dist/runtime-api/intake/types.d.ts +0 -55
- package/dist/runtime-api/intake/types.d.ts.map +1 -1
- package/dist/runtime-api/routes/signals.d.ts +0 -2
- package/dist/runtime-api/routes/signals.d.ts.map +1 -1
- package/dist/runtime-api/routes/signals.js +1 -5
- package/dist/runtime-api/routes/signals.js.map +1 -1
- package/dist/runtime-api/routes/signals.schema.d.ts +0 -43
- package/dist/runtime-api/routes/signals.schema.d.ts.map +1 -1
- package/dist/runtime-api/routes/signals.schema.js +0 -43
- package/dist/runtime-api/routes/signals.schema.js.map +1 -1
- package/dist/runtime-api/server.d.ts +1 -7
- package/dist/runtime-api/server.d.ts.map +1 -1
- package/dist/runtime-api/server.js +0 -1
- package/dist/runtime-api/server.js.map +1 -1
- package/dist/scanners/engine/engine.d.ts +1 -22
- package/dist/scanners/engine/engine.d.ts.map +1 -1
- package/dist/scanners/engine/engine.js +11 -78
- package/dist/scanners/engine/engine.js.map +1 -1
- package/dist/scanners/engine/lifecycle.d.ts +1 -7
- package/dist/scanners/engine/lifecycle.d.ts.map +1 -1
- package/dist/scanners/events.d.ts +0 -4
- package/dist/scanners/events.d.ts.map +1 -1
- package/dist/scanners/events.js +0 -2
- package/dist/scanners/events.js.map +1 -1
- package/dist/scanners/external/scaffold/delivery.py +25 -194
- package/dist/scanners/external/scaffold/scaffold.py +31 -172
- package/dist/scanners/external/scaffold/senpi_mcp.py +8 -150
- package/dist/scanners/external-scanner-receiver.d.ts +0 -17
- package/dist/scanners/external-scanner-receiver.d.ts.map +1 -1
- package/dist/scanners/external-scanner-receiver.js +0 -8
- package/dist/scanners/external-scanner-receiver.js.map +1 -1
- package/dist/scanners/runtime-module.d.ts +0 -1
- package/dist/scanners/runtime-module.d.ts.map +1 -1
- package/dist/scanners/runtime-module.js +9 -66
- package/dist/scanners/runtime-module.js.map +1 -1
- package/dist/telemetry/attributes.d.ts +0 -20
- package/dist/telemetry/attributes.d.ts.map +1 -1
- package/dist/telemetry/attributes.js +0 -24
- package/dist/telemetry/attributes.js.map +1 -1
- package/dist/telemetry/event-builders.d.ts +6 -81
- package/dist/telemetry/event-builders.d.ts.map +1 -1
- package/dist/telemetry/event-builders.js +17 -141
- package/dist/telemetry/event-builders.js.map +1 -1
- package/dist/telemetry/event-store.d.ts +0 -6
- package/dist/telemetry/event-store.d.ts.map +1 -1
- package/dist/telemetry/event-store.js +8 -12
- package/dist/telemetry/event-store.js.map +1 -1
- package/dist/telemetry/metrics.d.ts +2 -14
- package/dist/telemetry/metrics.d.ts.map +1 -1
- package/dist/telemetry/metrics.js +4 -19
- package/dist/telemetry/metrics.js.map +1 -1
- package/dist/telemetry/spans/redact-pii.d.ts.map +1 -1
- package/dist/telemetry/spans/redact-pii.js +2 -18
- package/dist/telemetry/spans/redact-pii.js.map +1 -1
- package/dist/telemetry/tracing.d.ts +0 -9
- package/dist/telemetry/tracing.d.ts.map +1 -1
- package/dist/telemetry/tracing.js +0 -36
- package/dist/telemetry/tracing.js.map +1 -1
- package/dist/types/dsl/index.d.ts +0 -11
- package/dist/types/dsl/index.d.ts.map +1 -1
- package/dist/types/scanner.d.ts +0 -15
- package/dist/types/scanner.d.ts.map +1 -1
- package/dist/utils/event-catalog.d.ts +0 -166
- package/dist/utils/event-catalog.d.ts.map +1 -1
- package/dist/utils/event-catalog.js +0 -18
- package/dist/utils/event-catalog.js.map +1 -1
- package/dist/utils/logger.d.ts +1 -4
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js.map +1 -1
- package/dist/validate/recipe-checks.d.ts.map +1 -1
- package/dist/validate/recipe-checks.js +2 -2
- package/dist/validate/recipe-checks.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/actions/skipped-signal-results.d.ts +0 -25
- package/dist/actions/skipped-signal-results.d.ts.map +0 -1
- package/dist/actions/skipped-signal-results.js +0 -71
- package/dist/actions/skipped-signal-results.js.map +0 -1
- package/dist/runtime-api/intake/ingest-request.d.ts +0 -17
- package/dist/runtime-api/intake/ingest-request.d.ts.map +0 -1
- package/dist/runtime-api/intake/ingest-request.js +0 -34
- package/dist/runtime-api/intake/ingest-request.js.map +0 -1
- package/dist/runtime-api/intake/scaffold-tick-router.d.ts +0 -39
- package/dist/runtime-api/intake/scaffold-tick-router.d.ts.map +0 -1
- package/dist/runtime-api/intake/scaffold-tick-router.js +0 -122
- package/dist/runtime-api/intake/scaffold-tick-router.js.map +0 -1
- package/dist/scanners/external/scaffold/tick_facts.py +0 -130
- package/dist/scanners/external/scaffold/ulid.py +0 -58
- package/dist/telemetry/live-telemetry.d.ts +0 -238
- package/dist/telemetry/live-telemetry.d.ts.map +0 -1
- package/dist/telemetry/live-telemetry.js +0 -853
- package/dist/telemetry/live-telemetry.js.map +0 -1
- package/dist/telemetry/scanner-stats.d.ts +0 -143
- package/dist/telemetry/scanner-stats.d.ts.map +0 -1
- package/dist/telemetry/scanner-stats.js +0 -426
- package/dist/telemetry/scanner-stats.js.map +0 -1
- package/dist/telemetry/scanner-tick-feed.d.ts +0 -87
- package/dist/telemetry/scanner-tick-feed.d.ts.map +0 -1
- package/dist/telemetry/scanner-tick-feed.js +0 -48
- package/dist/telemetry/scanner-tick-feed.js.map +0 -1
- package/dist/telemetry/strategy-topology.d.ts +0 -99
- package/dist/telemetry/strategy-topology.d.ts.map +0 -1
- package/dist/telemetry/strategy-topology.js +0 -93
- package/dist/telemetry/strategy-topology.js.map +0 -1
- package/dist/telemetry/telemetry-publisher.d.ts +0 -63
- package/dist/telemetry/telemetry-publisher.d.ts.map +0 -1
- package/dist/telemetry/telemetry-publisher.js +0 -229
- package/dist/telemetry/telemetry-publisher.js.map +0 -1
- package/dist/telemetry/tick-frame.d.ts +0 -212
- package/dist/telemetry/tick-frame.d.ts.map +0 -1
- package/dist/telemetry/tick-frame.js +0 -421
- package/dist/telemetry/tick-frame.js.map +0 -1
- package/dist/telemetry/timeline-buffer.d.ts +0 -95
- package/dist/telemetry/timeline-buffer.d.ts.map +0 -1
- package/dist/telemetry/timeline-buffer.js +0 -237
- package/dist/telemetry/timeline-buffer.js.map +0 -1
- package/dist/utils/telemetry-required-log.d.ts +0 -60
- package/dist/utils/telemetry-required-log.d.ts.map +0 -1
- package/dist/utils/telemetry-required-log.js +0 -105
- package/dist/utils/telemetry-required-log.js.map +0 -1
- package/dist/utils/ulid.d.ts +0 -9
- package/dist/utils/ulid.d.ts.map +0 -1
- package/dist/utils/ulid.js +0 -43
- package/dist/utils/ulid.js.map +0 -1
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-signal `results[]` rows synthesized for a batch-level early exit — the exits that return
|
|
3
|
-
* before the per-signal loop and would otherwise leave the scan's signals with no recorded outcome.
|
|
4
|
-
* Entry shape matches the loop's own rows so the derived per-signal telemetry is identical in
|
|
5
|
-
* structure: normalized `dex`, `direction`/`score` only when usable, and a zero-width work window
|
|
6
|
-
* (both stamps present — a half window is dropped downstream, and a missing one is
|
|
7
|
-
* indistinguishable from an unstamped legacy row).
|
|
8
|
-
*
|
|
9
|
-
* Each row carries `__signalIndex`, its position in the INPUT list, so the event mapper pairs the
|
|
10
|
-
* row with THIS signal's `meta` rather than with the first signal sharing its asset. It is read
|
|
11
|
-
* inside the loop, not zipped on by the caller: a dropped signal shifts every later output
|
|
12
|
-
* position. The input list is the scan's own signal array, which is what the mapper indexes into;
|
|
13
|
-
* close-position's static-params fallback list has no scan array behind it, so its index matches
|
|
14
|
-
* nothing and the mapper degrades to its asset join, as it does for any unmatched index.
|
|
15
|
-
*
|
|
16
|
-
* A signal with no usable asset is dropped: an outcome that names no asset is not attributable.
|
|
17
|
-
* A drop is a hole in the "no signal goes unrecorded" contract, so it is logged (once per call,
|
|
18
|
-
* with the count) rather than passing silently. Counts are unaffected — the row is still absent.
|
|
19
|
-
* Total by construction — it runs on the trading path and must never throw on a malformed entry.
|
|
20
|
-
*/
|
|
21
|
-
export declare function skippedSignalResults(signals: readonly unknown[] | undefined, reason: string, nowMs: number, overrides?: {
|
|
22
|
-
success?: boolean;
|
|
23
|
-
error?: string;
|
|
24
|
-
}): Array<Record<string, unknown>>;
|
|
25
|
-
//# sourceMappingURL=skipped-signal-results.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"skipped-signal-results.d.ts","sourceRoot":"","sources":["../../src/actions/skipped-signal-results.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,EACvC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA8ChC"}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { createLogger } from '../utils/logger.js';
|
|
2
|
-
const logger = createLogger('[actions][skipped-signal-results]');
|
|
3
|
-
/**
|
|
4
|
-
* Per-signal `results[]` rows synthesized for a batch-level early exit — the exits that return
|
|
5
|
-
* before the per-signal loop and would otherwise leave the scan's signals with no recorded outcome.
|
|
6
|
-
* Entry shape matches the loop's own rows so the derived per-signal telemetry is identical in
|
|
7
|
-
* structure: normalized `dex`, `direction`/`score` only when usable, and a zero-width work window
|
|
8
|
-
* (both stamps present — a half window is dropped downstream, and a missing one is
|
|
9
|
-
* indistinguishable from an unstamped legacy row).
|
|
10
|
-
*
|
|
11
|
-
* Each row carries `__signalIndex`, its position in the INPUT list, so the event mapper pairs the
|
|
12
|
-
* row with THIS signal's `meta` rather than with the first signal sharing its asset. It is read
|
|
13
|
-
* inside the loop, not zipped on by the caller: a dropped signal shifts every later output
|
|
14
|
-
* position. The input list is the scan's own signal array, which is what the mapper indexes into;
|
|
15
|
-
* close-position's static-params fallback list has no scan array behind it, so its index matches
|
|
16
|
-
* nothing and the mapper degrades to its asset join, as it does for any unmatched index.
|
|
17
|
-
*
|
|
18
|
-
* A signal with no usable asset is dropped: an outcome that names no asset is not attributable.
|
|
19
|
-
* A drop is a hole in the "no signal goes unrecorded" contract, so it is logged (once per call,
|
|
20
|
-
* with the count) rather than passing silently. Counts are unaffected — the row is still absent.
|
|
21
|
-
* Total by construction — it runs on the trading path and must never throw on a malformed entry.
|
|
22
|
-
*/
|
|
23
|
-
export function skippedSignalResults(signals, reason, nowMs, overrides) {
|
|
24
|
-
if (!Array.isArray(signals))
|
|
25
|
-
return [];
|
|
26
|
-
const rows = [];
|
|
27
|
-
let dropped = 0;
|
|
28
|
-
for (const [index, raw] of signals.entries()) {
|
|
29
|
-
if (raw === null || typeof raw !== 'object') {
|
|
30
|
-
dropped++;
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
const signal = raw;
|
|
34
|
-
const rawAsset = signal.asset;
|
|
35
|
-
// Kept verbatim (not trimmed) so it still joins the scanner signal it came from.
|
|
36
|
-
const asset = typeof rawAsset === 'string' ? rawAsset : typeof rawAsset === 'number' ? String(rawAsset) : '';
|
|
37
|
-
if (asset.trim() === '') {
|
|
38
|
-
dropped++;
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
const direction = signal.direction;
|
|
42
|
-
const score = signal.score;
|
|
43
|
-
// A decision-payload signal carries the book top-level (the strategy hoists it there); a raw
|
|
44
|
-
// scanner signal carries it only on `meta`, since `Signal` has no `dex` field. Both call
|
|
45
|
-
// shapes reach this helper, so both are read — top-level first, matching the per-signal loop.
|
|
46
|
-
const meta = signal.meta;
|
|
47
|
-
const metaDex = meta !== null && typeof meta === 'object' ? meta.dex : undefined;
|
|
48
|
-
const dex = typeof signal.dex === 'string' && signal.dex.trim() !== '' ? signal.dex : metaDex;
|
|
49
|
-
rows.push({
|
|
50
|
-
asset,
|
|
51
|
-
...(direction === 'LONG' || direction === 'SHORT' ? { direction } : {}),
|
|
52
|
-
dex: typeof dex === 'string' && dex.trim() !== '' ? dex.trim() : 'main',
|
|
53
|
-
...(typeof score === 'number' && Number.isFinite(score) ? { score } : {}),
|
|
54
|
-
success: overrides?.success ?? true,
|
|
55
|
-
reason,
|
|
56
|
-
...(overrides?.error !== undefined ? { error: overrides.error } : {}),
|
|
57
|
-
startedAt: nowMs,
|
|
58
|
-
endedAt: nowMs,
|
|
59
|
-
__signalIndex: index,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
if (dropped > 0) {
|
|
63
|
-
logger.warn('signals dropped from the skip rows: no usable asset to attribute the outcome to', undefined, {
|
|
64
|
-
reason,
|
|
65
|
-
dropped,
|
|
66
|
-
recorded: rows.length,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
return rows;
|
|
70
|
-
}
|
|
71
|
-
//# sourceMappingURL=skipped-signal-results.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"skipped-signal-results.js","sourceRoot":"","sources":["../../src/actions/skipped-signal-results.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* IntakeSignal → ExternalScannerIngestRequest.
|
|
3
|
-
*
|
|
4
|
-
* The single mapping between the intake wire shape and the engine's ingest shape. Both accept
|
|
5
|
-
* seams call it: the live route closure in `src/index.ts` and `buildIntakeMount`'s `onAccepted`.
|
|
6
|
-
*/
|
|
7
|
-
import type { ExternalScannerIngestRequest } from "../../scanners/external-scanner-receiver.js";
|
|
8
|
-
import type { ScannerId } from "../../scanners/types.js";
|
|
9
|
-
import type { IntakeSignal } from "./types.js";
|
|
10
|
-
/**
|
|
11
|
-
* Narrow one accepted intake signal to the ingest request the engine takes.
|
|
12
|
-
*
|
|
13
|
-
* @param scannerName Configured scanner NAME resolved from the registry, not the wire `scanner_id`.
|
|
14
|
-
* @param correlationId Intake-minted id of the acceptance row that admitted this signal.
|
|
15
|
-
*/
|
|
16
|
-
export declare function toIngestRequest(signal: IntakeSignal, correlationId: string, scannerName: ScannerId): ExternalScannerIngestRequest;
|
|
17
|
-
//# sourceMappingURL=ingest-request.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ingest-request.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/intake/ingest-request.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,6CAA6C,CAAC;AAChG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,YAAY,EACpB,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,SAAS,GACrB,4BAA4B,CAoB9B"}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* IntakeSignal → ExternalScannerIngestRequest.
|
|
3
|
-
*
|
|
4
|
-
* The single mapping between the intake wire shape and the engine's ingest shape. Both accept
|
|
5
|
-
* seams call it: the live route closure in `src/index.ts` and `buildIntakeMount`'s `onAccepted`.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Narrow one accepted intake signal to the ingest request the engine takes.
|
|
9
|
-
*
|
|
10
|
-
* @param scannerName Configured scanner NAME resolved from the registry, not the wire `scanner_id`.
|
|
11
|
-
* @param correlationId Intake-minted id of the acceptance row that admitted this signal.
|
|
12
|
-
*/
|
|
13
|
-
export function toIngestRequest(signal, correlationId, scannerName) {
|
|
14
|
-
return {
|
|
15
|
-
scanner: scannerName,
|
|
16
|
-
signal_id: signal.signal_id, // greppable handle across intake→ingest (obs only)
|
|
17
|
-
asset: signal.asset,
|
|
18
|
-
direction: signal.direction,
|
|
19
|
-
...(signal.signal_type !== undefined && { signal_type: signal.signal_type }),
|
|
20
|
-
data: signal.data,
|
|
21
|
-
// Per-signal sizing rides at the top level; the open-position action reads
|
|
22
|
-
// request.marginPct / request.leverage directly, else a supervised signal's
|
|
23
|
-
// sizing is lost ("no margin source resolved").
|
|
24
|
-
...(signal.marginPct !== undefined && { marginPct: signal.marginPct }),
|
|
25
|
-
...(signal.leverage !== undefined && { leverage: signal.leverage }),
|
|
26
|
-
// The producing scan and the admitting acceptance row.
|
|
27
|
-
tick_id: signal.tick_id,
|
|
28
|
-
correlationId,
|
|
29
|
-
// Intentionally omitted: score (intake has none, defaults to 0 downstream),
|
|
30
|
-
// valid_until/produced_at (acceptance-pipeline concerns, not ingest fields),
|
|
31
|
-
// signals[] (single-signal shape: data, not signals[]).
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
//# sourceMappingURL=ingest-request.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ingest-request.js","sourceRoot":"","sources":["../../../src/runtime-api/intake/ingest-request.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAoB,EACpB,aAAqB,EACrB,WAAsB;IAEtB,OAAO;QACL,OAAO,EAAE,WAAW;QACpB,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,mDAAmD;QAChF,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC;QAC5E,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,2EAA2E;QAC3E,4EAA4E;QAC5E,gDAAgD;QAChD,GAAG,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;QACtE,GAAG,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;QACnE,uDAAuD;QACvD,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,aAAa;QACb,4EAA4E;QAC5E,6EAA6E;QAC7E,wDAAwD;KACzD,CAAC;AACJ,CAAC"}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `/signals` and `/errors` routes' `onTick` — one implementation, used by both.
|
|
3
|
-
*
|
|
4
|
-
* A supervised external scanner runs in its own Python process, so the only facts the runtime has
|
|
5
|
-
* about one of its ticks are the ones that arrive over the intake. Both routes already fire once
|
|
6
|
-
* per tick — `/signals` on every clean tick including a quiet one, `/errors` on every failed one —
|
|
7
|
-
* so the facts ride the request that tick already makes. No second channel, no extra POST, and a
|
|
8
|
-
* producer that sends none behaves exactly as it did before.
|
|
9
|
-
*
|
|
10
|
-
* What this does with them is hand the run to the SAME process sink the in-process scanner runtime
|
|
11
|
-
* hands its own finished runs to ({@link ../../telemetry/scanner-tick-feed.js}), which is a no-op
|
|
12
|
-
* until a client is watching. Nothing here reaches `logger.event` or `appendDomainEvent`: a tick is
|
|
13
|
-
* a LEVEL, and per-tick records would evict real decision rows from the on-disk ring and the
|
|
14
|
-
* publisher's bounded buffer.
|
|
15
|
-
*
|
|
16
|
-
* ABSENT IS NOT ZERO, end to end. A field the producer did not send is left off the run rather than
|
|
17
|
-
* defaulted, so the publisher can leave it off the frame and the screen can print "unknown" instead
|
|
18
|
-
* of a number nobody measured.
|
|
19
|
-
*/
|
|
20
|
-
import { type ScannerTickExtras } from "../../telemetry/scanner-tick-feed.js";
|
|
21
|
-
import type { IntakeContext } from "./intake-context.js";
|
|
22
|
-
import type { IntakeTickFacts } from "./types.js";
|
|
23
|
-
/** The producer's facts as the tick feed's extras, with every unreadable field left off. */
|
|
24
|
-
export declare function toTickExtras(facts: IntakeTickFacts): ScannerTickExtras;
|
|
25
|
-
/**
|
|
26
|
-
* Build the `onTick` both intake routes call.
|
|
27
|
-
*
|
|
28
|
-
* Resolves against the SHARED IntakeContext registry, like `onAccepted` and `onScaffoldError`, so
|
|
29
|
-
* the tick is attributed to the scanner's STABLE name and its runtime's wallet rather than to the
|
|
30
|
-
* ephemeral scanner_id a relaunch re-mints — which is the key a client joins a tick to its stats
|
|
31
|
-
* row on.
|
|
32
|
-
*
|
|
33
|
-
* `now` is the runtime clock at the POST, used as the run's finish. The producer's own clock is not
|
|
34
|
-
* used: it is a different machine's wall time, and a frame mixing the two would put ticks in an
|
|
35
|
-
* order neither machine saw. `startedAt` is derived from the duration the producer measured, which
|
|
36
|
-
* keeps `ms` the producer's own number while `t` stays on this box's clock.
|
|
37
|
-
*/
|
|
38
|
-
export declare function buildScaffoldTickRouter(ctx: IntakeContext, now?: () => number): (scannerId: string, facts: IntakeTickFacts) => void;
|
|
39
|
-
//# sourceMappingURL=scaffold-tick-router.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold-tick-router.d.ts","sourceRoot":"","sources":["../../../src/runtime-api/intake/scaffold-tick-router.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,YAAY,CAAC;AAkClE,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,iBAAiB,CA+BtE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,aAAa,EAClB,GAAG,GAAE,MAAM,MAAyB,GACnC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,KAAK,IAAI,CAqBrD"}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The `/signals` and `/errors` routes' `onTick` — one implementation, used by both.
|
|
3
|
-
*
|
|
4
|
-
* A supervised external scanner runs in its own Python process, so the only facts the runtime has
|
|
5
|
-
* about one of its ticks are the ones that arrive over the intake. Both routes already fire once
|
|
6
|
-
* per tick — `/signals` on every clean tick including a quiet one, `/errors` on every failed one —
|
|
7
|
-
* so the facts ride the request that tick already makes. No second channel, no extra POST, and a
|
|
8
|
-
* producer that sends none behaves exactly as it did before.
|
|
9
|
-
*
|
|
10
|
-
* What this does with them is hand the run to the SAME process sink the in-process scanner runtime
|
|
11
|
-
* hands its own finished runs to ({@link ../../telemetry/scanner-tick-feed.js}), which is a no-op
|
|
12
|
-
* until a client is watching. Nothing here reaches `logger.event` or `appendDomainEvent`: a tick is
|
|
13
|
-
* a LEVEL, and per-tick records would evict real decision rows from the on-disk ring and the
|
|
14
|
-
* publisher's bounded buffer.
|
|
15
|
-
*
|
|
16
|
-
* ABSENT IS NOT ZERO, end to end. A field the producer did not send is left off the run rather than
|
|
17
|
-
* defaulted, so the publisher can leave it off the frame and the screen can print "unknown" instead
|
|
18
|
-
* of a number nobody measured.
|
|
19
|
-
*/
|
|
20
|
-
import { hasScannerTickSink, recordScannerTick, } from "../../telemetry/scanner-tick-feed.js";
|
|
21
|
-
/** The commit endings this box publishes. Anything else a producer sends is dropped, not relayed. */
|
|
22
|
-
const COMMIT_OUTCOMES = new Set([
|
|
23
|
-
"committed",
|
|
24
|
-
"rolled_back",
|
|
25
|
-
"persist_failed",
|
|
26
|
-
]);
|
|
27
|
-
/** A finite, non-negative number, or `undefined` — which is how an unknown stays unknown. */
|
|
28
|
-
function count(value) {
|
|
29
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
30
|
-
}
|
|
31
|
-
function calls(rows) {
|
|
32
|
-
if (!Array.isArray(rows))
|
|
33
|
-
return undefined;
|
|
34
|
-
const out = [];
|
|
35
|
-
for (const row of rows) {
|
|
36
|
-
if (row === null || typeof row !== "object")
|
|
37
|
-
continue;
|
|
38
|
-
if (typeof row.tool !== "string" || row.tool.length === 0)
|
|
39
|
-
continue;
|
|
40
|
-
out.push({
|
|
41
|
-
tool: row.tool,
|
|
42
|
-
...(count(row.ms) === undefined ? {} : { ms: count(row.ms) }),
|
|
43
|
-
...(row.args !== null && typeof row.args === "object" && !Array.isArray(row.args)
|
|
44
|
-
? { args: row.args }
|
|
45
|
-
: {}),
|
|
46
|
-
...(typeof row.error_type === "string" && row.error_type.length > 0
|
|
47
|
-
? { errorType: row.error_type }
|
|
48
|
-
: {}),
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
return out;
|
|
52
|
-
}
|
|
53
|
-
/** The producer's facts as the tick feed's extras, with every unreadable field left off. */
|
|
54
|
-
export function toTickExtras(facts) {
|
|
55
|
-
const commit = typeof facts.commit === "string" && COMMIT_OUTCOMES.has(facts.commit)
|
|
56
|
-
? facts.commit
|
|
57
|
-
: undefined;
|
|
58
|
-
const state = facts.state !== null && typeof facts.state === "object" && !Array.isArray(facts.state)
|
|
59
|
-
? facts.state
|
|
60
|
-
: undefined;
|
|
61
|
-
const mcpCalls = calls(facts.mcp_calls);
|
|
62
|
-
return {
|
|
63
|
-
...(count(facts.mcp_failures) === undefined ? {} : { mcpFailures: count(facts.mcp_failures) }),
|
|
64
|
-
...(mcpCalls === undefined ? {} : { mcpCalls }),
|
|
65
|
-
...(count(facts.mcp_ms) === undefined ? {} : { mcpMs: count(facts.mcp_ms) }),
|
|
66
|
-
...(count(facts.quiet_ticks) === undefined ? {} : { quietTicks: count(facts.quiet_ticks) }),
|
|
67
|
-
// The only signed field: a tick that ran EARLY reports a negative lag, and the frame omits it.
|
|
68
|
-
...(typeof facts.lag_ms === "number" && Number.isFinite(facts.lag_ms)
|
|
69
|
-
? { lagMs: facts.lag_ms }
|
|
70
|
-
: {}),
|
|
71
|
-
...(count(facts.journal_pending) === undefined
|
|
72
|
-
? {}
|
|
73
|
-
: { journalPending: count(facts.journal_pending) }),
|
|
74
|
-
...(commit === undefined ? {} : { commit }),
|
|
75
|
-
...(state === undefined ? {} : { state }),
|
|
76
|
-
...(count(facts.state_fields) === undefined
|
|
77
|
-
? {}
|
|
78
|
-
: { stateFieldCount: count(facts.state_fields) }),
|
|
79
|
-
...(count(facts.state_changed) === undefined
|
|
80
|
-
? {}
|
|
81
|
-
: { stateChangedCount: count(facts.state_changed) }),
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Build the `onTick` both intake routes call.
|
|
86
|
-
*
|
|
87
|
-
* Resolves against the SHARED IntakeContext registry, like `onAccepted` and `onScaffoldError`, so
|
|
88
|
-
* the tick is attributed to the scanner's STABLE name and its runtime's wallet rather than to the
|
|
89
|
-
* ephemeral scanner_id a relaunch re-mints — which is the key a client joins a tick to its stats
|
|
90
|
-
* row on.
|
|
91
|
-
*
|
|
92
|
-
* `now` is the runtime clock at the POST, used as the run's finish. The producer's own clock is not
|
|
93
|
-
* used: it is a different machine's wall time, and a frame mixing the two would put ticks in an
|
|
94
|
-
* order neither machine saw. `startedAt` is derived from the duration the producer measured, which
|
|
95
|
-
* keeps `ms` the producer's own number while `t` stays on this box's clock.
|
|
96
|
-
*/
|
|
97
|
-
export function buildScaffoldTickRouter(ctx, now = () => Date.now()) {
|
|
98
|
-
return (scannerId, facts) => {
|
|
99
|
-
if (facts === null || typeof facts !== "object")
|
|
100
|
-
return;
|
|
101
|
-
// Checked first, before anything is built: a box no client has ever reached pays one
|
|
102
|
-
// comparison per tick and allocates nothing.
|
|
103
|
-
if (!hasScannerTickSink())
|
|
104
|
-
return;
|
|
105
|
-
const entry = ctx.registry.resolve(scannerId);
|
|
106
|
-
if (!entry)
|
|
107
|
-
return; // zombie fence — a relaunch re-mints the id and unregisters the old one
|
|
108
|
-
const finishedAt = now();
|
|
109
|
-
const durationMs = count(facts.duration_ms);
|
|
110
|
-
const run = {
|
|
111
|
-
address: entry.wallet,
|
|
112
|
-
scannerId: entry.scannerName,
|
|
113
|
-
status: typeof facts.status === "string" && facts.status.length > 0 ? facts.status : "ok",
|
|
114
|
-
...(count(facts.candidate_count) === undefined
|
|
115
|
-
? {}
|
|
116
|
-
: { signalCount: count(facts.candidate_count) }),
|
|
117
|
-
tick: toTickExtras(facts),
|
|
118
|
-
};
|
|
119
|
-
recordScannerTick(run, durationMs === undefined ? undefined : finishedAt - durationMs, finishedAt);
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
//# sourceMappingURL=scaffold-tick-router.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold-tick-router.js","sourceRoot":"","sources":["../../../src/runtime-api/intake/scaffold-tick-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
"""Per-tick observability facts the scaffold hands to the intake.
|
|
2
|
-
|
|
3
|
-
A scanner tick produces nothing on roughly 99% of ticks, so the only thing a
|
|
4
|
-
live screen can show about a working box is what the tick itself reports. These
|
|
5
|
-
facts are assembled here, once per tick, and ride the POST the delivery sink
|
|
6
|
-
already makes every tick — `/signals` on a clean tick, `/errors` on a failed
|
|
7
|
-
one. There is no second channel and no extra request.
|
|
8
|
-
|
|
9
|
-
ABSENT IS NOT ZERO. Every field is omitted when its value is unknown, never
|
|
10
|
-
defaulted. A `candidate_count` of 0 is a scanner that found nothing; an absent
|
|
11
|
-
one would be a scanner that did not say. The distinction has to survive from
|
|
12
|
-
here to the screen, so nothing in this module substitutes one for the other.
|
|
13
|
-
|
|
14
|
-
The state projection is the LAST COMMITTED row, which makes it stale by one tick
|
|
15
|
-
whenever the current tick failed. That is deliberate: a tick that could not
|
|
16
|
-
commit is exactly when the last agreed state is worth seeing.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
from __future__ import annotations
|
|
20
|
-
|
|
21
|
-
from typing import Any, Optional
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
# Per-value character ceiling inside a projected row. An author may park a whole
|
|
25
|
-
# serialised payload in one state key; this bounds what one tick can put on the
|
|
26
|
-
# wire without bounding what the author may store.
|
|
27
|
-
MAX_STATE_VALUE_CHARS = 1024
|
|
28
|
-
|
|
29
|
-
# Keys projected out of one state row. Bounds an author's open-ended row the way
|
|
30
|
-
# the runtime bounds an open attribute bag.
|
|
31
|
-
MAX_STATE_KEYS = 32
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _is_scalar(value: Any) -> bool:
|
|
35
|
-
"""A value a consumer can parse: str, bool, or a FINITE number.
|
|
36
|
-
|
|
37
|
-
bool is checked before the numeric branch only implicitly — it is accepted
|
|
38
|
-
either way. NaN and the infinities are rejected: they are not JSON, and a
|
|
39
|
-
consumer reading one has no way to tell it from a real measurement.
|
|
40
|
-
"""
|
|
41
|
-
if isinstance(value, bool) or isinstance(value, str):
|
|
42
|
-
return True
|
|
43
|
-
if isinstance(value, (int, float)):
|
|
44
|
-
return value == value and value not in (float("inf"), float("-inf"))
|
|
45
|
-
return False
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def project_state_row(row: Any) -> dict:
|
|
49
|
-
"""The scalar fields of one state row, capped and bounded.
|
|
50
|
-
|
|
51
|
-
Returns {} for anything that is not a dict — a row the author replaced with
|
|
52
|
-
a list or a string projects to nothing rather than raising inside the loop.
|
|
53
|
-
"""
|
|
54
|
-
if not isinstance(row, dict):
|
|
55
|
-
return {}
|
|
56
|
-
projected: dict = {}
|
|
57
|
-
for key in list(row.keys())[:MAX_STATE_KEYS]:
|
|
58
|
-
if not isinstance(key, str):
|
|
59
|
-
continue
|
|
60
|
-
value = row[key]
|
|
61
|
-
if not _is_scalar(value):
|
|
62
|
-
continue
|
|
63
|
-
projected[key] = value[:MAX_STATE_VALUE_CHARS] if isinstance(value, str) else value
|
|
64
|
-
return projected
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def count_changed(current: dict, previous: Optional[dict]) -> int:
|
|
68
|
-
"""How many projected fields moved since the previously reported row.
|
|
69
|
-
|
|
70
|
-
A first row counts every field as changed: nothing was known before it, so
|
|
71
|
-
every value is new information. A key that disappeared counts too — its
|
|
72
|
-
absence is a change the operator should see.
|
|
73
|
-
"""
|
|
74
|
-
if previous is None:
|
|
75
|
-
return len(current)
|
|
76
|
-
keys = set(current) | set(previous)
|
|
77
|
-
return sum(1 for key in keys if current.get(key) != previous.get(key))
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def build_tick_facts(
|
|
81
|
-
*,
|
|
82
|
-
tick_id: str,
|
|
83
|
-
status: str,
|
|
84
|
-
candidate_count: int,
|
|
85
|
-
duration_ms: int,
|
|
86
|
-
commit: Optional[str],
|
|
87
|
-
quiet_ticks: int,
|
|
88
|
-
lag_ms: Optional[int],
|
|
89
|
-
mcp_snapshot: Optional[dict],
|
|
90
|
-
call_snapshot: Optional[dict],
|
|
91
|
-
state_row: Any,
|
|
92
|
-
state_fields: Optional[int],
|
|
93
|
-
state_changed: Optional[int],
|
|
94
|
-
) -> dict:
|
|
95
|
-
"""Assemble one tick's facts for the wire.
|
|
96
|
-
|
|
97
|
-
`mcp_snapshot` / `call_snapshot` are the MCP boundary's own per-tick tallies,
|
|
98
|
-
or None when the tick ran without an MCP client — which is not the same as a
|
|
99
|
-
tick that made no calls, so both keys are then left off entirely.
|
|
100
|
-
"""
|
|
101
|
-
facts: dict = {
|
|
102
|
-
"tick_id": tick_id,
|
|
103
|
-
"status": status,
|
|
104
|
-
"candidate_count": candidate_count,
|
|
105
|
-
"duration_ms": duration_ms,
|
|
106
|
-
# Always known: the loop either commits, rolls back, or fails to persist.
|
|
107
|
-
**({"commit": commit} if commit else {}),
|
|
108
|
-
# Zero is a real answer here (this tick produced a signal), so it is sent.
|
|
109
|
-
"quiet_ticks": quiet_ticks,
|
|
110
|
-
}
|
|
111
|
-
# Unknown on the very first tick of a process: there is no previous tick to
|
|
112
|
-
# measure the gap against, and a 0 would claim the scanner was exactly on time.
|
|
113
|
-
if lag_ms is not None:
|
|
114
|
-
facts["lag_ms"] = lag_ms
|
|
115
|
-
if mcp_snapshot is not None:
|
|
116
|
-
# Every failure the boundary saw this tick. The overwhelming case is a failure the
|
|
117
|
-
# author's own `except` caught and turned into an empty return — the one thing that
|
|
118
|
-
# otherwise leaves no trace at all. A failure that escaped scan() is in the count too,
|
|
119
|
-
# and needs no separating out: it already failed the tick, so `status` names it.
|
|
120
|
-
facts["mcp_failures"] = int(mcp_snapshot.get("count") or 0)
|
|
121
|
-
if call_snapshot is not None:
|
|
122
|
-
facts["mcp_ms"] = call_snapshot.get("total_ms", 0)
|
|
123
|
-
facts["mcp_calls"] = call_snapshot.get("calls", [])
|
|
124
|
-
projected = project_state_row(state_row)
|
|
125
|
-
if state_fields is not None:
|
|
126
|
-
facts["state"] = projected
|
|
127
|
-
facts["state_fields"] = state_fields
|
|
128
|
-
if state_changed is not None:
|
|
129
|
-
facts["state_changed"] = state_changed
|
|
130
|
-
return facts
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
"""ULID minting: a 26-character, lexicographically sortable id — 48 bits of millisecond timestamp
|
|
2
|
-
followed by 80 bits of randomness, rendered in Crockford's base32. Sortable ids are what let two
|
|
3
|
-
ticks be ordered without carrying a second field, and 80 random bits make a collision between two
|
|
4
|
-
ticks of the same millisecond unreachable.
|
|
5
|
-
|
|
6
|
-
Mirrors src/utils/ulid.ts so a scaffold id and a runtime id are the same kind of value. The random
|
|
7
|
-
half is read out of a `uuid.uuid4()`, taking only the ten bytes that carry no version or variant
|
|
8
|
-
bits, so all 80 of them are random.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from __future__ import annotations
|
|
12
|
-
|
|
13
|
-
import math
|
|
14
|
-
import time
|
|
15
|
-
import uuid
|
|
16
|
-
|
|
17
|
-
# Crockford's base32: no I, L, O or U, so a transcribed id cannot be misread.
|
|
18
|
-
CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
|
|
19
|
-
|
|
20
|
-
TIME_CHARS = 10
|
|
21
|
-
RANDOM_CHARS = 16
|
|
22
|
-
MAX_TIME = 2 ** 48 - 1
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def _encode_time(ms) -> str:
|
|
26
|
-
"""Render `ms` as the 10-character time prefix.
|
|
27
|
-
|
|
28
|
-
Clamped, and never raised from: a clock that reads non-finite, negative, or past the 48-bit
|
|
29
|
-
ceiling must still yield a valid id rather than kill the tick that asked for one.
|
|
30
|
-
"""
|
|
31
|
-
try:
|
|
32
|
-
remaining = min(max(math.floor(ms), 0), MAX_TIME)
|
|
33
|
-
except (OverflowError, ValueError, TypeError):
|
|
34
|
-
remaining = 0
|
|
35
|
-
out = ""
|
|
36
|
-
for _ in range(TIME_CHARS):
|
|
37
|
-
out = CROCKFORD[remaining % 32] + out
|
|
38
|
-
remaining //= 32
|
|
39
|
-
return out
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def _encode_random() -> str:
|
|
43
|
-
"""Render 80 random bits as the 16-character suffix, five bits at a time."""
|
|
44
|
-
# uuid4 holds its version and variant in bytes 6 and 8; the ten bytes taken here are the
|
|
45
|
-
# fully random ones.
|
|
46
|
-
raw = uuid.uuid4().bytes
|
|
47
|
-
acc = int.from_bytes(raw[:6] + raw[9:13], "big")
|
|
48
|
-
return "".join(
|
|
49
|
-
CROCKFORD[(acc >> shift) & 31]
|
|
50
|
-
for shift in range(RANDOM_CHARS * 5 - 5, -1, -5)
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def new_ulid(now_ms: int | None = None) -> str:
|
|
55
|
-
"""Mint a ULID. `now_ms` is injectable so a caller can pin the time half in a test."""
|
|
56
|
-
if now_ms is None:
|
|
57
|
-
now_ms = int(time.time() * 1000)
|
|
58
|
-
return _encode_time(now_ms) + _encode_random()
|