Nine findings from review, all taken. Row reads (getdata): - approversForTable reads every column through field(): the security and group rows are seeded with UPPERCASE keys and an edited row comes back lower-cased, so a direct property read compared undefined with 'UNDEFINED' and found no grant - silently falling back to the admin group for every table. - tx_to is handled by rowInForce(): epoch seconds, which is what Date.now()/1000 assumes, with an ISO string accepted; a blank, absent or unparseable end date is open-ended rather than expired, so a rule or a grant that omits it is no longer dropped as NaN. The dqrules filter reads rule_active/base_lib/base_ds through field() for the same reason. Rows and the text that describes them (getdata): - the current-rows clause in FILTER_TEXT is now applied to the selection: the grid no longer shows expired rows while telling the user they were excluded. - the primary-key sort resolves each key to the column's own casing, so a lowercase DDL sorts on real values instead of comparing undefined. Settings (getdata, viewlibs): - dcLibref falls back to 'DC_JSLIB' like dcAdminGroup already did: a deploy that has not run makedata has no settings.js, and viewlibs must still list the control library. Wording that had gone stale: - the parity README's Status paragraph now states the invariant (every scenario is gated; gated:false is advisory) instead of counts and a list of differences that were fixed, and the scenarios.json notes say what each scenario pins now. - viewdata's comment states the contract rather than the behaviour it replaced, and the synthetic no-data row writes the same space for a blank character cell as the data rows do. Tests: getdata-rules.test.js covers an uppercase-keyed APPROVE grant and an open-ended rule (both fail on the previous code); viewdata.test.js covers the numeric missing and the empty-table row.