# 2026-07-09 — Cascades of Tucson: Charity Sika -> Charity Menle caregiver rename (ALIS SSO)

## User
- **User:** Howard Enos (howard)
- **Machine:** Howard-Home
- **Role:** tech

---

## Session Summary

The request arrived as "Charity Menle needs an email setup for Cascades Tucson and be put in the caregivers group," with a follow-up clarifying the goal was to make ALIS SSO work for her. Before provisioning anything, the name was checked against the authoritative sources. "Menle" appeared nowhere — not in the ALIS roster (612 staff records pulled via the read-only API), not in AD, and not in any Cascades doc, roster, or CSV in the repo. The only Charity on record was Charity Sika, whose AD account `b.sika` already existed, was enabled, Business Premium licensed, and already a member of `SG-Caregivers`. The `b.` initial derives from her legal first name Bariffa, documented at `clients/cascades-tucson/scripts/create-caregiver-accounts.ps1:11`.

Rather than create an account, the identity conflict was raised with the user. He confirmed it was the same person, that she had legally changed her name, and that he had already updated the ALIS record himself. A re-read of ALIS staffId 309045 confirmed it: `Charity Menle`, `primaryEmail = c.menle@cascadestucson.com` (it had been `Bariffa Sika` with a null email earlier in the same session). Since ALIS SSO joins on **ALIS `Email` == Entra UPN**, and AD still carried `b.sika@cascadestucson.com`, the mismatch was the actual reason SSO would not resolve. The correct fix was a rename of the existing object, not a new account — a duplicate would have consumed a second Business Premium seat and left two AD objects competing for one ALIS staff record, the same failure that produced the `t.lassey-assiakoley` duplicate on the 7/1 reconcile.

A read-only pass on `b.sika` showed a clean object: empty `mail`, empty `proxyAddresses`, `PasswordExpired = False`, `PSO-Caregivers` applying, and `SG-Caregivers` as the only group. No collision existed on `c.menle` or `c.menle@cascadestucson.com`. The plan was previewed to the user (including the fact that her Windows/M365 login username would change while her password would not), and he approved.

The rename ran on CS-SERVER as a single PowerShell script via GuruRMM (`cmd:518f678e`, exit 0): `Set-ADUser` for `Surname`/`DisplayName`/`UserPrincipalName`/`EmailAddress` plus an explicit `proxyAddresses` add, then `Rename-ADObject` for the CN, then `Set-ADUser -SamAccountName`. `Start-ADSyncSyncCycle -PolicyType Delta` was invoked in the same script (the ADSync module is present on CS-SERVER, confirming Entra Connect runs there). The Entra export is asynchronous — the first Graph read still returned the old UPN, and the object only reflected the rename on a subsequent poll roughly 25 seconds later.

Post-change verification via the `remediation-tool` investigator tier confirmed the cloud object: `displayName = Charity Menle`, `userPrincipalName`/`mail` = `c.menle@cascadestucson.com`, `onPremisesSamAccountName = c.menle`, `accountEnabled = true`, `usageLocation = US`, license `SPB` intact, and `SG-Caregivers` (`8b8d9222`) membership unchanged. `proxyAddresses` carried `SMTP:c.menle@` (primary), `smtp:b.sika@` (alias), and the tenant `smtp:b.sika@NETORGFT4257522.onmicrosoft.com` routing alias that Entra Connect preserved on its own. The 6/29 open item ("Confirm Charity Sika (CSV) == Bariffa Sika (ALIS 309045)") was resolved and closed in the wiki.

---

## Key Decisions

- **Renamed the existing AD object instead of creating a new account**, against the literal wording of the request. A second account would duplicate the identity, consume a second Business Premium seat (SPB pool had only 4 free as of 7/1), and leave two AD objects competing for one ALIS staff record — the `t.lassey-assiakoley` failure mode. The user's own clarification ("just edit the sika bariffa account to match the new name") confirmed this reading.
- **Stopped and asked before writing** rather than provisioning on a name that matched nothing in ALIS, AD, or any repo doc. The discrepancy between "Menle" and the only on-record Charity (Sika) was too large to resolve by inference.
- **Set `proxyAddresses` explicitly** (`SMTP:c.menle@` primary + `smtp:b.sika@` alias) rather than relying on the UPN change to move the mailbox. These caregiver objects have an empty `proxyAddresses`, so Exchange Online derived primary SMTP from the UPN at provisioning; renaming the UPN alone is not a reliable way to move primary SMTP, and without the old address as an alias, inbound mail to `b.sika@` would bounce.
- **Changed `sAMAccountName` to `c.menle`** rather than leaving `b.sika`. The Cascades design is Windows login = email = M365/ALIS identity (one credential everywhere); leaving the old sAMAccountName would have defeated it.
- **Did not touch group, license, or password.** All three ride the unchanged object — `SG-Caregivers` membership, Business Premium, and `PSO-Caregivers` (never-expire) survive a rename. Re-adding any of them would have been a no-op at best.
- **Left ALIS alone.** The user explicitly took that side. Her ALIS record already reads `Charity Menle` / `c.menle@`, so no `--format update` .xls import was needed.

---

## Problems Encountered

- **`--json` is a global flag on the `alis` CLI, not a subcommand flag.** `alis.py staff --json` errored with `unrecognized arguments: --json`; the correct form is `alis.py --json staff`. Resolved by moving the flag before the subcommand.
- **Used `$UID` as a shell variable in a Bash tool script.** `UID` is readonly in bash, so the assignment failed (`readonly variable`) and the downstream Graph `licenseDetails` / `memberOf` calls silently ran against an empty user id, returning nothing. Resolved by renaming the variable to `OBJ`. Logged to `errorlog.md` via `log-skill-error.sh --friction`.
- **First Graph read after the delta sync still returned the old UPN**, which reads as a failed sync. It is not — `Start-ADSyncSyncCycle` returned `Success` and the Entra export is asynchronous. Resolved by polling the object by its stable objectId (`0dd5cb5d-…`) until the UPN flipped, which took roughly 25 seconds. Note the lookup had to be done by objectId or old UPN, since `GET /users/c.menle@…` 404s until the sync lands.

---

## Configuration Changes

**Live AD / Entra (CS-SERVER, `cascades.local`) — user object `cfa2d909-4cf2-46a5-8a1c-120602e2a2e2`:**

| Attribute | Before | After |
|---|---|---|
| `sAMAccountName` | `b.sika` | `c.menle` |
| `userPrincipalName` | `b.sika@cascadestucson.com` | `c.menle@cascadestucson.com` |
| `CN` / `Name` | `Charity Sika` | `Charity Menle` |
| `DisplayName` | (empty) | `Charity Menle` |
| `Surname` | `Sika` | `Menle` |
| `mail` | (empty) | `c.menle@cascadestucson.com` |
| `proxyAddresses` | (empty) | `SMTP:c.menle@cascadestucson.com`, `smtp:b.sika@cascadestucson.com` |

Unchanged: `GivenName` (`Charity`), `Enabled` (true), password, `SG-Caregivers` membership, Business Premium (`SPB`) license, `PSO-Caregivers` resultant policy, OU (`OU=Caregivers,OU=Departments,DC=cascades,DC=local`).

**Repo files modified:**
- `wiki/clients/cascades-tucson.md` — resolved the 6/29 "Confirm Charity Sika == Bariffa Sika" open item; added new subsection **"Caregiver name changes -- rename, never re-create"** documenting the procedure, the `proxyAddresses` gotcha, the async-sync gotcha, and the vault-key gotcha.
- `clients/cascades-tucson/docs/cloud/caretaker-phones-only-list.md` — roster row `Charity Sika | b.sika` -> `Charity Menle | c.menle`.
- `errorlog.md` — one `--friction` entry (bash `$UID` readonly).

---

## Credentials & Secrets

- **No credential was created, rotated, or changed.** Her password is unchanged by the rename.
- **Vault key gotcha:** Charity Menle's temp password remains filed under the OLD sAMAccountName key — `b.sika` in `clients/cascades-tucson/caregiver-temp-passwords-2026-06-30.sops.yaml`. Retrieve with `vault get` (NOT `get-field` — the keys contain dots). She now signs in as `c.menle` with that same password. The vault entry was deliberately not re-keyed.
- Tokens used this session: GuruRMM JWT via `.claude/scripts/rmm-auth.sh` (vault `infrastructure/gururmm-server.sops.yaml`); ALIS JWT via `clients/cascades-tucson/alis-api-howard-user.sops.yaml`; Graph token via `remediation-tool` `get-token.sh cascadestucson.com investigator`.

---

## Infrastructure & Servers

- **CS-SERVER** — `192.168.2.254` (SMB clients use `192.168.2.248`). DC / DNS / file server / Hyper-V host. GuruRMM agent `c39f1de7-d5b6-45ae-b132-e06977ab1713` (resolved live via `rmm-search.sh`, never hardcoded). **Confirmed this session: the `ADSync` module is present on CS-SERVER — Entra Connect runs here**, so `Start-ADSyncSyncCycle -PolicyType Delta` can be dispatched directly to this agent.
- **Tenant:** `cascadestucson.com`, routing domain `NETORGFT4257522.onmicrosoft.com`.
- **Entra objects:** user `0dd5cb5d-6143-4151-b4a7-6e37b3d071b0` (cloud), AD GUID `cfa2d909-4cf2-46a5-8a1c-120602e2a2e2`; group `SG-Caregivers` = `8b8d9222-5d71-419a-936d-56d895c6c332`.
- **ALIS:** communityId 622, staffId **309045** — now `Charity Menle`, `primaryEmail = c.menle@cascadestucson.com`, status Hired, jobRole `Certified Caregiver`, securityRoles `[Caregiver (Cascades)]`.

---

## Commands & Outputs

Resolve the agent (never hardcode the UUID):
```bash
bash .claude/scripts/rmm-search.sh cs-server -c cascades --json
# -> CS-SERVER  c39f1de7-d5b6-45ae-b132-e06977ab1713  online
```

Read the ALIS roster (note `--json` is a GLOBAL flag, before the subcommand):
```bash
bash .claude/scripts/py.sh .claude/skills/alis/scripts/alis.py --json staff --limit 1000
```

The rename itself (dispatched to CS-SERVER as `powershell`, `cmd:518f678e`, exit 0):
```powershell
$u = Get-ADUser b.sika -Properties proxyAddresses
$g = $u.ObjectGUID
Set-ADUser -Identity $g -Surname "Menle" -DisplayName "Charity Menle" `
  -UserPrincipalName "c.menle@cascadestucson.com" -EmailAddress "c.menle@cascadestucson.com" `
  -Add @{proxyAddresses=@("SMTP:c.menle@cascadestucson.com","smtp:b.sika@cascadestucson.com")}
Rename-ADObject -Identity (Get-ADUser -Identity $g).DistinguishedName -NewName "Charity Menle"
Set-ADUser -Identity $g -SamAccountName "c.menle"
Import-Module ADSync; Start-ADSyncSyncCycle -PolicyType Delta   # -> Result: Success
```

Post-sync Entra verification (poll by objectId — `GET /users/c.menle@…` 404s until the export lands):
```
displayName: Charity Menle | userPrincipalName: c.menle@cascadestucson.com
mail: c.menle@cascadestucson.com | onPremisesSamAccountName: c.menle
accountEnabled: true | usageLocation: US | license: SPB
proxyAddresses: smtp:b.sika@cascadestucson.com, SMTP:c.menle@cascadestucson.com,
                smtp:b.sika@NETORGFT4257522.onmicrosoft.com
memberOf: SG-Caregivers  8b8d9222-5d71-419a-936d-56d895c6c332
```

Error encountered and its fix:
```
/usr/bin/bash: line 15: UID: readonly variable     # $UID is reserved in bash -> use OBJ
alis: error: unrecognized arguments: --json        # --json is a global flag: alis.py --json staff
```

---

## Pending / Incomplete Tasks

- **Howard (ALIS side, self-assigned):** disable ALIS-native 2FA for Charity Menle so "Sign in with Microsoft" completes silently on the shared Samsung phone. The Email=UPN join key is now satisfied on both sides.
- **Tell Charity her login username changed** to `c.menle` — her password did NOT change and is still vaulted under the `b.sika` key in `caregiver-temp-passwords-2026-06-30.sops.yaml`.
- **Not verified end-to-end:** actual phone SSO sign-in as `c.menle`. Everything upstream of it (UPN, license, group, PSO, ALIS email) is confirmed, but no sign-in was observed this session.
- Carried over, untouched this session: **Juan Andrade (`j.andrade`) offboards 2026-07-11** (disable + remove from `SG-Caregivers` + reclaim SPB); ALIS Email=UPN backfill for the remaining caregivers; ALIS records for the 3 new hires (Munezero, Cota, Robinson); Vallejo's ALIS Email=UPN; ALIS app timeout 20 -> 15 min; reboot NURSESTATION to activate the lockdown GPO.

---

## Reference Information

- GuruRMM command id: `518f678e-7f9f-42f9-b8e5-f0317a84ba36` (the rename, exit 0). Earlier read-only probes: `eb5855c9-…` (name search), plus one attribute read.
- `#dev-alerts` post: message_id `1524831396915314729`.
- Syncro customer ID **20149445**. No ticket was opened for this change.
- Prior art / why rename-not-recreate: `clients/cascades-tucson/reports/2026-07-01-caretaker-roster-update.md` (the `t.lassey-assiakoley` duplicate), and `clients/cascades-tucson/scripts/create-caregiver-accounts.ps1:11` (`b.sika -- Charity Sika (legal first name Bariffa drives the initial)`).
- Forced-change / `50126` phone-login rule and `PSO-Caregivers` rationale: `wiki/clients/cascades-tucson.md`, sections "Caregiver phone login -- forced-change-at-next-logon gotcha" and "Caregiver password expiry".
- New wiki section written this session: "Caregiver name changes -- rename, never re-create (Charity Menle, 2026-07-09)".

---

## Update: 19:45 UTC -- Android shared-phone enrollment (new phone) + token replace

(Timestamps in UTC. `now-phoenix.sh` returned `20:23 PT` against a real UTC time of `19:43` -- not a valid UTC-7 offset, so local time was not trusted for this entry. Same class of bug as the `GURU-BEAST-ROG` TZ friction entry in `errorlog.md` from the same day.)

### What happened

Howard needed to enroll additional Samsung shared caregiver phones. The vaulted Intune Android enrollment token was **stale** (`MVDVVDMPSHYJAGDAJOCN`, old profile `CSC - Android Shared Phones`, expired 2026-06-22). The live profile turned out to be `CSC - Android Shared Phones (Entra SDM)` (`9a0fcc6d-0a88-466e-aa53-44401bb74fca`), whose QR was pulled live from Graph and vaulted as `clients/cascades-tucson/intune-android-enrollment-token.sops.yaml`.

That token (`KJCFJUWKRCOGATEHBTGYJZXM`) was then **rejected by Google at redemption** -- the phone displayed "checking code" then an error telling the user to contact IT -- even though Graph reported it valid through 2027-05-08 and the Managed Google Play binding was `boundAndValidated` with a successful app sync that morning. Howard fixed it in the Intune portal with **Replace Token** (not Revoke, which would leave the profile with no usable token). The replacement token carries an expiry of **2091-07-10** (~65 years) and enrolled a phone immediately.

Enrollment then succeeded: `CSC-R9TX70L693H` (serial `R9TX70L693H`), enrolled 18:33:52Z, `androidEnterpriseDedicatedDevice` / `googleCloudDevicePolicyController`, company-owned, encrypted, one Intune record and one Entra object (no duplicates). It joined the dynamic group `Cascades - Shared Phones` within ~3 minutes and both config profiles reported applied by 18:41.

The phone never became usable. Apps (Managed Home Screen, Alis) installed and uninstalled repeatedly -- six-plus cycles observed by Howard on the handset. Intune-side configuration was exhaustively verified as correct and was **not** the cause. The device stopped checking in at **18:51:26Z** and never resumed across a 52-minute poll. **Howard swapped the handset out; he reports this phone had known prior issues.** Root cause was never established from the tenant side, and Graph exposes no app-install state for these devices.

### What was verified correct (so it can be ruled out next time)

- `kioskModeApps` (9) and `kioskModeWallpaperUrl` are set on `CSC - Android Shared Phones Restrictions` (`070a76c2-a8c3-4f7f-9ba7-1f4ac5084184`), and `kioskModeUseManagedHomeScreenApp: multiAppMode`.
- All 10 Android apps are assigned `required` to the shared-phone group. **No `uninstall` intent anywhere; no duplicate packageIds.**
- `playStoreMode: notConfigured`; `proxySettings: none` on the CSCNet Wi-Fi profile.
- Group membership stable; `enrollmentProfileName` present on the Entra device object.
- Eleven identical phones (same models) run this exact config and check in daily.

### Two Graph fields that are NOT evidence (both burned me this session)

- **`freeStorageSpaceInBytes` / `totalStorageSpaceInBytes` are not collected for Android Enterprise dedicated devices.** Every one of the 26 phones reports `free = 0` and an implausible `total` (4.54 / 5.38 GB). I read `0` as "out of storage" and told Howard the phone was full and was the wrong model. **Both claims were false** -- he was looking at 15 GB used of 64 GB, and `SM-S146VL` is 9 of the 26 phones including working ones. Never treat a zero here as a measurement.
- **`detectedApps` is empty on ALL these devices**, including phones that sync daily. It is not an app-inventory source for COSU. Do not use it to conclude an app did or did not install.

The only trustworthy device-side signal available from Graph is **`lastSyncDateTime`** plus `deviceConfigurationStates`.

### Fleet observation (not acted on, Howard's answer recorded)

Of 26 Android device records, 15 last synced within a day of enrollment (May 11-18) and never again; 11 sync daily. Howard confirmed: **14 of the phones are simply powered off.** Not a fault. Two records (`CSC-R92W60LRA8Z`, `CSC-R9TW20DGYKF`) are duplicate objects from re-enrollment; 22 unique physical phones + the new one. `samsungSM-F731U` in the Android list is John Trozzi's personal Galaxy Z Flip 5, `trustType: Workplace` BYOD -- correctly outside the profile and group, not a shared phone.

### Configuration changes

- **Intune (via portal, by Howard):** enrollment token on profile `9a0fcc6d` replaced. Nothing else changed. Profile name, dynamic group rule, and the enrolled phones were deliberately left untouched.
- **Vault:** `clients/cascades-tucson/intune-android-enrollment-token.sops.yaml` created, then updated with the post-Replace token + `token_expires: 2091-07-10` + a `token_replaced` note. Verified encrypted (8 `ENC[]` fields; token absent from plaintext; all 37 Cascades entries scanned clean).
- **No brightness change was applied.** `show_brightness_slider` / `show_adaptive_brightness_toggle` exist in the Managed Home Screen schema and both default `False`, which is why caregivers cannot adjust brightness. Applying them requires editing the group-targeted app config `CSC - MHS layout` (`27683709-7b78-4b52-9c53-bb4401955bbf`) -- **Intune has no per-device app config**, and a second app config for the same app on one device is a conflict. Left unapplied at Howard's direction.

### Pending

- **Brightness**: add `show_brightness_slider=true` (+ optionally `show_adaptive_brightness_toggle`, `show_volume_setting`) to the existing `payloadJson` on app config `27683709`, keeping `screen_orientation` / `set_grid_size` / `lock_home_screen`. Snapshot `payloadJson` first for rollback. Fleet-wide by necessity.
- **Bad handset `CSC-R9TX70L693H`** swapped out. Its stale Intune record + Entra object should be cleaned up so it doesn't join the duplicate pile.
- Stray **`Microsoft Launcher`** (`com.microsoft.launcher`, consumer launcher) sits in the tenant app list unassigned. Harmless now; if ever assigned it would fight Managed Home Screen. Worth deleting.
- Enrollment of the replacement phone(s) not yet observed.
