KeyValueTable.dump() builds a dict, so two rows with the same key silently lost one value on save. Duplicates are now blocked at the only writer:
Add dialog: OK disabled + inline "'KEY' already exists" warning while the typed key duplicates an existing row.
Inline edits: a column-0 edit that collides is reverted to its previous text (tracked via UserRole) with a tooltip "Duplicate key 'X' — reverted."
dump() unchanged.
Verified with an offscreen widget smoke test: renaming a key into a collision reverts with no data loss; legitimate renames pass. Tests + ruff clean. (Implemented by a delegated agent; reviewed.)
Closes #38.
`KeyValueTable.dump()` builds a dict, so two rows with the same key silently lost one value on save. Duplicates are now blocked at the only writer:
- **Add dialog**: OK disabled + inline "'KEY' already exists" warning while the typed key duplicates an existing row.
- **Inline edits**: a column-0 edit that collides is reverted to its previous text (tracked via UserRole) with a tooltip "Duplicate key 'X' — reverted."
- `dump()` unchanged.
Verified with an offscreen widget smoke test: renaming a key into a collision reverts with no data loss; legitimate renames pass. Tests + ruff clean. (Implemented by a delegated agent; reviewed.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #38.
KeyValueTable.dump()builds a dict, so two rows with the same key silently lost one value on save. Duplicates are now blocked at the only writer:dump()unchanged.Verified with an offscreen widget smoke test: renaming a key into a collision reverts with no data loss; legitimate renames pass. Tests + ruff clean. (Implemented by a delegated agent; reviewed.)
🤖 Generated with Claude Code