Blocked on jfberry/PoracleNG#217.
Every user-geofence area mutation bypasses SetAreasAsync and writes humans.area and profiles.area directly through IUserAreaDualWriter. The reason: PoracleNG's HandleSetAreas intersects the submitted list against fences with userSelectable == true for non-admins, and PoracleWeb serves user-drawn geofences with userSelectable: false on purpose — to keep their names out of the bot's !area picker and out of DM text. So the names were silently stripped, the UI showed optimistic success, and a refresh revealed the geofence gone.
#217 adds an opt-in trusted flag to POST /v2/humans/{id}/areas that lifts the userSelectable filter only — unknown fence names are still rejected, so a typo can't become a stored area matching nothing. It also returns what was stored and what was rejected, so a partly-ignored request stops looking like a fully-applied one.
Delete
grep -rn "HACK: trusted-set-areas" --include="*.cs" lists every site. UserGeofenceService holds eleven of them; AreaController one; the rest are the interface and DI.
AreaController.UpdateAreas gets simpler in two ways: PreserveOwnedAreasInHumanAsync after SetAreasAsync becomes unnecessary, and the new rejected array means we can surface a genuinely partial save instead of guessing.
Does NOT cover the override path
UserOwnedOverrideAreaProxy stays, and gets more load-bearing, not less.
override_areas on a tracking write is validated against the same fence set, and #217's tracking.go:298 builds it with settableAreaNames(deps, human, admin, false) — trusted hardcoded false. There is no equivalent escape hatch on that path. Worse, #217 revives that check: validateOverrideFields gated on oc.permitted != nil, permitted came from AreaLogic, and main.go never set AreaLogic, so it was dead code on every tracking write. It now runs.
Raised on the #217 review; if it isn't taken there it needs its own upstream issue before this one can close completely.
Watch for
The dual writer is one atomic SaveChangesAsync spanning both tables. SetAreasAsync is one HTTP call. Sequencing several of them where there used to be one transaction is a new failure mode — a create that adds the area but leaves no user_geofences row, or the reverse. Work out the ordering deliberately rather than translating call-for-call.
RenameAreaInAllProfilesAsync is the subtle one (#408). On approval the old name is userSelectable: false and the promoted name isn't in PoracleNG's fence list yet, because the reload happens afterwards. trusted fixes the first half; the second half is an ordering problem that survives it.
Blocked on jfberry/PoracleNG#217.
Every user-geofence area mutation bypasses
SetAreasAsyncand writeshumans.areaandprofiles.areadirectly throughIUserAreaDualWriter. The reason: PoracleNG'sHandleSetAreasintersects the submitted list against fences withuserSelectable == truefor non-admins, and PoracleWeb serves user-drawn geofences withuserSelectable: falseon purpose — to keep their names out of the bot's!areapicker and out of DM text. So the names were silently stripped, the UI showed optimistic success, and a refresh revealed the geofence gone.#217 adds an opt-in
trustedflag toPOST /v2/humans/{id}/areasthat lifts theuserSelectablefilter only — unknown fence names are still rejected, so a typo can't become a stored area matching nothing. It also returns what was stored and what was rejected, so a partly-ignored request stops looking like a fully-applied one.Delete
grep -rn "HACK: trusted-set-areas" --include="*.cs"lists every site.UserGeofenceServiceholds eleven of them;AreaControllerone; the rest are the interface and DI.AreaController.UpdateAreasgets simpler in two ways:PreserveOwnedAreasInHumanAsyncafterSetAreasAsyncbecomes unnecessary, and the newrejectedarray means we can surface a genuinely partial save instead of guessing.Does NOT cover the override path
UserOwnedOverrideAreaProxystays, and gets more load-bearing, not less.override_areason a tracking write is validated against the same fence set, and #217'stracking.go:298builds it withsettableAreaNames(deps, human, admin, false)—trustedhardcoded false. There is no equivalent escape hatch on that path. Worse, #217 revives that check:validateOverrideFieldsgated onoc.permitted != nil,permittedcame fromAreaLogic, andmain.gonever setAreaLogic, so it was dead code on every tracking write. It now runs.Raised on the #217 review; if it isn't taken there it needs its own upstream issue before this one can close completely.
Watch for
The dual writer is one atomic
SaveChangesAsyncspanning both tables.SetAreasAsyncis one HTTP call. Sequencing several of them where there used to be one transaction is a new failure mode — a create that adds the area but leaves nouser_geofencesrow, or the reverse. Work out the ordering deliberately rather than translating call-for-call.RenameAreaInAllProfilesAsyncis the subtle one (#408). On approval the old name isuserSelectable: falseand the promoted name isn't in PoracleNG's fence list yet, because the reload happens afterwards.trustedfixes the first half; the second half is an ordering problem that survives it.