From 9d48240111edc0d1b31ad0b6f8a2d774b2171341 Mon Sep 17 00:00:00 2001 From: dc Date: Thu, 15 Oct 2026 17:49:01 +0000 Subject: [PATCH] docs(developer-guide): address review on the pre-edit hook page - The re-read step now sorts work.out by &sortpk after rebuilding it, matching getdata (which sorts before the hook runs and does not sort again), so the grid keeps the order the user first saw. The bullet records why. - Adds a .pre-commit-config.yaml with the gitleaks hook pinned to v8.30.1, so staged content is scanned at commit time. --- .pre-commit-config.yaml | 11 +++++++++++ docs/developer-guide/filter-pre-edit-hook.md | 7 ++++++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..b429dc4 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,11 @@ +# Hooks for the pre-commit framework - https://pre-commit.com +# +# This repo carries no native git hooks, so this is the route for a secret scan +# at commit time: install the framework once with `pre-commit install`, and the +# scan then runs on every commit. The hook is pinned to an exact gitleaks +# release tag. +repos: + - repo: https://github.com/gitleaks/gitleaks + rev: v8.30.1 + hooks: + - id: gitleaks diff --git a/docs/developer-guide/filter-pre-edit-hook.md b/docs/developer-guide/filter-pre-edit-hook.md index 274458e..e1bcac0 100644 --- a/docs/developer-guide/filter-pre-edit-hook.md +++ b/docs/developer-guide/filter-pre-edit-hook.md @@ -106,6 +106,11 @@ The hook below is registered in `MPE_TABLES.PRE_EDIT_HOOK` for a table with a da where %inc newfilt; run; + /* keep the order the editor first showed */ + proc sort data=work.out; + by &sortpk; + run; + /* hand the widened filter back to the editor */ data _null_; file filtref lrecl=32767; @@ -125,7 +130,7 @@ The hook below is registered in `MPE_TABLES.PRE_EDIT_HOOK` for a table with a da - **The user's clause.** `work.QUERY` is the filter's clauses as structured rows, and `%mp_filtergenerate` turns them back into a WHERE clause. This is the user's filter on its own, with no Row Level Security or validity clause mixed in. - **Data Controller's clause.** Calling `%mpe_filtermaster` with `filter_rk=-1` produces the part of the filter that is not the user's: the current-record validity clause and any Row Level Security, or `1=1` when there is neither. - **The combined filter.** The two clauses are combined as `( user OR previous-quarter ) AND ( validity + RLS )`, so the previous quarter is added to the user's selection without widening anything the user is not entitled to see. -- **The rows.** `work.OUT` is rebuilt with the combined filter, using the same drop list as the data step `getdata` runs itself - the transaction and processing columns, plus `&drop_rk`, the surrogate key that `getdata` hides when a table is registered with `RK_UNDERLYING`. On a bitemporal table `getdata` also deduplicates to the latest record per primary key (`by &pk &var_busfrom`); add that step too, or the re-read returns every temporal version rather than the current one. +- **The rows.** `work.OUT` is rebuilt with the combined filter, using the same drop list as the data step `getdata` runs itself - the transaction and processing columns, plus `&drop_rk`, the surrogate key that `getdata` hides when a table is registered with `RK_UNDERLYING` - and sorted on `&sortpk`, because `getdata` sorts before the hook runs and does not sort again afterwards. On a bitemporal table `getdata` also deduplicates to the latest record per primary key (`by &pk &var_busfrom`); add that step too, or the re-read returns every temporal version rather than the current one. - **The returned text.** `filtref` is overwritten with the combined filter, so the clause the editor shows is the one that was actually applied. ### What it looks like