Proyecto independiente No afiliado, patrocinado ni avalado por la Watch Tower Bible and Tract Society o Jehovah's Witnesses.
jw-agent-toolkit
EN

Paquete · Librería

jw-meeting-scheduler

Solver de asignaciones + importer organized-app

Cierra el loop operativo del meeting-scheduler. Diseñado para que un anciano del cuerpo pueda: (1) importar el roster desde organized-app web/desktop (F81.0), (2) editar manualmente privilegios + asignaciones elegibles + status con CRDT-preserving last_updated (F81.1), (3) declarar las reglas locales en constraints.yaml versionado (F81.2). El CP-SAT solver y el assignment_generator agent vienen en F81.3+. El store vive en ~/.jw-agent-toolkit/congregations/<id>/ aislado por congregación; el cifrado at-rest usa FieldEncryptor con salt PBKDF2 derivada del congregation_id (mismo passphrase en dos congregaciones produce keys distintas). El re-import desde organized-app respeta CRDT: una edición manual con last_updated más reciente NO se machaca.

Funcionalidades

Lo que hace, en detalle.

01

organized-app JSON backup importer (F81.0)

load_backup con Pydantic OrganizedAppBackup envelope + lista de PersonType del schema F51. map_person convierte PersonType.person_data.* en PersonRecord plano (gender derivado de male/female booleans separados, status derivado de publisher_baptized/unbaptized.active + statusHistory, privileges activos sólo, eligible_assignments flattened+deduped, time_away filtered, last_updated = max(updatedAt) de todos los campos Timestamped). map_schedule_week walk recursivo del SchedWeek anidado picking up dict slots {value, type, updatedAt} → AssignmentHistoryEntry con aula auto-detected del field suffix (_B→aux_class_1, _C→aux_class_2). slugify_person_id con NFD strip diacritics + lowercase. run_import pipeline con dry-run flag + compute_person_diff (added/updated/kept_local/unchanged).

02

Store SQLite + CRDT upsert (F81.0)

SchedulerStore con dos tables: persons (PK person_id) + history (PK entry_id, índice compuesto person_id+assignment_code+meeting_date DESC para rotation queries rápidas). upsert_person con CRDT guard: si existing.last_updated ≥ rec.last_updated, no escribe (local newer wins). record_history con INSERT OR IGNORE por entry_id (idempotente). last_history_for(person, code) query para el solver. slug_table() reverse lookup display → person_id para el schedule mapper. JW_MEETING_SCHED_HOME env override del path por defecto ~/.jw-agent-toolkit/congregations/.

03

Encryption helper sobre FieldEncryptor (F81.0)

get_encryptor(passphrase, congregation_id) wrapea jw_core.privacy.encryption.FieldEncryptor con salt PBKDF2 derivada del congregation_id (b'jw-meeting-scheduler/v1:' + congregation_id). Si passphrase es None, FieldEncryptor cae a JW_PRIVACY_KEY env var o no-op (cleartext + warning) — mismo patrón que field_report.py. Output cifrado es str base64 Fernet token, NUNCA bytes (consistencia con field_report). Mismo passphrase + distinto congregation_id → keys distintas (verificado en tests con Fernet InvalidToken).

04

CLI edits manuales del roster (F81.1)

jw scheduler people list (Rich table del roster con privileges, eligible count, last_updated). jw scheduler person edit <slug> con --add-privilege ms/elder, --remove-privilege, --add-eligible (acepta nombre MM_BibleReading o código numérico 100), --remove-eligible, --set-status active/irregular/inactive/disfellowshipped. Cada edición toca last_updated con datetime.now(UTC).strftime('%Y-%m-%dT%H:%M:%S') para CRDT-preserving (re-import futuro respeta el edit). jw scheduler history --person <slug> --congregation <id> listing meeting_date DESC con field, code (enum name), aula, confirmed, cancelled.

05

AssignmentConstraints YAML por congregación (F81.2)

AssignmentConstraints Pydantic v2 strict (extra='forbid') con congregation_id regex pattern, gap_minimum_days dict[AssignmentCode, int] (18 códigos default: 60d bible_reading, 90d speaker+TGWTalk, 45d student parts), max_assignments_per_month [1,10], pair_experienced_with_novice, require_brother_for_reading (hard constraint para reading), languages_active (≥1), aulas_active (subset de main_hall/aux_class_1/aux_class_2), weights dict[str, float] no-negativos (rotation_gap, balance_per_month, skill_match, novice_pairing, aula_distribution). constraints_io.load_constraints + write_default_constraints. Hand-rolled commented YAML dump porque PyYAML no preserva comments. CLI jw scheduler constraints {init [--force], lint, show}.

06

Solver CP-SAT (F81.3, pendiente)

OR-Tools CpModel con variables booleanas x[person, slot] por persona elegible × slot del programa. Hard constraints: género-compatible (presidente, orador público, lectura solo hermanos bautizados), privilege-compatible (presidente reserved a ancianos/MS), pareja same-gender en AYF demonstrations, no asignación doble en una semana. Soft constraints como IntVar de penalización sumados en Minimize(): rotación gap_minimum_days hard floor, balance ≤ max_assignments_per_month, novice pairing con assistant experimentado. Output ProposedSchedWeek + infeasibility_reason estructurado por slot. Determinista con params.random_seed.

En la práctica

Cuatro líneas.
Resultado verificable.

Flujo end-to-end: import → edición manual → constraints YAML.

bash · jw-meeting-scheduler
# 1. Importar el roster desde organized-app
uv run jw scheduler import \
  --backup ~/Downloads/organized-backup.json \
  --congregation kingdom-hall-central \
  --passphrase "correct-horse-battery-staple"

# 2. Ver el roster
uv run jw scheduler people list --congregation kingdom-hall-central

# 3. Editar manualmente (CRDT-preserving — un re-import no machaca)
uv run jw scheduler person edit juan-perez \
  --congregation kingdom-hall-central \
  --add-privilege ms \
  --add-eligible MM_TGWTalk \
  --add-eligible MM_BibleReading

# 4. Declarar reglas locales
uv run jw scheduler constraints init --congregation kingdom-hall-central
# Editar ~/.jw-agent-toolkit/congregations/kingdom-hall-central/constraints.yaml
uv run jw scheduler constraints lint --congregation kingdom-hall-central
uv run jw scheduler constraints show --congregation kingdom-hall-central

# 5. Ver historial de asignaciones
uv run jw scheduler history \
  --person juan-perez --congregation kingdom-hall-central

# 6. Sugerir asignaciones para una semana (F81.3, pendiente)
# uv run jw scheduler suggest --week 2026-07-06 --congregation kingdom-hall-central

API pública

Qué exporta el módulo.

Resumen de los símbolos principales. La referencia exhaustiva cubre cada uno con signature, parámetros y ejemplos.

  • models.{PersonRecord, AssignmentHistoryEntry, TimeAway}
  • importer.loader.load_backup · OrganizedAppBackup
  • importer.person_mapper.{map_person, slugify_person_id}
  • importer.schedule_mapper.map_schedule_week
  • importer.pipeline.run_import · ImportReport
  • importer.diff.compute_person_diff · ImportDiff
  • store.SchedulerStore · open_store
  • crypto.get_encryptor (FieldEncryptor + salt PBKDF2 por congregación)
  • constraints.AssignmentConstraints · DEFAULT_GAP_MINIMUM_DAYS · DEFAULT_WEIGHTS
  • constraints_io.{load_constraints, write_default_constraints, constraints_path}
  • CLI: jw scheduler {import, people list, person edit, history, constraints {init, lint, show}}