Skip to content

Reactive system doesn't propagate changes to derived attributes #103

Description

@jameshgrn

Summary

The reactive recalculation system (reactive.py) has gaps where derived attributes don't auto-update when their dependencies change.

Gaps Found

Derived Attribute Depends On Auto-Recalculates?
stream_order path_freq ❌ NO
path_segs topology ❌ NO
path_order dist_out ❌ NO
main_side path_freq ✅ YES

Impact

If topology is modified (e.g., fixing flow direction), these attributes become stale:

  • stream_order won't reflect new path_freq
  • path_segs won't reflect new segment boundaries
  • path_order won't reflect new distance ordering

Evidence

From reactive.py analysis:

  • _recalc_reach_main_side() exists and uses path_freq
  • No equivalent _recalc_reach_stream_order() or _recalc_reach_path_segs()

Recommendation

  1. Add stream_order to reactive dependency graph with trigger on path_freq change
  2. Add path_segs to reactive dependency graph with trigger on topology change
  3. Add path_order to reactive dependency graph with trigger on dist_out change
  4. Or document these as "static after initial computation" if intentional

Related


Design Notes (2026-02-17 brainstorming session)

Rescoped to v18. This is bigger than patching reactive.py — the real fix is a PostGIS trigger-based reactive system.

What we learned

  • The Python-side reactive.py (DuckDB) is obsolete for this purpose. Production data lives in PostgreSQL, edited via QGIS.
  • Geometry edits cascade: geometry → reach_id, reach_len → topology (rch_id_up/dn) → dist_out → path_freq → stream_order, path_order, path_segs. Too many dependencies to patch incrementally.
  • path_segs in reconstruction.py is also broken (0.1% match with v17b). Needs a rewrite regardless.

Target architecture (v18)

  • Pure PL/pgSQL trigger functions on sword_reaches_v17b (or v18 table)
  • CONSTRAINT TRIGGER ... INITIALLY DEFERRED so bulk QGIS edits recompute once at transaction commit
  • Scope recalculation to network column (subnetwork ID). If an edit merges two networks, recompute both.
  • path_freq: recursive CTE from outlets (n_rch_dn=0) upstream
  • stream_order: round(ln(path_freq)) + 1, side channels → -9999
  • path_order: ROW_NUMBER() OVER (PARTITION BY path_freq ORDER BY dist_out)
  • path_segs: needs correct junction-based segmentation algorithm (separate sub-task)

Schema reference (sword_reaches_v17b)

  • rch_id_up / rch_id_dn: space-delimited text
  • network: integer subnetwork ID (247 networks, largest is 125K reaches)
  • strm_order, path_freq, path_order, path_segs: bigint columns

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions