You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] the two human-user predicates disagree on non-object rows, and the plugin-security spelling fails OPEN — the class #12512's pin deliberately excludes #12515
Surfaced by the dev implementing #11959 (PR #12512) and filed by the domain:services PM seat on review. Filed unassigned; ⛔ no domain:* — routing and grading are triage's.
What was measured
The two owners of "is this sys_user row a HUMAN?" disagree on non-object truthy inputs:
isHumanUser (plugin-security/src/bootstrap-platform-admin.ts:401) is u && u.id !== SystemUserId.SYSTEM && u.role !== 'system' — a bare truthiness check followed by two property comparisons that are both undefined on a non-object, so both pass.
Measured by executing the expression extracted verbatim from source, not by reading it.
⚠️Direction matters: the security copy fails OPEN — it calls a non-row "human", and it is the copy that performs the platform-admin promotion.
Why this is a finding and not a defect
It is unreachable today. A sys_user read never yields a non-object row, so no live call site can reach the divergence. ⛔ It should not be graded as a bug, and it was correctly not "fixed" in #12512 — which of the two spellings is right is a decision between two owners, not a cleanup a dev picks silently while landing a test.
Why it is still worth a card rather than a shrug
Two reasons, and the second is the load-bearing one:
test(auth): pin the human-user predicate agreement across the plugin-security boundary #12512's pin deliberately excludes this input class. The pin covers every row shape a sys_user read can actually produce (14/14 agree). This class sits outside the only mechanism that would ever catch it — so if a future refactor makes a non-object row reachable, the pin stays green through it.
⚠️"The consolidation will delete it anyway" is not currently true. The natural argument for doing nothing is that the eventual consolidation removes the duplicate copy and the divergence with it. But consolidation is explicitly declined — triage ruled at [finding] a third hand-spelled copy of the human-user predicate lives in plugin-security, out of reach of the one #11767 consolidated #11959's grading that moving the predicate into @objectstack/spec / @objectstack/platform-objects expands a published surface and "stays declined absent new pull". So there is no scheduled event that retires this asymmetry.
⇒ Recording it makes it a decision rather than an oversight, which is the whole difference.
Options, so grading is cheap
shape
note
A
close as won't-fix, on record
honest if the reachability judgement is accepted and nobody wants the asymmetry tracked
B
add a typeof guard to the plugin-security copy so both spell the same rule
⚠️ picks a winner between two owners — small, but it is a decision
A second, behaviourally inert shape difference recorded for completeness: for falsy input the security closure returns the input itself (null) where isHumanUserRow returns false. Both are consumed by .filter(), so the decision is identical — this is why test(auth): pin the human-user predicate agreement across the plugin-security boundary #12512's pin compares decisions rather than raw return values.
Surfaced by the dev implementing #11959 (PR #12512) and filed by the
domain:servicesPM seat on review. Filed unassigned; ⛔ nodomain:*— routing and grading are triage's.What was measured
The two owners of "is this
sys_userrow a HUMAN?" disagree on non-object truthy inputs:plugin-authisHumanUserRowplugin-securityisHumanUser'usr_alice'(a string)falsetruefalsetruetruefalsetrueCause, from the two spellings:
isHumanUserRow(plugin-auth/src/audience-posture.ts:317) requirestypeof row === 'object'.isHumanUser(plugin-security/src/bootstrap-platform-admin.ts:401) isu && u.id !== SystemUserId.SYSTEM && u.role !== 'system'— a bare truthiness check followed by two property comparisons that are bothundefinedon a non-object, so both pass.Measured by executing the expression extracted verbatim from source, not by reading it.
Why this is a
findingand not a defectIt is unreachable today. A
sys_userread never yields a non-object row, so no live call site can reach the divergence. ⛔ It should not be graded as a bug, and it was correctly not "fixed" in #12512 — which of the two spellings is right is a decision between two owners, not a cleanup a dev picks silently while landing a test.Why it is still worth a card rather than a shrug
Two reasons, and the second is the load-bearing one:
sys_userread can actually produce (14/14 agree). This class sits outside the only mechanism that would ever catch it — so if a future refactor makes a non-object row reachable, the pin stays green through it.@objectstack/spec/@objectstack/platform-objectsexpands a published surface and "stays declined absent new pull". So there is no scheduled event that retires this asymmetry.⇒ Recording it makes it a decision rather than an oversight, which is the whole difference.
Options, so grading is cheap
typeofguard to the plugin-security copy so both spell the same rule⛔ Deliberately not recommending one — this is a grading call, and the seat that filed it has no more evidence than the table above.
Related
plugin-authcopiesnull) whereisHumanUserRowreturnsfalse. Both are consumed by.filter(), so the decision is identical — this is why test(auth): pin the human-user predicate agreement across the plugin-security boundary #12512's pin compares decisions rather than raw return values.