Problem
An NGO/agent viewing their own profile sees their own address masked (e.g. o***, 10407) instead of the real value. There's no privacy reason to mask an agent's address from the agent themselves.
Root cause
In src/server/utils/pii/mask.ts, the maskPii walker has a Person branch that correctly checks visibility before masking:
if (node instanceof Person) {
const isVisible = ctx.personIds.has(node.id);
if (!isVisible) {
maskFields(node as unknown as Record<string, unknown>, PERSON_PII_FIELDS);
}
...
}
But the standalone Address branch masks unconditionally, with no visibility check at all:
} else if (node instanceof Address) {
// Reached not via a Person (e.g. agent.address) -> standalone PII, mask it.
maskFields(
node as unknown as Record<string, unknown>,
ADDRESS_PII_FIELDS,
);
}
There's also no Agent branch in the walker at all (only Person, Address, Opportunity, Comment), so when the walk descends into an Agent entity and reaches agent.address, it's masked as a plain standalone Address — regardless of whether ctx.agentIds (populated in resolveCallerVisibility, see src/server/utils/pii/visible-persons.ts) already contains that agent's own id.
Proposed fix
Add an Agent branch to the walker, mirroring the Person branch's pattern: if ctx.agentIds.has(node.id), treat the agent (and its address) as visible and skip masking, then seen.add(node.address) so the fallback standalone-Address branch doesn't re-mask it — same pattern already used for a visible Person's own address.
Acceptance criteria
- An AGENT-role caller viewing their own agent profile sees their own address unmasked
- Callers without visibility into a given agent (e.g. another agent, or a volunteer) still see that agent's address masked
- Existing masking behavior for
Person, Opportunity accompanying, and Comment is unaffected
Related
Problem
An NGO/agent viewing their own profile sees their own address masked (e.g.
o***, 10407) instead of the real value. There's no privacy reason to mask an agent's address from the agent themselves.Root cause
In
src/server/utils/pii/mask.ts, themaskPiiwalker has aPersonbranch that correctly checks visibility before masking:But the standalone
Addressbranch masks unconditionally, with no visibility check at all:There's also no
Agentbranch in the walker at all (onlyPerson,Address,Opportunity,Comment), so when the walk descends into anAgententity and reachesagent.address, it's masked as a plain standaloneAddress— regardless of whetherctx.agentIds(populated inresolveCallerVisibility, seesrc/server/utils/pii/visible-persons.ts) already contains that agent's own id.Proposed fix
Add an
Agentbranch to the walker, mirroring thePersonbranch's pattern: ifctx.agentIds.has(node.id), treat the agent (and itsaddress) as visible and skip masking, thenseen.add(node.address)so the fallback standalone-Addressbranch doesn't re-mask it — same pattern already used for a visiblePerson's own address.Acceptance criteria
Person,Opportunityaccompanying, andCommentis unaffectedRelated
febefore the root cause was traced to BE-side masking)