Skip to content

fix(persona): never write a value the editor never held, and let a decision reach the copy - #197

Merged
stormer78 merged 1 commit into
mainfrom
fix/editor-never-blanks-a-value
Sep 8, 2026
Merged

fix(persona): never write a value the editor never held, and let a decision reach the copy#197
stormer78 merged 1 commit into
mainfrom
fix/editor-never-blanks-a-value

Conversation

@stormer78

Copy link
Copy Markdown
Contributor

Two bugs reported minutes after #195, both from one gap: neither the pool's value nor the pool's decisions travel with the copy.

1. The editor was blanking values — data loss

Since #194 the pane lists without includeSensitive, so the plaintext of a sensitive attribute is deliberately not in the page. That means an existing one reaches the editor as value: undefinedrawValue returns ""the field opens blank → and persona/attribute/put is a replace.

So opening a withheld attribute to change its label — or the visibility controls #195 had just put in that same form — wrote an empty string over a value the console had never seen. Silently, and with no way back: there is no attribute/get, no version history, nothing to restore from.

Two mechanisms now, deliberately separate:

  • The fetch. On open, an attribute that arrived without its value is asked for — the same one-attribute request Show makes, narrowed by type and matched by id.
  • The refusal. Independently of that, a save is refused while the value is neither loaded nor typed. It sends no put at all: "wrote something wrong" and "wrote nothing" are very different outcomes for a value with no way back. The message says which case it is and offers the deliberate route — type the value in yourself.

Every control that edits the field now goes through one writer. One that set raw directly would leave the guard reading a typed value as one nobody typed — which the test caught while this was being written.

2. A decision did not reach the copy

What someone would receive renders claims read from a face or a binding. A claim is a copy and carries no sensitivity: the decision lives on the pool attribute it was materialised from, above the boundary those panels sit below. So a value the holder had just marked show it was masked in one panel and shown in the clear on the card one scroll away — same person, same value, two answers.

decidedSensitivity matches a resolved claim's attributeId back to the pool. An inline claim has no attributeId and no pool ancestor to have decided anything, so the registry answers for it — the right answer for that case rather than a gap in this one.

Rebased onto #196, not merged with it

#196 moved the claim-type table to the agent's served one and threads a registry through these same components. It fixes neither of these — nothing in it touches the put path, and the claims panel still passed no sensitivity — but it rewrote the files. This branch was rebased onto it and the conflicts resolved by keeping both props at every call site, rather than letting a textual merge pick one.

Checks

  • 7 new tests. Extension 359 pass, core 562 pass.
  • tsc -b clean; npm run build clean, manager.js a single chunk.
  • Pinned: opening a withheld attribute fetches its value and the save carries it; a refused fetch blocks the save and writes nothing; typing a value is allowed through; a claim is drawn under the decision made about the attribute behind it; and an inline claim still falls to the registry.

Note for whoever hit this

Values already blanked this way are gone — they have to be re-entered. Worth knowing while reviewing: the window was #194 → this, and it applied to any attribute the registry resolves as sensitivity: high, which includes every unregistered type.

…cision reach the copy

Two bugs a holder hit within minutes of #195, both from the same gap: the pool's
value and the pool's decisions do not travel with the copy.

**The editor was blanking values.** Since #194 the pane lists without
`includeSensitive` — the plaintext of a sensitive attribute is deliberately not
in the page — so an existing one reaches the editor with `value: undefined`.
`rawValue(undefined)` is `""`, the field opens blank, and `attribute/put`
REPLACES the record. Opening a withheld attribute to change its label, or the
visibility controls #195 had just put in that same form, wrote an empty string
over a value the console had never seen. There is no `attribute/get`, no version
history and nothing to restore from, so it was silent and final.

The editor now asks for the value on open — the same one-attribute request
*Show* makes — and, separately, refuses to save while the value is neither
loaded nor typed. Two mechanisms deliberately: the fetch is the convenience, the
refusal is the property, and the refusal sends no put at all rather than writing
something wrong. Typing a value yourself is the deliberate overwrite it allows,
which is also why every control that edits the field goes through one writer:
one that set `raw` directly would leave the guard reading a typed value as one
nobody typed.

**A decision did not reach the copy.** "What someone would receive" renders
claims read from a face or a binding, and a claim is a copy that carries no
`sensitivity` — the decision lives on the pool attribute it was materialised
from. So a value the holder had just marked *show it* was masked one panel away
from the card showing it in the clear: same person, same value, two answers.
`decidedSensitivity` matches a resolved claim's `attributeId` back to the pool.
An inline claim has no `attributeId` and no pool ancestor, so the registry
answers for it — the right answer for that case rather than a gap in this one.

Rebased onto #196 rather than merged with it: that PR moved the claim-type table
to the agent's served one and threads a `registry` through these same
components. Both props are additive and both are now passed at every call site.

7 new tests (359 extension, 562 core), `tsc -b` clean, `npm run build` clean.

Signed-off-by: Glenn Gore <glenn.g@affinidi.com>
@stormer78
stormer78 merged commit 33a9821 into main Sep 8, 2026
3 checks passed
@stormer78
stormer78 deleted the fix/editor-never-blanks-a-value branch September 8, 2026 11:25
@affinidi-appsecurity-bot

Copy link
Copy Markdown

🛡️ AI Agentic Security Code Review

🔎 A manual security review is recommended before merging. Please contact the Security team for specifics and remediation guidance.

ℹ️ Detailed findings are not published on public repositories; the Security team holds the complete report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants