fix(corpus): חיפה is its own district, not folded into צפון (G2)
Haifa (מחוז חיפה) and the North (מחוז הצפון) are separate Israeli planning
districts, each with its own appeals committee. Two divergent bugs collapsed
Haifa into צפון:
- services/internal_decisions.py _VALID_DISTRICTS omitted "חיפה" (while the
tools-layer VALID_DISTRICTS and db.py citation-abbrev map both include it —
a G2 single-source-of-truth divergence)
- _COURT_TO_DISTRICT mapped "חיפה" -> "צפון", so Haifa courts derived צפון
Result: 2 Haifa committee decisions (1074-08-23, 8508-03-24) were mis-filed
under צפון, and "חיפה" never appeared as a district.
Changes:
- add "חיפה" to service _VALID_DISTRICTS
- _COURT_TO_DISTRICT: ("חיפה","צפון") -> ("חיפה","חיפה")
- SCHEMA_V43: reclassify legacy internal rows whose court mentions חיפה from
צפון -> חיפה (normalize at source, G1; idempotent)
Verified against live DB (rollback txn): 2 rows move צפון(6)->צפון(4)+חיפה(2).
Invariants: G1 (normalize at source) · G2 (single source of truth for the
valid-district set — follow-up: consolidate the 3 divergent lists).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1690,6 +1690,19 @@ EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
"""
|
||||
|
||||
|
||||
SCHEMA_V43_SQL = """
|
||||
-- חיפה (Haifa) is a distinct planning district, separate from הצפון (North).
|
||||
-- A bug in _district_from_court mapped "חיפה" -> "צפון", and the service-layer
|
||||
-- _VALID_DISTRICTS omitted "חיפה" entirely, so Haifa committee decisions were
|
||||
-- mis-filed under צפון. Both fixed in internal_decisions.py; this reclassifies
|
||||
-- the legacy rows at the source (G1) by their court text. Idempotent.
|
||||
UPDATE case_law SET district = 'חיפה'
|
||||
WHERE source_kind = 'internal_committee'
|
||||
AND district = 'צפון'
|
||||
AND court ILIKE '%חיפה%';
|
||||
"""
|
||||
|
||||
|
||||
# Stable, arbitrary key for the session-level advisory lock that serialises
|
||||
# schema DDL across processes. Every short-lived process (cron drains, services)
|
||||
# re-runs the idempotent migrations on startup; without this lock two processes
|
||||
@@ -1707,7 +1720,7 @@ async def _run_schema_migrations(pool: asyncpg.Pool) -> None:
|
||||
await _apply_schema_ddl(conn)
|
||||
finally:
|
||||
await conn.execute("SELECT pg_advisory_unlock($1)", _MIGRATION_LOCK_KEY)
|
||||
logger.info("Database schema initialized (v1-v42)")
|
||||
logger.info("Database schema initialized (v1-v43)")
|
||||
|
||||
|
||||
async def _apply_schema_ddl(conn: asyncpg.Connection) -> None:
|
||||
@@ -1754,6 +1767,7 @@ async def _apply_schema_ddl(conn: asyncpg.Connection) -> None:
|
||||
await conn.execute(SCHEMA_V40_SQL)
|
||||
await conn.execute(SCHEMA_V41_SQL)
|
||||
await conn.execute(SCHEMA_V42_SQL)
|
||||
await conn.execute(SCHEMA_V43_SQL)
|
||||
|
||||
|
||||
async def init_schema() -> None:
|
||||
|
||||
@@ -28,14 +28,14 @@ logger = logging.getLogger(__name__)
|
||||
INTERNAL_DECISIONS_DIR = Path(config.DATA_DIR) / "internal-decisions"
|
||||
|
||||
_VALID_PRACTICE_AREAS = frozenset({"", "rishuy_uvniya", "betterment_levy", "compensation_197"})
|
||||
_VALID_DISTRICTS = frozenset({"", "ירושלים", "מרכז", "תל אביב", "צפון", "דרום", "ארצי"})
|
||||
_VALID_DISTRICTS = frozenset({"", "ירושלים", "מרכז", "תל אביב", "חיפה", "צפון", "דרום", "ארצי"})
|
||||
|
||||
_COURT_TO_DISTRICT = [
|
||||
("ירושלים", "ירושלים"),
|
||||
("תל אביב", "תל אביב"),
|
||||
('ת"א', "תל אביב"),
|
||||
("מרכז", "מרכז"),
|
||||
("חיפה", "צפון"),
|
||||
("חיפה", "חיפה"),
|
||||
("צפון", "צפון"),
|
||||
("דרום", "דרום"),
|
||||
("ארצי", "ארצי"),
|
||||
|
||||
Reference in New Issue
Block a user