Cleanup: infer a missing sex from a known-sex spouse (preview → approve)

Unset sex renders blue (male-colored), which is misleading next to a confirmed
male partner. Add a Cleanup action that proposes the opposite sex for an unset
partner of someone whose sex is set (couples are opposite-sex in practice — a
confirmed-male husband ⇒ a female wife). People whose known partners disagree
are skipped as ambiguous.

It's a preview the user reviews and approves in the Cleanup tool (reusing the
existing gender apply path + audit) — not an autonomous write. Backend:
guess_gender_by_spouse + GET /cleanup/gender/from-spouse. Frontend: an "Infer
from spouse" button feeding the existing proposal list. Test covers
propose-opposite, skip-no-partner, skip-already-set, apply, and re-preview.

Full suite 73 passed; frontend build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Paul <justin@jpaul.me>
This commit is contained in:
2026-06-09 10:59:08 -04:00
parent 768c68cbe0
commit 05d2773e25
6 changed files with 211 additions and 2 deletions
+16 -2
View File
@@ -109,6 +109,15 @@ export default function CleanupPage() {
setGenSel(new Set((data ?? []).map((g) => g.person_id)));
}
async function guessGenderFromSpouse() {
setGenMsg(null);
const { data } = await api.GET("/api/v1/trees/{tree_id}/cleanup/gender/from-spouse", {
params: { path: { tree_id: treeId } },
});
setGender(data ?? []);
setGenSel(new Set((data ?? []).map((g) => g.person_id)));
}
async function applyGender() {
const updates = (gender ?? [])
.filter((g) => genSel.has(g.person_id))
@@ -246,10 +255,15 @@ export default function CleanupPage() {
<Button variant="outline" onClick={guessGender}>
Guess from first name
</Button>
<Button variant="outline" onClick={guessGenderFromSpouse}>
Infer from spouse
</Button>
</div>
<p className="text-xs text-[var(--muted)]">
Guess from first name uses a built-in name dictionary for people with no sex set;
ambiguous names (Marion, Frances, ) are left for you to decide.
Guess from first name uses a built-in name dictionary for people with no sex set.
Infer from spouse sets the opposite sex for an unset partner of someone whose sex is
known (e.g. a confirmed-male husband a female wife) review before applying, since
it assumes opposite-sex couples.
</p>
{genMsg && <p className="text-sm text-bronze">{genMsg}</p>}
{gender && (