@nac3/forge-cli 1.23.3 → 1.23.5
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/bin/yf.js +0 -0
- package/dist/chat/doctrine_digest.d.ts.map +1 -1
- package/dist/chat/doctrine_digest.js +4 -1
- package/dist/chat/doctrine_digest.js.map +1 -1
- package/dist/chat/server.d.ts.map +1 -1
- package/dist/chat/server.js +72 -19
- package/dist/chat/server.js.map +1 -1
- package/dist/chat/tools/evidence.d.ts +34 -2
- package/dist/chat/tools/evidence.d.ts.map +1 -1
- package/dist/chat/tools/evidence.js +90 -12
- package/dist/chat/tools/evidence.js.map +1 -1
- package/dist/commands/urazuke.d.ts.map +1 -1
- package/dist/commands/urazuke.js +27 -0
- package/dist/commands/urazuke.js.map +1 -1
- package/dist/core/error_catalog.d.ts +4 -0
- package/dist/core/error_catalog.d.ts.map +1 -1
- package/dist/core/error_catalog.js +16 -0
- package/dist/core/error_catalog.js.map +1 -1
- package/dist/core/loopback_post.d.ts +101 -0
- package/dist/core/loopback_post.d.ts.map +1 -0
- package/dist/core/loopback_post.js +156 -0
- package/dist/core/loopback_post.js.map +1 -0
- package/dist/docs/doctrine/urazuke.md +50 -38
- package/dist/mcp/forge_panel_server.d.ts +1 -26
- package/dist/mcp/forge_panel_server.d.ts.map +1 -1
- package/dist/mcp/forge_panel_server.js +5 -26
- package/dist/mcp/forge_panel_server.js.map +1 -1
- package/dist/mcp/forge_verbs_server.d.ts +1 -11
- package/dist/mcp/forge_verbs_server.d.ts.map +1 -1
- package/dist/mcp/forge_verbs_server.js +7 -23
- package/dist/mcp/forge_verbs_server.js.map +1 -1
- package/dist/mcp/panel_invoke.d.ts +51 -0
- package/dist/mcp/panel_invoke.d.ts.map +1 -0
- package/dist/mcp/panel_invoke.js +102 -0
- package/dist/mcp/panel_invoke.js.map +1 -0
- package/dist/nac3/internal_manifest.d.ts +2 -0
- package/dist/nac3/internal_manifest.d.ts.map +1 -1
- package/dist/nac3/internal_manifest.js +18 -3
- package/dist/nac3/internal_manifest.js.map +1 -1
- package/dist/nac3/verb_budget.d.ts +110 -0
- package/dist/nac3/verb_budget.d.ts.map +1 -0
- package/dist/nac3/verb_budget.js +142 -0
- package/dist/nac3/verb_budget.js.map +1 -0
- package/dist/relay/in_flight_turn.d.ts +52 -11
- package/dist/relay/in_flight_turn.d.ts.map +1 -1
- package/dist/relay/in_flight_turn.js +98 -30
- package/dist/relay/in_flight_turn.js.map +1 -1
- package/dist/relay/loopback_turn.d.ts +15 -42
- package/dist/relay/loopback_turn.d.ts.map +1 -1
- package/dist/relay/loopback_turn.js +27 -115
- package/dist/relay/loopback_turn.js.map +1 -1
- package/dist/urazuke/evidence.d.ts +22 -0
- package/dist/urazuke/evidence.d.ts.map +1 -1
- package/dist/urazuke/evidence.js +42 -3
- package/dist/urazuke/evidence.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/doctrine/urazuke.md +50 -38
- package/package.json +20 -18
- package/src/i18n/catalogs/ar.json +3 -0
- package/src/i18n/catalogs/de.json +3 -0
- package/src/i18n/catalogs/en.json +3 -0
- package/src/i18n/catalogs/es.json +3 -0
- package/src/i18n/catalogs/fr.json +3 -0
- package/src/i18n/catalogs/hi.json +3 -0
- package/src/i18n/catalogs/it.json +3 -0
- package/src/i18n/catalogs/ja.json +3 -0
- package/src/i18n/catalogs/pt.json +3 -0
- package/src/i18n/catalogs/zh.json +3 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cuanto puede durar la invocacion de un verbo, y quien lo decide.
|
|
3
|
+
*
|
|
4
|
+
* EL DEFECTO (PND-235). Los dos servers MCP reenvian cada invocacion al
|
|
5
|
+
* servidor de chat por loopback y esperan la respuesta. Con `fetch` esa espera
|
|
6
|
+
* heredaba el techo de undici -- 305.677 ms MEDIDOS en Node 22.16 -- y moria
|
|
7
|
+
* ahi. El techo no era una decision de nadie: era el default de una libreria
|
|
8
|
+
* aplicado a un canal para el que no estaba pensado. Y era un techo SECRETO:
|
|
9
|
+
* `yujin.evidence.run` declara en su schema que acepta hasta 30 minutos, el
|
|
10
|
+
* servidor los honra, y la invocacion se caia a los cinco. El verbo que
|
|
11
|
+
* acredita una bateria de siete minutos era justo el que no podia dejar
|
|
12
|
+
* recibo.
|
|
13
|
+
*
|
|
14
|
+
* LA REGLA. El presupuesto del transporte sale de lo que el VERBO declara, no
|
|
15
|
+
* de lo que la libreria trae puesto. Nadie impone por debajo un techo mas bajo
|
|
16
|
+
* que el que el verbo promete.
|
|
17
|
+
*
|
|
18
|
+
* PERO EL PRESUPUESTO NO ES INFINITO, Y EL LIMITE NO ES ARBITRARIO. En modo
|
|
19
|
+
* Plan el verbo corre adentro de un turno de `claude -p`, y ese turno tiene su
|
|
20
|
+
* propia vigilia de SILENCIO (limits.claude_cli_silence_ms, 15 min por
|
|
21
|
+
* default): mientras una tool call esta pendiente el subproceso no emite un
|
|
22
|
+
* solo evento, asi que una invocacion que bloquea mas que esa ventana no falla
|
|
23
|
+
* sola -- se lleva el TURNO ENTERO por colgado. Por eso lo que un verbo puede
|
|
24
|
+
* BLOQUEAR tiene que quedar por debajo de esa ventana, con margen.
|
|
25
|
+
*
|
|
26
|
+
* Y de ahi sale la otra mitad del arreglo: un verbo que legitimamente dura mas
|
|
27
|
+
* que la ventana de bloqueo no se recorta en silencio, se corre EN SEGUNDO
|
|
28
|
+
* PLANO y devuelve un handle (ver chat/tools/evidence.ts). El techo deja de ser
|
|
29
|
+
* secreto: o entra en la ventana, o el verbo te dice que lo lanzo aparte.
|
|
30
|
+
*
|
|
31
|
+
* ASCII puro.
|
|
32
|
+
*/
|
|
33
|
+
import { manifest } from './internal_manifest.js';
|
|
34
|
+
/**
|
|
35
|
+
* Lo maximo que una invocacion puede BLOQUEAR el turno.
|
|
36
|
+
*
|
|
37
|
+
* Diez minutos. El numero sale de la vigilia de silencio del subproceso
|
|
38
|
+
* (claude_cli_silence_ms, 15 min por default): bloquear mas que eso no da un
|
|
39
|
+
* error del verbo, mata el turno. Diez mas el margen de abajo deja cuatro
|
|
40
|
+
* minutos de aire. La simetria con ese limite esta cuidada por un test: si
|
|
41
|
+
* alguien baja la vigilia, el test lo avisa antes de que se vuelva un turno
|
|
42
|
+
* muerto en produccion.
|
|
43
|
+
*/
|
|
44
|
+
export const VERB_BLOCKING_MAX_MS = 10 * 60_000;
|
|
45
|
+
/**
|
|
46
|
+
* Margen del despachador por encima del tope del propio verbo.
|
|
47
|
+
*
|
|
48
|
+
* El verbo mide SU trabajo; el presupuesto del transporte tiene que cubrir
|
|
49
|
+
* ademas lo que pasa alrededor (resolver el schema, la cola del panel, armar y
|
|
50
|
+
* serializar la respuesta). Sin margen, el transporte se cae un instante antes
|
|
51
|
+
* de que la respuesta salga -- el peor de los dos mundos: el trabajo hecho y
|
|
52
|
+
* el resultado perdido.
|
|
53
|
+
*/
|
|
54
|
+
export const VERB_BUDGET_OVERHEAD_MS = 60_000;
|
|
55
|
+
/** Piso: ni la invocacion mas trivial se corta antes de esto. */
|
|
56
|
+
export const VERB_BUDGET_MIN_MS = 30_000;
|
|
57
|
+
/**
|
|
58
|
+
* El presupuesto de un verbo que NO declara cuanto puede durar.
|
|
59
|
+
*
|
|
60
|
+
* Cinco minutos, y si -- es casi el mismo numero que heredaba de undici. Eso
|
|
61
|
+
* es deliberado: para un verbo que no declara nada (leer un archivo, un git
|
|
62
|
+
* status, el grafo) cinco minutos nunca fue el problema. El problema era
|
|
63
|
+
* aplicarle ese mismo techo al verbo que declara TREINTA minutos y despues
|
|
64
|
+
* tratar el corte como un fracaso del trabajo.
|
|
65
|
+
*
|
|
66
|
+
* Elegirlo igual tiene una segunda virtud: el radio de este cambio queda
|
|
67
|
+
* acotado a los verbos que SI declaran un tope. Para todos los demas el
|
|
68
|
+
* comportamiento es el de antes, y un servidor colgado se reporta en cinco
|
|
69
|
+
* minutos y no en once -- que, con la vigilia de silencio en quince, es la
|
|
70
|
+
* diferencia entre un error legible y un turno muerto sin explicacion.
|
|
71
|
+
*/
|
|
72
|
+
export const VERB_BUDGET_DEFAULT_MS = 5 * 60_000;
|
|
73
|
+
/** El techo absoluto que puede salir de esta funcion. */
|
|
74
|
+
export const VERB_BUDGET_MAX_MS = VERB_BLOCKING_MAX_MS + VERB_BUDGET_OVERHEAD_MS;
|
|
75
|
+
/**
|
|
76
|
+
* El tope que el VERBO declara para si mismo, leido de su schema.
|
|
77
|
+
*
|
|
78
|
+
* `undefined` cuando el verbo no acepta timeout_ms: no es un verbo pensado
|
|
79
|
+
* para durar, y su presupuesto sale del default.
|
|
80
|
+
*/
|
|
81
|
+
export function verbTimeoutCeilingMs(verb) {
|
|
82
|
+
const props = verb?.schema?.properties;
|
|
83
|
+
const t = props?.['timeout_ms'];
|
|
84
|
+
if (!t)
|
|
85
|
+
return undefined;
|
|
86
|
+
const max = typeof t.maximum === 'number' && Number.isFinite(t.maximum) && t.maximum > 0
|
|
87
|
+
? t.maximum : undefined;
|
|
88
|
+
/* Declara timeout_ms pero sin maximo en el schema: se le cree que puede
|
|
89
|
+
* durar, y el techo lo pone la ventana de bloqueo. */
|
|
90
|
+
return max ?? VERB_BLOCKING_MAX_MS;
|
|
91
|
+
}
|
|
92
|
+
function positivo(v) {
|
|
93
|
+
const n = typeof v === 'number' ? v : typeof v === 'string' ? Number(v) : NaN;
|
|
94
|
+
return Number.isFinite(n) && n > 0 ? n : undefined;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* El presupuesto de transporte para UNA invocacion.
|
|
98
|
+
*
|
|
99
|
+
* Orden de preferencia: lo que el llamador pidio en los args, si no el tope
|
|
100
|
+
* que el verbo declara, si no el default. Siempre con el margen del
|
|
101
|
+
* despachador encima y acotado por la ventana de bloqueo.
|
|
102
|
+
*/
|
|
103
|
+
export function invokeBudgetMs(verbId, args = {}, verbs = manifest().verbs) {
|
|
104
|
+
const verb = verbs.find((v) => v.id === verbId);
|
|
105
|
+
const ceiling = verbTimeoutCeilingMs(verb);
|
|
106
|
+
/* El verbo no declara cuanto puede durar: techo plano, sin margen que
|
|
107
|
+
* cubrir, y el de siempre. */
|
|
108
|
+
if (ceiling === undefined)
|
|
109
|
+
return VERB_BUDGET_DEFAULT_MS;
|
|
110
|
+
/* El tope del verbo manda sobre lo que pida el llamador: el servidor lo va a
|
|
111
|
+
* recortar igual, asi que esperar mas seria esperar de gusto. */
|
|
112
|
+
const propio = Math.min(positivo(args['timeout_ms']) ?? ceiling, ceiling);
|
|
113
|
+
const conMargen = Math.min(propio, VERB_BLOCKING_MAX_MS) + VERB_BUDGET_OVERHEAD_MS;
|
|
114
|
+
return Math.min(Math.max(conMargen, VERB_BUDGET_MIN_MS), VERB_BUDGET_MAX_MS);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Este trabajo entra en la ventana de bloqueo, o hay que lanzarlo aparte.
|
|
118
|
+
*
|
|
119
|
+
* El llamador que SI conoce la ventana real (el servidor, que lee limits.json)
|
|
120
|
+
* puede pasarla; sin eso se usa el default, que es el caso del subproceso.
|
|
121
|
+
*/
|
|
122
|
+
export function fitsInBlockingWindow(timeoutMs, windowMs = VERB_BLOCKING_MAX_MS) {
|
|
123
|
+
return timeoutMs <= windowMs;
|
|
124
|
+
}
|
|
125
|
+
/** Margen que se le deja a la vigilia de silencio: el turno tiene que poder
|
|
126
|
+
* recibir el resultado y contarlo antes de que el vigilante lo mate. */
|
|
127
|
+
export const BLOCKING_WINDOW_MARGIN_MS = 2 * 60_000;
|
|
128
|
+
/**
|
|
129
|
+
* La ventana de bloqueo REAL, para quien puede leer la configuracion viva.
|
|
130
|
+
*
|
|
131
|
+
* El default es una cota superior pensada para la vigilia de silencio por
|
|
132
|
+
* default (15 min). Si el dueno la baja, la ventana baja con ella: si no,
|
|
133
|
+
* un verbo que "entra" por el default se llevaria el turno puesto. Y nunca
|
|
134
|
+
* baja de un minuto, porque una ventana de cero mandaria al fondo hasta la
|
|
135
|
+
* corrida mas corta.
|
|
136
|
+
*/
|
|
137
|
+
export function blockingWindowMs(silenceMs) {
|
|
138
|
+
if (!Number.isFinite(silenceMs) || silenceMs <= 0)
|
|
139
|
+
return VERB_BLOCKING_MAX_MS;
|
|
140
|
+
return Math.max(60_000, Math.min(VERB_BLOCKING_MAX_MS, silenceMs - BLOCKING_WINDOW_MARGIN_MS));
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=verb_budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verb_budget.js","sourceRoot":"","sources":["../../src/nac3/verb_budget.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,32 @@
|
|
|
24
24
|
* refresco a mano -- cae sobre un latido reciente y reconstruye que esta
|
|
25
25
|
* corriendo, incluso si el telefono no estaba conectado cuando arranco.
|
|
26
26
|
*
|
|
27
|
+
* POR QUE ES UN REGISTRO Y NO UNA VARIABLE (PND-237, 30-oct-2026).
|
|
28
|
+
*
|
|
29
|
+
* Esto era UN solo slot (`let current`), y un panel corre turnos SOLAPADOS: el
|
|
30
|
+
* dueno manda un pedido mientras el anterior sigue, o entra uno por el puente.
|
|
31
|
+
* Con un solo slot el segundo pisaba al primero, y `clearInFlightTurn(id)` --
|
|
32
|
+
* que NO limpia si el id no coincide, y eso esta bien, porque un cierre tardio
|
|
33
|
+
* no tiene que borrar el anuncio del que recien arranco -- dejaba al pisado
|
|
34
|
+
* SIN NINGUN camino de salida. Peor: `touchInFlightTurn()` refrescaba lo que
|
|
35
|
+
* hubiera en el slot sin mirar el id, asi que el latido de cualquier turno
|
|
36
|
+
* POSTERIOR mantenia vivo al huerfano y el tope de silencio no vencia nunca.
|
|
37
|
+
*
|
|
38
|
+
* Medido en produccion (D1, 30-oct-2026 13:25 UTC): el panel de adip-kikan
|
|
39
|
+
* venia anunciando `dt-mvuyvonj` -- arrancado 12:47:13 -- durante 152 latidos
|
|
40
|
+
* y 38 minutos, mientras el MISMO panel ya habia publicado los remote_turn
|
|
41
|
+
* completos de dos turnos que arrancaron a su lado (12:46:39 y 12:47:40: los
|
|
42
|
+
* tres se solapan en 61 segundos). El telefono mostraba la burbuja "trabajando"
|
|
43
|
+
* con el texto viejo, y como su guarda es por id, el turno REAL no recibia
|
|
44
|
+
* burbuja: el dueno veia una sesion trabajando sin su pedido a la vista.
|
|
45
|
+
*
|
|
46
|
+
* Las dos reglas que lo cierran, y que son el contrato de este modulo:
|
|
47
|
+
* - un turno es una ENTRADA propia, identificada por su id. Nadie pisa a
|
|
48
|
+
* nadie, y cada uno sale por su propio cierre o por su propio silencio.
|
|
49
|
+
* - la SENAL DE VIDA esta ligada al id que la produce (touchInFlightTurn(id)).
|
|
50
|
+
* Un latido solo puede hablar por SU turno. Eso es lo que le devuelve el
|
|
51
|
+
* poder al tope de silencio: un huerfano deja de ser tocado y vence.
|
|
52
|
+
*
|
|
27
53
|
* ASCII puro.
|
|
28
54
|
*/
|
|
29
55
|
export interface InFlightTurn {
|
|
@@ -60,30 +86,45 @@ export declare const PULSO_DE_PROGRESO_MS: number;
|
|
|
60
86
|
*
|
|
61
87
|
* Diez pulsos de margen: tolera que se pierdan nueve latidos seguidos antes de
|
|
62
88
|
* dar por muerto un turno que esta vivo.
|
|
89
|
+
*
|
|
90
|
+
* PND-237: esta garantia solo existe de verdad desde que la senal de vida va
|
|
91
|
+
* por id. Mientras `touch()` refrescaba el slot entero, el latido de un turno
|
|
92
|
+
* nuevo reseteaba el reloj del huerfano y este tope era letra muerta.
|
|
63
93
|
*/
|
|
64
94
|
export declare const SILENCIO_MAX_MS: number;
|
|
65
95
|
export declare function setInFlightTurn(t: InFlightTurn, now?: number): void;
|
|
66
96
|
/**
|
|
67
|
-
* Senal de vida
|
|
68
|
-
*
|
|
97
|
+
* Senal de vida de UN turno. La llama el latido de actividad de ese turno,
|
|
98
|
+
* que corre solo mientras el turno vive.
|
|
69
99
|
*
|
|
70
|
-
* No crea nada: si no
|
|
71
|
-
* rezagado no puede resucitar un turno ya cerrado
|
|
100
|
+
* No crea nada: si ese id no esta registrado, no hace nada. Asi un latido
|
|
101
|
+
* rezagado no puede resucitar un turno ya cerrado -- y, desde PND-237, no
|
|
102
|
+
* puede tampoco mantener vivo el anuncio de OTRO turno, que era el agujero
|
|
103
|
+
* por el que un huerfano se anunciaba para siempre.
|
|
72
104
|
*/
|
|
73
|
-
export declare function touchInFlightTurn(now?: number): void;
|
|
105
|
+
export declare function touchInFlightTurn(id: string, now?: number): void;
|
|
74
106
|
/**
|
|
75
|
-
* Limpia el turno en vuelo. Con `id`, SOLO
|
|
76
|
-
*
|
|
77
|
-
*
|
|
107
|
+
* Limpia el turno en vuelo. Con `id`, SOLO ese: dos turnos encadenados pueden
|
|
108
|
+
* cerrar fuera de orden, y un cierre tardio del viejo no tiene que borrar el
|
|
109
|
+
* anuncio del que recien arranco. Sin `id`, TODOS (apagado del servidor).
|
|
78
110
|
*/
|
|
79
111
|
export declare function clearInFlightTurn(id?: string): void;
|
|
80
112
|
/**
|
|
81
|
-
* El turno
|
|
113
|
+
* El turno que se ANUNCIA, o null si no hay ninguno vivo.
|
|
114
|
+
*
|
|
115
|
+
* El latido de presencia lleva UN turno (contrato del relay), asi que entre
|
|
116
|
+
* varios solapados hay que elegir, y se elige el que arranco ULTIMO: es el
|
|
117
|
+
* pedido que el dueno acaba de hacer y que esta esperando ver. Era justo el
|
|
118
|
+
* que se perdia -- con el slot unico, el que quedaba anunciado podia ser
|
|
119
|
+
* cualquiera, y si era un huerfano la guarda por id del telefono dejaba al
|
|
120
|
+
* pedido nuevo sin burbuja (PND-237, sintoma 6).
|
|
82
121
|
*
|
|
83
|
-
* La edad del turno no entra en la decision: un turno de tres horas
|
|
84
|
-
* latiendo es un turno vivo
|
|
122
|
+
* La edad del turno no entra en la decision de VIDA: un turno de tres horas
|
|
123
|
+
* que sigue latiendo es un turno vivo. Lo que lo saca es el silencio.
|
|
85
124
|
*/
|
|
86
125
|
export declare function inFlightTurn(now?: number): InFlightTurn | null;
|
|
126
|
+
/** Cuantos turnos vivos declara este panel (diagnostico / tests). */
|
|
127
|
+
export declare function inFlightCount(now?: number): number;
|
|
87
128
|
/** Solo para tests. */
|
|
88
129
|
export declare function _resetInFlightTurn(): void;
|
|
89
130
|
//# sourceMappingURL=in_flight_turn.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"in_flight_turn.d.ts","sourceRoot":"","sources":["../../src/relay/in_flight_turn.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"in_flight_turn.d.ts","sourceRoot":"","sources":["../../src/relay/in_flight_turn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,QAAY,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,eAAe,QAA4B,CAAC;AAUzD,wBAAgB,eAAe,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,GAAE,MAAmB,GAAG,IAAI,CAS/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,IAAI,CAK5E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGnD;AAWD;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAmB,GAAG,YAAY,GAAG,IAAI,CAiB1E;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAmB,GAAG,MAAM,CAG9D;AAED,uBAAuB;AACvB,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
|
@@ -24,6 +24,32 @@
|
|
|
24
24
|
* refresco a mano -- cae sobre un latido reciente y reconstruye que esta
|
|
25
25
|
* corriendo, incluso si el telefono no estaba conectado cuando arranco.
|
|
26
26
|
*
|
|
27
|
+
* POR QUE ES UN REGISTRO Y NO UNA VARIABLE (PND-237, 30-oct-2026).
|
|
28
|
+
*
|
|
29
|
+
* Esto era UN solo slot (`let current`), y un panel corre turnos SOLAPADOS: el
|
|
30
|
+
* dueno manda un pedido mientras el anterior sigue, o entra uno por el puente.
|
|
31
|
+
* Con un solo slot el segundo pisaba al primero, y `clearInFlightTurn(id)` --
|
|
32
|
+
* que NO limpia si el id no coincide, y eso esta bien, porque un cierre tardio
|
|
33
|
+
* no tiene que borrar el anuncio del que recien arranco -- dejaba al pisado
|
|
34
|
+
* SIN NINGUN camino de salida. Peor: `touchInFlightTurn()` refrescaba lo que
|
|
35
|
+
* hubiera en el slot sin mirar el id, asi que el latido de cualquier turno
|
|
36
|
+
* POSTERIOR mantenia vivo al huerfano y el tope de silencio no vencia nunca.
|
|
37
|
+
*
|
|
38
|
+
* Medido en produccion (D1, 30-oct-2026 13:25 UTC): el panel de adip-kikan
|
|
39
|
+
* venia anunciando `dt-mvuyvonj` -- arrancado 12:47:13 -- durante 152 latidos
|
|
40
|
+
* y 38 minutos, mientras el MISMO panel ya habia publicado los remote_turn
|
|
41
|
+
* completos de dos turnos que arrancaron a su lado (12:46:39 y 12:47:40: los
|
|
42
|
+
* tres se solapan en 61 segundos). El telefono mostraba la burbuja "trabajando"
|
|
43
|
+
* con el texto viejo, y como su guarda es por id, el turno REAL no recibia
|
|
44
|
+
* burbuja: el dueno veia una sesion trabajando sin su pedido a la vista.
|
|
45
|
+
*
|
|
46
|
+
* Las dos reglas que lo cierran, y que son el contrato de este modulo:
|
|
47
|
+
* - un turno es una ENTRADA propia, identificada por su id. Nadie pisa a
|
|
48
|
+
* nadie, y cada uno sale por su propio cierre o por su propio silencio.
|
|
49
|
+
* - la SENAL DE VIDA esta ligada al id que la produce (touchInFlightTurn(id)).
|
|
50
|
+
* Un latido solo puede hablar por SU turno. Eso es lo que le devuelve el
|
|
51
|
+
* poder al tope de silencio: un huerfano deja de ser tocado y vence.
|
|
52
|
+
*
|
|
27
53
|
* ASCII puro.
|
|
28
54
|
*/
|
|
29
55
|
/**
|
|
@@ -54,63 +80,105 @@ export const PULSO_DE_PROGRESO_MS = 60 * 1000;
|
|
|
54
80
|
*
|
|
55
81
|
* Diez pulsos de margen: tolera que se pierdan nueve latidos seguidos antes de
|
|
56
82
|
* dar por muerto un turno que esta vivo.
|
|
83
|
+
*
|
|
84
|
+
* PND-237: esta garantia solo existe de verdad desde que la senal de vida va
|
|
85
|
+
* por id. Mientras `touch()` refrescaba el slot entero, el latido de un turno
|
|
86
|
+
* nuevo reseteaba el reloj del huerfano y este tope era letra muerta.
|
|
57
87
|
*/
|
|
58
88
|
export const SILENCIO_MAX_MS = PULSO_DE_PROGRESO_MS * 10;
|
|
59
|
-
|
|
89
|
+
/** Los turnos vivos de ESTE panel, por id. Varios a la vez es lo normal. */
|
|
90
|
+
const vivos = new Map();
|
|
60
91
|
export function setInFlightTurn(t, now = Date.now()) {
|
|
61
92
|
if (!t || !t.id)
|
|
62
93
|
return;
|
|
63
|
-
|
|
64
|
-
|
|
94
|
+
const id = String(t.id);
|
|
95
|
+
vivos.set(id, {
|
|
96
|
+
id,
|
|
65
97
|
user: String(t.user || ''),
|
|
66
98
|
started_at: String(t.started_at || new Date(now).toISOString()),
|
|
67
99
|
visto: now,
|
|
68
|
-
};
|
|
100
|
+
});
|
|
69
101
|
}
|
|
70
102
|
/**
|
|
71
|
-
* Senal de vida
|
|
72
|
-
*
|
|
103
|
+
* Senal de vida de UN turno. La llama el latido de actividad de ese turno,
|
|
104
|
+
* que corre solo mientras el turno vive.
|
|
73
105
|
*
|
|
74
|
-
* No crea nada: si no
|
|
75
|
-
* rezagado no puede resucitar un turno ya cerrado
|
|
106
|
+
* No crea nada: si ese id no esta registrado, no hace nada. Asi un latido
|
|
107
|
+
* rezagado no puede resucitar un turno ya cerrado -- y, desde PND-237, no
|
|
108
|
+
* puede tampoco mantener vivo el anuncio de OTRO turno, que era el agujero
|
|
109
|
+
* por el que un huerfano se anunciaba para siempre.
|
|
76
110
|
*/
|
|
77
|
-
export function touchInFlightTurn(now = Date.now()) {
|
|
78
|
-
if (!
|
|
111
|
+
export function touchInFlightTurn(id, now = Date.now()) {
|
|
112
|
+
if (!id)
|
|
113
|
+
return;
|
|
114
|
+
const r = vivos.get(String(id));
|
|
115
|
+
if (!r)
|
|
79
116
|
return;
|
|
80
|
-
|
|
117
|
+
r.visto = now;
|
|
81
118
|
}
|
|
82
119
|
/**
|
|
83
|
-
* Limpia el turno en vuelo. Con `id`, SOLO
|
|
84
|
-
*
|
|
85
|
-
*
|
|
120
|
+
* Limpia el turno en vuelo. Con `id`, SOLO ese: dos turnos encadenados pueden
|
|
121
|
+
* cerrar fuera de orden, y un cierre tardio del viejo no tiene que borrar el
|
|
122
|
+
* anuncio del que recien arranco. Sin `id`, TODOS (apagado del servidor).
|
|
86
123
|
*/
|
|
87
124
|
export function clearInFlightTurn(id) {
|
|
88
|
-
if (!
|
|
125
|
+
if (!id) {
|
|
126
|
+
vivos.clear();
|
|
89
127
|
return;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
128
|
+
}
|
|
129
|
+
vivos.delete(String(id));
|
|
130
|
+
}
|
|
131
|
+
/** Poda las entradas que se quedaron CALLADAS. */
|
|
132
|
+
function podar(now) {
|
|
133
|
+
for (const [id, r] of vivos) {
|
|
134
|
+
/* Un reloj que salta hacia atras da silencio negativo: no vence. Preferible
|
|
135
|
+
* anunciar un turno de mas que descartar uno vivo por un salto de NTP. */
|
|
136
|
+
if (now - r.visto > SILENCIO_MAX_MS)
|
|
137
|
+
vivos.delete(id);
|
|
138
|
+
}
|
|
93
139
|
}
|
|
94
140
|
/**
|
|
95
|
-
* El turno
|
|
141
|
+
* El turno que se ANUNCIA, o null si no hay ninguno vivo.
|
|
96
142
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
143
|
+
* El latido de presencia lleva UN turno (contrato del relay), asi que entre
|
|
144
|
+
* varios solapados hay que elegir, y se elige el que arranco ULTIMO: es el
|
|
145
|
+
* pedido que el dueno acaba de hacer y que esta esperando ver. Era justo el
|
|
146
|
+
* que se perdia -- con el slot unico, el que quedaba anunciado podia ser
|
|
147
|
+
* cualquiera, y si era un huerfano la guarda por id del telefono dejaba al
|
|
148
|
+
* pedido nuevo sin burbuja (PND-237, sintoma 6).
|
|
149
|
+
*
|
|
150
|
+
* La edad del turno no entra en la decision de VIDA: un turno de tres horas
|
|
151
|
+
* que sigue latiendo es un turno vivo. Lo que lo saca es el silencio.
|
|
99
152
|
*/
|
|
100
153
|
export function inFlightTurn(now = Date.now()) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
154
|
+
podar(now);
|
|
155
|
+
let elegido = null;
|
|
156
|
+
let mejor = -Infinity;
|
|
157
|
+
for (const r of vivos.values()) {
|
|
158
|
+
/* Un started_at ilegible NO puede ganar la eleccion. Date.parse devuelve
|
|
159
|
+
* NaN y toda comparacion con NaN es false, asi que comparando en crudo el
|
|
160
|
+
* primero de la iteracion se quedaba con el anuncio para siempre -- el
|
|
161
|
+
* mismo sintoma que estamos arreglando, por otra puerta. Vale -Infinity:
|
|
162
|
+
* se anuncia solo si es el unico que hay. */
|
|
163
|
+
const t = Date.parse(r.started_at);
|
|
164
|
+
const orden = Number.isFinite(t) ? t : -Infinity;
|
|
165
|
+
if (!elegido || orden > mejor) {
|
|
166
|
+
elegido = r;
|
|
167
|
+
mejor = orden;
|
|
168
|
+
}
|
|
108
169
|
}
|
|
109
|
-
|
|
170
|
+
if (!elegido)
|
|
171
|
+
return null;
|
|
172
|
+
const { id, user, started_at } = elegido;
|
|
110
173
|
return { id, user, started_at };
|
|
111
174
|
}
|
|
175
|
+
/** Cuantos turnos vivos declara este panel (diagnostico / tests). */
|
|
176
|
+
export function inFlightCount(now = Date.now()) {
|
|
177
|
+
podar(now);
|
|
178
|
+
return vivos.size;
|
|
179
|
+
}
|
|
112
180
|
/** Solo para tests. */
|
|
113
181
|
export function _resetInFlightTurn() {
|
|
114
|
-
|
|
182
|
+
vivos.clear();
|
|
115
183
|
}
|
|
116
184
|
//# sourceMappingURL=in_flight_turn.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"in_flight_turn.js","sourceRoot":"","sources":["../../src/relay/in_flight_turn.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"in_flight_turn.js","sourceRoot":"","sources":["../../src/relay/in_flight_turn.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,47 +9,21 @@
|
|
|
9
9
|
* sin una segunda implementacion que se desincronice.
|
|
10
10
|
*
|
|
11
11
|
* EL DEFECTO QUE ESTE MODULO CIERRA (PND-234. Pablo, 29-oct-2026, desde el
|
|
12
|
-
* telefono: "No pude completar tu pedido: fetch failed").
|
|
12
|
+
* telefono: "No pude completar tu pedido: fetch failed"). La respuesta de
|
|
13
|
+
* /api/chat es un JSON que recien se arma cuando el turno entero termino, asi
|
|
14
|
+
* que con `fetch` el POST moria a los cinco minutos y el usuario recibia un
|
|
15
|
+
* fracaso por un trabajo que el escritorio estaba terminando bien.
|
|
13
16
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* habia recibido "fetch failed" y el usuario quedaba creyendo que no se hizo
|
|
20
|
-
* nada.
|
|
21
|
-
*
|
|
22
|
-
* El limite esta MEDIDO, no estimado: contra un servidor que acepta la
|
|
23
|
-
* conexion y nunca responde, el fetch global de Node 22.16 murio a los
|
|
24
|
-
* 305.677 ms con name=TypeError, message="fetch failed" y
|
|
25
|
-
* cause.code=UND_ERR_HEADERS_TIMEOUT. El turno del reporte habia durado 22
|
|
26
|
-
* minutos (turn_routing.jsonl 13:36:33Z; los archivos que escribio tienen
|
|
27
|
-
* mtime hasta 10:58 local). O sea: cinco minutos de techo para turnos que
|
|
28
|
-
* duran veinte. El defecto es determinista y crece con la utilidad del
|
|
29
|
-
* pedido -- cuanto mas trabajo pide el usuario desde el telefono, mas seguro
|
|
30
|
-
* es que no vea el resultado.
|
|
31
|
-
*
|
|
32
|
-
* POR QUE node:http Y NO fetch. Es la unica forma de mandar los tiempos sin
|
|
33
|
-
* depender de undici: Node lo trae adentro pero no lo expone como paquete, y
|
|
34
|
-
* construir un Agent con otro headersTimeout exigiria declarar una
|
|
35
|
-
* dependencia nueva para algo que el stdlib ya hace. La conexion es loopback
|
|
36
|
-
* y en claro, asi que no se pierde nada por bajar de capa.
|
|
37
|
-
*
|
|
38
|
-
* EL PRESUPUESTO NO DESAPARECE, cambia de escala. Sin ningun limite, un
|
|
39
|
-
* servidor de chat colgado dejaria al consumidor esperando para siempre -- y
|
|
40
|
-
* como atiende un pedido a la vez, ningun pedido POSTERIOR del telefono se
|
|
41
|
-
* correria nunca. Lo que no se usa es `req.setTimeout`, que mide INACTIVIDAD
|
|
42
|
-
* del socket: un turno que piensa diez minutos no manda un byte, y ese
|
|
43
|
-
* temporizador lo mataria sin motivo, que es la forma exacta del bug que esto
|
|
44
|
-
* cierra. Lo que se mide es el tiempo TOTAL, con un techo mas alto que
|
|
45
|
-
* cualquier turno legitimo.
|
|
46
|
-
*
|
|
47
|
-
* Y al vencerse, el usuario recibe algo accionable y VERDADERO: que el
|
|
48
|
-
* escritorio puede seguir trabajando y donde ver el resultado. El mensaje
|
|
49
|
-
* anterior ("no pude completar tu pedido") era falso en el caso mas comun.
|
|
17
|
+
* EL TRANSPORTE YA NO VIVE ACA (PND-235). El mismo techo aparecio identico en
|
|
18
|
+
* el canal de los verbos MCP, asi que el POST con presupuesto se mudo a
|
|
19
|
+
* core/loopback_post.ts y lo comparten los dos caminos. Lo que queda aca es lo
|
|
20
|
+
* que SI es del telefono: el techo de una hora y como se le cuenta el corte al
|
|
21
|
+
* usuario. El detalle de por que node:http y no fetch esta en ese modulo.
|
|
50
22
|
*
|
|
51
23
|
* ASCII puro.
|
|
52
24
|
*/
|
|
25
|
+
import { type LoopbackResponse } from '../core/loopback_post.js';
|
|
26
|
+
export type { LoopbackResponse };
|
|
53
27
|
/**
|
|
54
28
|
* Techo de tiempo total para un turno pedido desde el telefono.
|
|
55
29
|
*
|
|
@@ -63,15 +37,14 @@
|
|
|
63
37
|
export declare const MOBILE_TURN_BUDGET_MS: number;
|
|
64
38
|
/** El techo efectivo, con el override de operacion. */
|
|
65
39
|
export declare function mobileTurnBudgetMs(env?: NodeJS.ProcessEnv): number;
|
|
66
|
-
export interface LoopbackResponse {
|
|
67
|
-
status: number;
|
|
68
|
-
body: string;
|
|
69
|
-
}
|
|
70
40
|
/**
|
|
71
41
|
* POST al /api/chat local, esperando lo que tarde el turno.
|
|
72
42
|
*
|
|
73
43
|
* Devuelve el status y el cuerpo crudo; parsear es del llamador, que es el
|
|
74
|
-
* que conoce la forma de la respuesta.
|
|
44
|
+
* que conoce la forma de la respuesta. Al cortarse, el usuario recibe algo
|
|
45
|
+
* accionable y VERDADERO: que el escritorio puede seguir trabajando y donde
|
|
46
|
+
* ver el resultado. El mensaje anterior ("no pude completar tu pedido") era
|
|
47
|
+
* falso en el caso mas comun.
|
|
75
48
|
*/
|
|
76
49
|
export declare function postChatTurn(args: {
|
|
77
50
|
port: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loopback_turn.d.ts","sourceRoot":"","sources":["../../src/relay/loopback_turn.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"loopback_turn.d.ts","sourceRoot":"","sources":["../../src/relay/loopback_turn.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,OAAO,EAAiC,KAAK,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEhG,YAAY,EAAE,gBAAgB,EAAE,CAAC;AAEjC;;;;;;;;;GASG;AACH,eAAO,MAAM,qBAAqB,QAAc,CAAC;AAEjD,uDAAuD;AACvD,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAU/E;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwB5B"}
|