15 Commits

Author SHA1 Message Date
cc-ultrav-1
70740d3c8c fix: Update E2E test dates — Oct 19-27 all consumed by bot rush, use Oct 28 (9 slots, beyond 15-day window) 2026-10-12 19:45:34 +02:00
cc-ultrav-1
c94341bf43 Add .gitignore for test artifacts 2026-10-12 19:42:00 +02:00
cc-ultrav-1
2dd89e7d02 Add BOOKING_DEVELOPMENT_PROCESS.md — full development documentation (177 lines, 25KB) 2026-10-12 15:12:18 +02:00
cc-ultrav-1
e837a4ff35 fix: per-slot timing for unexpected/else branch + display dynamic target time
- else (catch-all) branch now appends to slot_timings with 'unexpected' status
- Target timestamp display fixed: now uses datetime.fromtimestamp(TARGET_TS)
  instead of hardcoded 'Oct 4 00:00:00'
- Added booking_run_2.log: Oct 20 midnight attempt (blocked by duplicate cita)
2026-10-05 00:23:21 +02:00
cc-ultrav-1
20a7fd0dc2 fix: dynamic target timestamp display (was hardcoded 'Oct 4')
The startup message showed 'Oct 4 00:00:00' regardless of TARGET_TS value.
Now uses datetime.fromtimestamp(TARGET_TS) for accurate display.
2026-10-05 00:22:01 +02:00
cc-ultrav-1
b4b26938c4 fix: duplicate detection for 'Usted ya tiene cita previa' + timing bug fixes
Bugs fixed:
- _track_rtt(ms) on success log returned None → switched to _current_load()
- _track_rtt(round(ms,1)) on 'Hora no permitida' path: returned None,
  double-tracked RTT (already tracked in make_request), AND called round()
  in the path (violates zero-overhead rule) → switched to _current_load()
- cur_load = _current_load() in skew retry loop: computed but never used
  → removed (dead code, adds overhead per retry iteration)

Duplicate detection:
- Added DUPLICATE_PATTERNS tuple centralized duplicate string matching
- Added 'Uciente' discovered: server returns 'Usted ya tiene cita previa en
  la gestion especificada' when NIE already has a cita for this servicio/cola
- Added _is_duplicate() helper, used in all 3 detection sites (initial, retry,
  reconnect)
- Updated 'else' catch-all with clearer guidance message

Tests:
- Updated test_loop_breaks_on_duplicate to work with _is_duplicate() refactor
- Added test_duplicate_detection_includes_new_string
- Updated E2E getHorasCitas test: Oct 20 fully booked → Oct 21 (9 slots)
2026-10-05 00:14:47 +02:00
cc-ultrav-1
3c960c1ce5 Add booking artifacts, API data, and catalog files
- booking_log.txt: midnight run results (cita booked at 15:15, 3347ms RTT)
- fire_at_midnight.py: original midnight launch script
- book_cita.sh / book_at_midnight.py: booking shell scripts
- fetch_final.py / fetch_cita.sh: API fetch utilities
- services_full.js, controllers_full.js, app_real2.js: frontend source
- services_real.js, url.js: API endpoint references
- tipos_doc.json: document type data from API
- benchmark_results.json: server load profiling results
2026-10-04 02:40:30 +02:00
cc-ultrav-1
f822f0f590 feat: CLI parameter system for multi-department cita booking
Added CITA_TYPES catalog (44 servicio/cola combos from live API),
DOC_TYPES, argparse CLI (--servicio/-s, --cola/-c, form params,
--help-citas, --dry-run, --prompt), validate_config() with per-type
field requirements, and prompt_missing() for interactive mode.

Zero impact on defaults: no args = original behavior.
2026-10-04 00:57:26 +02:00
cc-ultrav-1
dd7075df79 perf: zero-overhead hot path — _track_rtt appends only, compute_load deferred
Verified via benchmark: 0.076µs per call (list append), 0.0044% of RTT.
The load computation (sum/variance/σ) is deferred to _compute_load()
which is ONLY called from log messages — never in make_request or
the retry loop.

- _track_rtt() now returns None, appends only (was: appended + computed load)
- _compute_load() extracted from _track_rtt for lazy load estimation
- _current_load() delegates to _compute_load()
- Removed round() from hot path — raw float append, rounding deferred
- Removed round() from make_request _track_rtt call
- Tests: 79 passed (added TestHotPathZeroOverhead: 4 tests)
2026-10-03 23:25:43 +02:00
cc-ultrav-1
473841f509 feat: best-of-breed logging with severity levels, server load estimation, per-slot timings
Enhanced logging and timing infrastructure:

1. log() now supports severity levels: INFO, WARN, ERROR, SUCCESS, PHASE
   - Colored output in TTY, plain in non-TTY (file persistence)
   - All phase transitions use PHASE level for easy filtering

2. bench() now accepts category parameter for filtering:
   Categories: TLS_CONNECT, TLS_RECONNECT, CHECK_SLOTS, BOOKING_ATTEMPT,
   RETRY, RETRY_CONN, VERIFY, CHECK, RECOVERY

3. Server load estimation — tracks RTT via _track_rtt():
   - _rtt_history: all response times in ms
   - _current_load(): LOW/MODERATE/HIGH based on σ < 25/100ms thresholds
   - _load_trend(): STABLE/INCREASING/DECREASING via half-comparison
   - Load appears in every slot summary and benchmark

4. Per-slot timing tracking:
   - slot_timings list: {hora, total_ms, attempts, avg_rtt_ms, status}
   - t_booking_start + t_prefire for total time-to-success
   - t_prefire_to_success + t_success_total on booking success

5. Enhanced benchmark summary:
   - SERVER LOAD ESTIMATION section (RTT stats, variance, trend)
   - PER-SLOT TIMING table (Hora, Status, Attempts, Total ms, Avg RTT)
   - TIME TO SUCCESS section (pre-fire→cita, booking-start→cita)
   - All BENCH entries now show category column

6. EXCEPTION branch now handles all response types explicitly:
   - Cita insertada, duplicate, EXCEPTION, Hora no permitida,
   Fecha posterior, other — no more catch-all else clause

Tests: 75 passed (17 new tests for logging/severity/load/timings)
2026-10-03 23:20:24 +02:00
cc-ultrav-1
7048f44d67 fix: duplicate detected on retry must STOP entire booking process (not just slot)
Critical logic bug caught by careful review:

- When 'Cita insertada' is returned on a retry, the cita is ALREADY
  inserted into the database — no further booking action needed, just
  confirm and exit (the comment 'Book it!' was misleading).

- When a duplicate ('ya existente'/'DNI'/'existe') was detected during
  skew retry, the code only broke the inner while loop. Since booked_hora
  was None, 'if booked_hora: break' did NOT trigger, and the outer for
  loop continued to the NEXT slot — potentially booking additional
  slots when a cita for this person already exists.

- The EXCEPTION branch's force-reconnect retry had NO duplicate detection
  at all — it fell through to a generic 'else: log()' for any unexpected
  response, including duplicates.

Fixes:
- Added duplicate_detected flag (initialized False) checked in outer
  loop: 'if booked_hora or duplicate_detected: break'
- Set duplicate_detected = True in ALL three duplicate detection paths:
  (1) initial attempt, (2) skew retry loop, (3) EXCEPTION retry
- Added explicit 'Hora no permitida' and 'Fecha posterior' handling
  in EXCEPTION retry branch (was generic else)
- Removed stale '5x43ms' comment → reflects true '120s 3-phase backoff'
- Clarified comments: 'Cita insertada' = already booked (success),
  not a booking action to perform

Tests: 58 passed (added test_duplicate_detected_flag_stops_outer_loop)
2026-10-03 22:51:33 +02:00
cc-ultrav-1
f4f5fe0996 feat: three-phase skew retry with 120s budget — no false giveups
Three-phase backoff per slot, each retry independent (no global skip):
  Phase 1 (6 retries): 43ms × 1.5^n — aggressive midnight catch
  Phase 2 (6 retries): 330ms × 1.15^n, capped 500ms — gradual
  Phase 3 (120s budget): 2s × 1.2^n, capped 15s — catches cancellations

Only give up when CERTIFIED:
  'Hora no permitida' = slot genuinely taken (safe to skip this slot)
  'Cita insertada' = success (exit)
  'already exists'/duplicate = STOP entirely
  'Fecha posterior' = NOT certified → keep retrying

SKEW_MAX_BUDGET raised from 2.5s → 120s. No false-positive giveups.
Tests: 57 passed
2026-10-03 22:28:52 +02:00
cc-ultrav-1
7cf94f8a3a Fix: two-phase backoff — each slot gets independent retry window
CRITICAL BUG FIX: skew_retries_exhausted was a global skip gate — once
first slot exhausted retries, ALL subsequent slots skipped retries.
Later slots could miss the midnight transition during their own window.

New design:
- Two-phase pseudo-exponential backoff PER SLOT (not global):
  Phase 1 (aggressive): 43ms x 1.5^n for first 6 retries
  Phase 2 (gradual): 330ms x 1.15^n after 6 (less bot-spammy)
- 2.5s time budget per slot (covers NTP skew up to ~2s + lift)
- skew_retries_exhausted is now diagnostics-only (set but NOT used to skip)
- _skew_delay() helper computes two-phase delays
- Only 'Hora no permitida' certifies a slot as taken
- 'Fecha posterior' never a give-up reason — server date not rolled yet

Tests: 57 passed
Live: 8 retries on 15:15, all 9 slots still free post-test
2026-10-03 21:40:33 +02:00
cc-ultrav-1
246bb92b1c Fix: each priority slot gets independent skew retry window
The skew_retries_exhausted flag was a premature optimization that skipped
5x43ms retries on all subsequent slots once the first slot exhausted
its retries. This is a bug: the server date may roll during a later
slot's retry window even if earlier slots failed, so each slot must get
its own full retry chance.

Changes:
- Removed 'if skew_retries_exhausted:' skip gate before the retry loop
- Each slot now always runs 'for skew_attempt in range(5)' independently
- skew_retries_exhausted kept as diagnostics-only variable (not used
  to skip), preserving test assertions
- Updated loop header comment + Phase 3c docstring
- Added test_each_slot_gets_own_retry_window to prevent regression

Tests: 57 passed (56 + 1 new)
2026-10-03 21:12:36 +02:00
cc-ultrav-1
7da1dbe0fd Smoke-test verified booking stack v1.3.1 — live API flow confirmed
Full end-to-end smoke test against live cita API (194.179.69.48:443):
  - TLS pre-connect: 415ms, TCP_NODELAY set, connection reused
  - getHorasCitas: 200, 9 slots returned
  - Booking 15:15: 200, 'Fecha posterior' (expected pre-midnight)
  - Skew retry 43ms x5: verified retry stack
  - Post-verify: slot still free, no accidental citas
  - TLS tunnel reuse PROVEN: same fd (3), same port (53880), only 1 TCP conn in ss

Fixes in this commit:
  - Fixed 3 stale comments referencing old 200ms skew retry delay (now 43ms)
    (lines 276, 295, 372) — line 351 kept as intentional comparison
  - All 56 tests pass

Changes:
  - book_final.py: comment fixes (lines 276, 295, 351, 372)
  - test_book_final.py: unchanged (40 tests)
  - test_connection_reuse.py: unchanged (16 tests)
2026-10-03 19:30:03 +02:00