Metadata-Version: 2.4
Name: deped-geos
Version: 0.7.2
Summary: School-derived area products for DepEd PSGC, governance, and legislative geographies.
Requires-Python: >=3.14
Requires-Dist: click>=8.4
Requires-Dist: deped-primitives>=0.11
Requires-Dist: deped-runtime[geoparquet]>=0.5
Requires-Dist: duckdb>=1.5
Requires-Dist: environs>=15.0
Requires-Dist: polars>=1.42
Requires-Dist: pyarrow>=22.0
Requires-Dist: rich>=15.0
Requires-Dist: shapely>=2.1
Description-Content-Type: text/markdown

# deped-geos

`deped-geos` is a **producer**: a Polars-first build that turns school records
and PSGC geography into school-derived area artifacts. It is layered on the
shared `deped-primitives` library (reusable hierarchy, territory, boundary,
PSGC, urbanicity, and legislative semantics) and keeps only what is bound to its
own artifact contract. Canonical boundary artifacts remain exact; the producer
also publishes a versioned current-year display tier for high-complexity
derived division and legislative-district maps.

It emits three artifact hierarchies plus national and region-group reporting
rows:

- Normalized PSGC stats by region, province, city, municipality, locality, and
  barangay.
- DepEd governance stats starting at region, with compatibility boundary
  GeoParquet for division and school district.
- Legislative stats starting at region, with compatibility boundary GeoParquet
  for legislative district.

(Strict `psgc` is an internal denominator/ordering construct only; it is never
emitted as an artifact hierarchy.)

The producer consumes two sibling build outputs:
`../deped-dataset/artifacts/db.sqlite3` for source-school tables and
`../deped-maps/artifacts-current` for PSGC CSV, area-boundary component, and
GeoParquet artifacts. It writes Parquet tables, partitioned membership data,
compatibility GeoParquet boundaries, and a manifest with source fingerprints,
source-contract status, timings, and geometry policy. Boundary GeoParquet is
written with PyArrow and Shapely; the `geometry` column is WKB bytes for
consumers to decode at their own display/API boundary.

In plain terms: run `just build` after `deped-dataset` and `deped-maps` are
fresh. The build reads those sibling outputs once and creates this repo's local
`artifacts-current/` folder. The notebook workbench then reads that folder
read-only; it does not go back to the dataset DB or rerun the build. The only
extra lookup is PSGC map geometry, which the notebook uses from bundled or
recorded `deped-maps` artifacts when a PSGC map needs to be drawn.

The installed distribution is `deped-geos`; the Python package is
`deped_geos`. Runtime code is grouped by ownership: `deped_geos.artifacts`,
`deped_geos.sources`, `deped_geos.products`, `deped_geos.producer`, and the
read-only `deped_geos.workbench` helpers. See `docs/architecture.md` for the
full role, ownership boundaries, and engine policy.

## Quick start

```sh
uv sync --all-groups
cd ../deped-dataset && just build
cd ../deped-maps && just build
cd ../deped-geos
just check
just build --output-dir artifacts-current
uv run deped-geos status --output-dir artifacts-current
```

`just build` remains the single deped-geos build command. It validates sibling
inputs but does not rebuild them. If the dataset DB or PSGC bundle is stale or
incomplete, the build fails with instructions to refresh upstream:

```sh
cd ../deped-dataset && just build
cd ../deped-maps && just build
```

Compatibility boundary GeoParquet files are a required producer output when
source geometry is present. The producer writes them with PyArrow and Shapely in
the normal `uv run deped-geos build` / `just build` path. The default test
environment installs the `dev` and `workbench` dependency groups so `just check`
runs the full collected test suite.

## Outputs

`artifacts-current/` contains:

- `manifest.json`
- `school_spine.parquet`
- `school_spine_current.parquet`
- `school_area_source_universe.parquet`
- `school_area_stats.parquet`
- `school_area_assignment_audit.parquet`
- `school_area_memberships/`
- `school_area_region_group_components.parquet`
- `school_area_division_coverage.parquet`
- `school_area_division_coverage_audit.parquet`
- `school_area_denominator_coverage.parquet`
- `school_area_insight_context.parquet`
- `school_area_display_subdivisions.parquet`
- `school_id_crosswalk.parquet`
- `school_area_boundaries_governance_division.parquet`
- `school_area_boundaries_governance_school_district.parquet`
- `school_area_boundaries_legislative_legis_district.parquet`
- `school_area_governance_context.parquet`
- `school_area_boundaries_*_current.parquet`
- `school_area_boundaries_governance_division_display_current.parquet`
- `school_area_boundaries_legislative_legis_district_display_current.parquet`

Area-grain stats, assignment audit, denominator and division coverage, insight
context, display subdivisions, and derived boundaries are keyed by
`school_type_scope` and `school_year_id`. The manifest marks the latest year as
`current` and lists school-type scopes beginning with `__all_active__`
(`All active schools`) and `Public • DepEd`. School spine and memberships stay
single-copy school-grain artifacts with the existing `school_type` column.
Coordinate correctness review belongs exclusively to the `deped-maps` review
workbench; geos keeps latitude and longitude but does not mirror coordinate QA.

CSV exports are optional: run `just build --export-csv` when a downstream handoff needs CSV copies.

`school_area_stats.parquet` owns the complete group universe for every
`(school_type_scope, school_year_id, hierarchy, level, group_id)`: current-year
group counts, denominators, labels, and parent ids belong there. Boundary
GeoParquet files own renderable geometry only. Governance and legislative
geometry comes from `deped-maps` `area_boundary_components.csv` source
components, repeated only for matching scoped stats rows. Derived boundary
GeoParquet is an exact dissolve. Contract 30 additionally publishes current-only
display geometry for divisions and legislative districts. It is simplified as
one coverage per parent region under `derived_boundary_display_v1`, with
component, ring, bounds, and area guards; a failing partition keeps exact WKB.
The manifest records the display path, fingerprint, QA receipt, and policy while
the canonical `path` and `current_path` remain exact. A current stats row without a
matching `school_area_boundaries_*_current.parquet` row is valid and means the
group is known, but has no display geometry for consumers to draw. Downstream
apps should select `display_current_path` for current maps, treat `geometry` as
WKB, and perform GeoJSON serialization outside the producer.

`school_area_governance_context.parquet` is a separate ADM4 collection of
canonical barangays classified upstream as `no_observed_district`. It is map
context only: consumers render it neutrally behind observed governance areas
and exclude it from metric joins, aggregation, tables, charts, and numeric
legend bins.

`school_area_stats.parquet` also includes shared planning ratios such as
`students_per_school`, `students_per_capita`, `population_per_school`,
`school_density`, `area_per_school`, plus `urban_barangay_share` and
`barangay_urbanicity_band`. These are producer-emitted artifact fields backed
by `deped-primitives` metric and urbanicity semantics; notebooks and downstream
consumers should read them rather than recomputing them at runtime.

`school_area_source_universe.parquet` preserves PSGC labels, parent ancestry,
boundary mapping, and denominator seeds for no-school groups so boundary-first
maps can render known geography without downstream inference.

## Docs and notebooks

```sh
uv run zensical build
just notebooks
just check-full
```

The local Marimo notebooks inspect `artifacts-current/` read-only and render
maps in-cell. They do not expose a server/API contract.
