Skip to content

feat: vigia de vencimientos, que mira todos los expedientes de una pasada - #38

Open
leocagli wants to merge 1 commit into
mainfrom
feat/vigia-vencimientos
Open

leocagli wants to merge 1 commit into
mainfrom
feat/vigia-vencimientos

Conversation

@leocagli

Copy link
Copy Markdown
Collaborator

Las skills que hay trabajan un caso. Esta mira todos a la vez, porque el plazo
que se pierde en una Defensoria casi nunca es el que estabas mirando.

El modo de falla que persigue

No es el plazo que computaste y se te paso: ese lo tenes en la cabeza. Es la
fila que quedo asi:

| contestar demanda | habiles judiciales |  |  | 🔲 a computar |

Alguien abrio el caso, cargo el acto, y no volvio. Con tres expedientes se nota.
Con veinte no se nota nunca, y desde afuera se ve identico a un caso al dia:
una tabla prolija, sin fechas rojas, porque no hay fechas.

Por eso el reporte separa tres cosas y no las mezcla:

  • vence pronto: tiene fecha y esta cerca. Lo que ya sabes.
  • sin computar: no tiene fecha porque nadie la calculo. Lo que no sabes que
    no sabes.
  • bloqueado: no se puede calcular porque a la FICHA le falta la jurisdiccion
    o el fuero. Parece un problema de formulario y es un plazo escondido.

El script no computa ningun plazo, a proposito

componentes/vigia/escanear.mjs lee fechas ya escritas y cuenta dias corridos
hasta ellas para ordenar la urgencia. Nada mas.

Restar dias habiles sin saber la jurisdiccion, la feria y las acordadas del
tribunal seria adivinar justo lo que la regla de la casa prohibe adivinar. El
computo sigue siendo de argentina-plazos, que pregunta lo que le falte.

Esa division tambien es lo que hace util el reporte: el escaner puede decir con
certeza "esta fila no tiene fecha" sin arriesgar una fecha equivocada, y una
fecha equivocada que figura como cerrada es peor que ninguna, porque deja de
aparecer en el reporte siguiente.

Detalles que salieron de leer la plantilla

Una ficha con los parentesis de ayuda sin completar cuenta como incompleta:

- **Jurisdiccion:** (CABA-Nacional / Jujuy / Salta)

Eso no es una jurisdiccion declarada, es la plantilla intacta, y tratarlo como
dato habilitaria un computo sobre un fuero inventado. Hay un test para eso.

La fila de ejemplo de la plantilla, entre guiones bajos, se ignora. Si no, todo
caso recien abierto apareceria con un plazo pendiente que no existe y el
reporte se volveria ruido a la semana.

Verificacion

node test/vigia-test.mjs        12 ok, 0 mal

Los expedientes de prueba se arman en /tmp y se borran. Nunca se escribe nada
dentro de casos/, ni siquiera inventado: la regla de la casa es que ahi no entra
nada que se parezca a un caso.

Se agrego el workflow que los corre. A diferencia de los smoke de SAIJ, estos no
tocan ninguna API, asi que no hay motivo para que sean tolerantes a fallos.


Qué se ve al correrlo

  4 expedientes revisados el 2026-08-29

  ── Vencen dentro de 15 días ──
  ⛔ VENCIDO hace 3d   0004-… · interponer recurso
  🔴 fatal  en 6d      0001-… · expresar agravios

  ── Sin computar ──
  (una fila sin vencimiento no es un plazo holgado: es un plazo que nadie miró)
  🔲 0002-… · contestar demanda · hábiles judiciales

  ── No se pueden computar: falta jurisdicción o fuero en la FICHA ──
  ⚠️  0003-… · falta jurisdicción y fuero

Devuelve exit 1 cuando hay algo que atender y 0 cuando está limpio, así se puede
encadenar. Con --json sale estructurado.

Lo que deliberadamente no hace

No manda avisos. Reporta cuando la corrés. Un sistema que avisa solo hace
falta, pero necesita dónde correr programado; es el paso siguiente, no este.

No abre el expediente electrónico. Si el juzgado notificó algo que nadie
cargó en casos/, el vigía no lo sabe. Sincronizar con el sistema del Poder
Judicial es otro trabajo, y bastante más grande.

No decide qué es urgente. Ordena por fecha y respeta el 🔴 que puso el
defensor. Entre dos plazos del mismo día decide una persona.

…sada

Las skills que hay trabajan un caso. Esta mira todos a la vez, porque el plazo
que se pierde en una Defensoria casi nunca es el que estabas mirando.

## El modo de falla que persigue

No es el plazo que computaste y se te paso: ese lo tenes en la cabeza. Es la
fila que quedo asi:

    | contestar demanda | habiles judiciales |  |  | 🔲 a computar |

Alguien abrio el caso, cargo el acto, y no volvio. Con tres expedientes se nota.
Con veinte no se nota nunca, y desde afuera se ve identico a un caso al dia:
una tabla prolija, sin fechas rojas, porque no hay fechas.

Por eso el reporte separa tres cosas y no las mezcla:

  - vence pronto: tiene fecha y esta cerca. Lo que ya sabes.
  - sin computar: no tiene fecha porque nadie la calculo. Lo que no sabes que
    no sabes.
  - bloqueado: no se puede calcular porque a la FICHA le falta la jurisdiccion
    o el fuero. Parece un problema de formulario y es un plazo escondido.

## El script no computa ningun plazo, a proposito

`componentes/vigia/escanear.mjs` lee fechas ya escritas y cuenta dias corridos
hasta ellas para ordenar la urgencia. Nada mas.

Restar dias habiles sin saber la jurisdiccion, la feria y las acordadas del
tribunal seria adivinar justo lo que la regla de la casa prohibe adivinar. El
computo sigue siendo de `argentina-plazos`, que pregunta lo que le falte.

Esa division tambien es lo que hace util el reporte: el escaner puede decir con
certeza "esta fila no tiene fecha" sin arriesgar una fecha equivocada, y una
fecha equivocada que figura como cerrada es peor que ninguna, porque deja de
aparecer en el reporte siguiente.

## Detalles que salieron de leer la plantilla

Una ficha con los parentesis de ayuda sin completar cuenta como incompleta:

    - **Jurisdiccion:** (CABA-Nacional / Jujuy / Salta)

Eso no es una jurisdiccion declarada, es la plantilla intacta, y tratarlo como
dato habilitaria un computo sobre un fuero inventado. Hay un test para eso.

La fila de ejemplo de la plantilla, entre guiones bajos, se ignora. Si no, todo
caso recien abierto apareceria con un plazo pendiente que no existe y el
reporte se volveria ruido a la semana.

## Verificacion

    node test/vigia-test.mjs        12 ok, 0 mal

Los expedientes de prueba se arman en /tmp y se borran. Nunca se escribe nada
dentro de casos/, ni siquiera inventado: la regla de la casa es que ahi no entra
nada que se parezca a un caso.

Se agrego el workflow que los corre. A diferencia de los smoke de SAIJ, estos no
tocan ninguna API, asi que no hay motivo para que sean tolerantes a fallos.
Comment on lines +214 to +221
if (proximos.some((p) => p.dias < 0) || sinComputar.length || bloqueados.length) {
process.exitCode = 1;
}
}

const resultado = await escanear();
if (JSON_OUT) console.log(JSON.stringify(resultado, null, 2));
else informar(resultado);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: --json mode never sets a non-zero exit code

In JSON mode the entry point does if (JSON_OUT) console.log(...); else informar(resultado);, so informar() — the only place that sets process.exitCode = 1 — is never called. The scanner therefore always exits 0 with --json, contradicting the documented behavior ("Devuelve exit 1 cuando hay algo que atender... así se puede encadenar. Con --json sale estructurado"). Any CI/pipeline that chains on the JSON output's exit status will treat every run as clean. Compute the exit code from the result regardless of output format (e.g. factor the proximos/sinComputar/bloqueados check into a helper called in both branches).

Set the exit code from the result in both output modes.:

function estadoSalida({ casos, error }) {
  if (error) return 2;
  const hayVencido = casos.some((c) => c.plazos.some((p) => p.dias !== null && p.dias < 0));
  const haySinComputar = casos.some((c) => c.plazos.some((p) => p.sinComputar));
  const hayBloqueado = casos.some((c) => !c.puedeComputarse);
  return hayVencido || haySinComputar || hayBloqueado ? 1 : 0;
}

const resultado = await escanear();
if (JSON_OUT) console.log(JSON.stringify(resultado, null, 2));
else informar(resultado);
process.exitCode = estadoSalida(resultado);
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +214 to +216
if (proximos.some((p) => p.dias < 0) || sinComputar.length || bloqueados.length) {
process.exitCode = 1;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: Imminent (non-overdue) deadlines don't trigger exit 1

The exit-code condition is proximos.some((p) => p.dias < 0) || sinComputar.length || bloqueados.length. A workspace whose only issue is a deadline that is close but not yet past (e.g. a 🔴 fatal en 3d, exactly the case shown in the PR's example output) yields exit 0 — reported as "limpio". This defeats the stated purpose ("exit 1 cuando hay algo que atender") for the most time-sensitive scenario and would let a chained check pass while a fatal deadline looms. Treat any entry in proximos as attention-worthy.

Any deadline within the window, not only overdue ones, marks the run as needing attention.:

if (proximos.length || sinComputar.length || bloqueados.length) {
  process.exitCode = 1;
}
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

@gitar-bot

gitar-bot Bot commented Aug 29, 2026

Copy link
Copy Markdown
CI failed: Smoke test workflow failed because the project is missing a dependencies lock file required by the setup-node caching configuration.

Overview

1 log analyzed from the smoke-test job revealed a configuration failure due to a missing lock file required for npm caching.

Failures

Missing Dependencies Lock File (confidence: high)

  • Type: configuration
  • Affected jobs: 99019822110
  • Related to change: yes
  • Root cause: The actions/setup-node action failed when trying to use npm cache because no dependencies lock file (package-lock.json, npm-shrinkwrap.json, or yarn.lock) was found in the repository root directory.
  • Suggested fix: Generate and commit a package-lock.json file by running 'npm install' locally, or remove the 'cache: npm' parameter from the actions/setup-node step in the workflow file if caching is not needed.

Summary

  • Change-related failures: 1 configuration failure due to a missing dependencies lock file.
  • Infrastructure/flaky failures: None
  • Recommended action: Add a package-lock.json file or update the workflow configuration to disable npm caching.
Code Review ⚠️ Changes requested 0 resolved / 3 findings

Expands the scanner to watch all expedientes at once, surfacing deadlines that slip through individual-case tracking. Three critical issues block merge: --json mode never exits with code 1 regardless of findings, so pipeline chaining on exit status treats every run as clean; imminent (non-overdue) deadlines don't trigger exit 1, letting a 🔴 fatal en 3d pass as "limpio"; and UTC-based date calculations shift day counts for evening runs in Argentina, causing off-by-one urgency reports. Fix the exit-code logic to treat any entry in proximos as attention-worthy, apply it in both output branches, and anchor 'today' to local calendar date.

⚠️ Bug: --json mode never sets a non-zero exit code

📄 componentes/vigia/escanear.mjs:214-221

In JSON mode the entry point does if (JSON_OUT) console.log(...); else informar(resultado);, so informar() — the only place that sets process.exitCode = 1 — is never called. The scanner therefore always exits 0 with --json, contradicting the documented behavior ("Devuelve exit 1 cuando hay algo que atender... así se puede encadenar. Con --json sale estructurado"). Any CI/pipeline that chains on the JSON output's exit status will treat every run as clean. Compute the exit code from the result regardless of output format (e.g. factor the proximos/sinComputar/bloqueados check into a helper called in both branches).

Set the exit code from the result in both output modes.
function estadoSalida({ casos, error }) {
  if (error) return 2;
  const hayVencido = casos.some((c) => c.plazos.some((p) => p.dias !== null && p.dias < 0));
  const haySinComputar = casos.some((c) => c.plazos.some((p) => p.sinComputar));
  const hayBloqueado = casos.some((c) => !c.puedeComputarse);
  return hayVencido || haySinComputar || hayBloqueado ? 1 : 0;
}

const resultado = await escanear();
if (JSON_OUT) console.log(JSON.stringify(resultado, null, 2));
else informar(resultado);
process.exitCode = estadoSalida(resultado);
⚠️ Bug: Imminent (non-overdue) deadlines don't trigger exit 1

📄 componentes/vigia/escanear.mjs:214-216

The exit-code condition is proximos.some((p) => p.dias < 0) || sinComputar.length || bloqueados.length. A workspace whose only issue is a deadline that is close but not yet past (e.g. a 🔴 fatal en 3d, exactly the case shown in the PR's example output) yields exit 0 — reported as "limpio". This defeats the stated purpose ("exit 1 cuando hay algo que atender") for the most time-sensitive scenario and would let a chained check pass while a fatal deadline looms. Treat any entry in proximos as attention-worthy.

Any deadline within the window, not only overdue ones, marks the run as needing attention.
if (proximos.length || sinComputar.length || bloqueados.length) {
  process.exitCode = 1;
}
💡 Edge Case: UTC-based 'hoy' can shift day count for evening runs

📄 componentes/vigia/escanear.mjs:97-99

hoy is derived from new Date() then floored with setUTCHours(0,0,0,0), and deadlines are parsed to UTC midnight. For a user in Argentina (UTC-3) running the scanner in the evening, the UTC date is already the next calendar day, so a deadline due 'tomorrow' local time is reported as en 0d (and an overdue-by-today boundary can flip). Since the tool's audience is Argentine courts, anchor 'today' to the local (or an explicit America/Argentina) calendar date rather than UTC to avoid off-by-one urgency counts.

🤖 Prompt for agents
Code Review: Expands the scanner to watch all expedientes at once, surfacing deadlines that slip through individual-case tracking. Three critical issues block merge: `--json` mode never exits with code 1 regardless of findings, so pipeline chaining on exit status treats every run as clean; imminent (non-overdue) deadlines don't trigger exit 1, letting a `🔴 fatal en 3d` pass as "limpio"; and UTC-based date calculations shift day counts for evening runs in Argentina, causing off-by-one urgency reports. Fix the exit-code logic to treat any entry in `proximos` as attention-worthy, apply it in both output branches, and anchor 'today' to local calendar date.

1. ⚠️ Bug: --json mode never sets a non-zero exit code
   Files: componentes/vigia/escanear.mjs:214-221

   In JSON mode the entry point does `if (JSON_OUT) console.log(...); else informar(resultado);`, so `informar()` — the only place that sets `process.exitCode = 1` — is never called. The scanner therefore always exits 0 with `--json`, contradicting the documented behavior ("Devuelve exit 1 cuando hay algo que atender... así se puede encadenar. Con --json sale estructurado"). Any CI/pipeline that chains on the JSON output's exit status will treat every run as clean. Compute the exit code from the result regardless of output format (e.g. factor the `proximos/sinComputar/bloqueados` check into a helper called in both branches).

   Fix (Set the exit code from the result in both output modes.):
   function estadoSalida({ casos, error }) {
     if (error) return 2;
     const hayVencido = casos.some((c) => c.plazos.some((p) => p.dias !== null && p.dias < 0));
     const haySinComputar = casos.some((c) => c.plazos.some((p) => p.sinComputar));
     const hayBloqueado = casos.some((c) => !c.puedeComputarse);
     return hayVencido || haySinComputar || hayBloqueado ? 1 : 0;
   }
   
   const resultado = await escanear();
   if (JSON_OUT) console.log(JSON.stringify(resultado, null, 2));
   else informar(resultado);
   process.exitCode = estadoSalida(resultado);

2. ⚠️ Bug: Imminent (non-overdue) deadlines don't trigger exit 1
   Files: componentes/vigia/escanear.mjs:214-216

   The exit-code condition is `proximos.some((p) => p.dias < 0) || sinComputar.length || bloqueados.length`. A workspace whose only issue is a deadline that is close but not yet past (e.g. a `🔴 fatal en 3d`, exactly the case shown in the PR's example output) yields exit 0 — reported as "limpio". This defeats the stated purpose ("exit 1 cuando hay algo que atender") for the most time-sensitive scenario and would let a chained check pass while a fatal deadline looms. Treat any entry in `proximos` as attention-worthy.

   Fix (Any deadline within the window, not only overdue ones, marks the run as needing attention.):
   if (proximos.length || sinComputar.length || bloqueados.length) {
     process.exitCode = 1;
   }

3. 💡 Edge Case: UTC-based 'hoy' can shift day count for evening runs
   Files: componentes/vigia/escanear.mjs:97-99

   `hoy` is derived from `new Date()` then floored with `setUTCHours(0,0,0,0)`, and deadlines are parsed to UTC midnight. For a user in Argentina (UTC-3) running the scanner in the evening, the UTC date is already the next calendar day, so a deadline due 'tomorrow' local time is reported as `en 0d` (and an overdue-by-today boundary can flip). Since the tool's audience is Argentine courts, anchor 'today' to the local (or an explicit America/Argentina) calendar date rather than UTC to avoid off-by-one urgency counts.

Tip

Comment Gitar fix CI or enable auto-apply: gitar auto-apply:on

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Important

Your trial ends in 4 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.

Was this helpful? React with 👍 / 👎 | Gitar

Comment on lines +97 to +99
const hoy = new Date();
hoy.setUTCHours(0, 0, 0, 0);
const diasHasta = (f) => Math.round((f - hoy) / 86400000);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Edge Case: UTC-based 'hoy' can shift day count for evening runs

hoy is derived from new Date() then floored with setUTCHours(0,0,0,0), and deadlines are parsed to UTC midnight. For a user in Argentina (UTC-3) running the scanner in the evening, the UTC date is already the next calendar day, so a deadline due 'tomorrow' local time is reported as en 0d (and an overdue-by-today boundary can flip). Since the tool's audience is Argentine courts, anchor 'today' to the local (or an explicit America/Argentina) calendar date rather than UTC to avoid off-by-one urgency counts.

Was this helpful? React with 👍 / 👎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant