RP DOT Pivot-Update — 02 Tool Design + Implementation
02 — dot-pivot-update: Design + Implementation
Full script: artifacts/dot-pivot-update (deployed to /opt/incomex/dot/bin/dot-pivot-update, 14392 bytes, +x).
Conventions followed (from reading the live framework)
Matched dot-matrix-update/dot-matrix-retire exactly: #!/usr/bin/env bash →
set -euo pipefail → source ../config/environment.sh (functions only; init_environment
NOT called to avoid the interactive cloud read -p confirm) → VERSION/VPS_*/PG_*
env defaults → log_info/ok/warn/err → pg_sql() that auto-detects on-VPS (docker exec)
vs remote (ssh) → --flag "$2"; shift 2 arg parsing → validate → UPDATE ... updated_at=NOW()
→ verify. Added -v ON_ERROR_STOP=1 so any server/trigger error yields non-zero exit.
Header carries CHECKED-NO-DUPLICATE and a description (Đ3 metadata requirement).
Interface
dot-pivot-update --code <PIV-xxx> --field <f> --value <v> [--reason "..."] [--commit] [--allow-noop]
dot-pivot-update --code <PIV-xxx> --field composition_level --auto-from-species [--commit]
dot-pivot-update --show --code <PIV-xxx>
- Default = DRY-RUN: applies the UPDATE inside
BEGIN..ROLLBACK, prints OLD→NEW and the mapping-viewcomposition_status, then ROLLBACK. Commits nothing.--commitpersists. --auto-from-species(composition_level only): sets value := the governedentity_species.composition_levelfor the row's species → the deterministic cleanup driver.--show: prints current classification + governed species composition (read-only).
Allowlist + governed validation
| Field | Validation |
|---|---|
| (any) | must be in {composition_level, species, registry_group, description} — else reject |
species |
must exist in entity_species.species_code (governed) |
composition_level |
if row has a governed species → value must equal that species' governed composition (deterministic guard); else value must be a known composition derived live from entity_species ∪ pivot_definitions (regex-filtered, never hardcoded) |
registry_group |
must be a value already in use or a governed FAC-02 taxonomy code; else reject (→ council naming packet) |
description |
non-empty |
Other guards: --code must exist and be active (retired rows refused); no-op refused
unless --allow-noop; exactly one of --value / --auto-from-species; single-quote SQL escaping via esc().
Trigger integration (intentional, Đ26 §II-QUINQUIES 1F)
A single-row, single-field UPDATE fires only trg_after_pivot_definitions_change
(statement-level → refresh_meta_catalog_from_pivot() + refresh_pivot_results()),
once per invocation. It does not fire trg_birth_pivot_definitions (INSERT-only)
nor trg_matrix_config_changed (the 3 targets have matrix_spec IS NULL). Because the
changed columns (composition/species/registry_group) do not affect pivot_query output,
the refresh recomputes identical result values (only refreshed_at bumps) — the system's
own designed consistency cascade, not a tool emit. Single-row scope = no row-by-row
refresh explosion (the explicit requirement).
Why no manual rollback symmetry (by design)
The forward fix converges composition_level to the governed truth. The inverse value
(the old drift) is rejected by the governed guard — you cannot use the tool to
re-introduce known-wrong drift. Pre-fix values are recorded (molecule/atom/atom) for a
DBA-level restore if ever required, but the lawful state is the governed one.
Deviations / honesty notes
descriptionis allowlisted but unused this macro (kept for completeness/parity).registry_groupvalidation is conservative; it is not exercised in the executed cleanup (naming is council-gated, §06).- One bug was found and fixed during rehearsal (boolean inactive-guard) — see §04.