Skip to content

Fixes infraction display duration off-by-one discrepancy#2234

Merged
mbaruh merged 47 commits into
mainfrom
infraction-durations
Aug 19, 2022
Merged

Fixes infraction display duration off-by-one discrepancy#2234
mbaruh merged 47 commits into
mainfrom
infraction-durations

Conversation

@ionite34
Copy link
Copy Markdown
Contributor

@ionite34 ionite34 commented Jul 28, 2022

Closes #2217, Closes #2130

Overview

Fixes the issue of displayed infractions being off from the originally requested duration.

Test Example

  • Infraction messages now display the correct intended applied time and are no longer off by one or more units.

Durations

  • DMs and most areas where durations are used have also been updated

DM1

Related Fixes and improvements

1. Ban command help message

  • The ban command help message did not accurately reflect its ability to accept expiry ISO times

Ban1

  • This has been improved as such

Ban2

2. Indicator for updated infraction durations

  • Pursuant to discussion an indicator for updated infraction durations has also been added:

Updated1

Updated2

3. DM now displays whether the infraction duration has been edited

Infraction_DM

Design and API Notes

  • Commands for durations have been modified from Expiry to use a new alias DurationOrExpiry
Expiry = t.Union[Duration, ISODateTime]
->
DurationOrExpiry = t.Union[DurationDelta, ISODateTime]

The added type, in converters.py, is a union between the types dateutils.timedelta and datetime.datetime respectively.

  • The post_infractions method of _utils.py has an updated parameter name and type. Associated usages have also been updated.
  • The updated name is to reflect that this new parameter may now accept either a timedelta or datetime marking the absolute expiry date. Originally the expires_at parameter only accepted a datetime marking the expiry date.
async def post_infraction(
		...
-     expires_at: datetime = None,
+     duration_or_expiry: t.Optional[DurationOrExpiry] = None,
		...
) -> t.Optional[dict]:

ionite34 added 11 commits July 28, 2022 03:42
- Refactored tests for new time duration arguments
- Changed `duration` parameter names to `duration_or_expiry` to more accurately reflect options for help
- Updated docstring to be more explicit on parameter fields
- Corrected datetime patching
@ionite34 ionite34 marked this pull request as ready for review July 28, 2022 23:06
- Added new usage of `last_applied`  time for duration calculation in `apply_infraction`
@ionite34 ionite34 added a: frontend Related to output and formatting a: API Related to or causes API changes p: 3 - low Low Priority t: enhancement Changes or improvements to existing features s: needs review Author is waiting for someone to review and approve review: do not merge The PR can be reviewed but cannot be merged now and removed review: do not merge The PR can be reviewed but cannot be merged now labels Jul 31, 2022
@ionite34 ionite34 changed the title Implement new infraction duration calculations Fixes infraction display duration off-by-one discrepancy Aug 1, 2022
Comment thread bot/exts/moderation/infraction/_scheduler.py Outdated
Comment thread bot/exts/moderation/infraction/_utils.py Outdated
Comment thread bot/exts/moderation/infraction/_utils.py Outdated
Comment thread bot/utils/time.py Outdated
Comment on lines +335 to +343
def round_datetime(dt: datetime.datetime) -> datetime.datetime:
"""
Round a datetime object to the nearest second.

Resulting datetime objects will have microsecond values of 0, useful for delta comparisons.
"""
if dt.microsecond >= 500000:
dt += datetime.timedelta(seconds=1)
return dt.replace(microsecond=0)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an example case where the representation is improved with this function? Most deltas are in the hours or days so I'm not sure what called for this addition.

Copy link
Copy Markdown
Contributor Author

@ionite34 ionite34 Aug 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that was the rationale for this change, since the minimum accuracy of our humanize_delta is 1 second, the rounding will trim off microseconds via rounding.

The original issue was that the humanize_delta call matches time units until the last unit is exhausted, which, in the case of infractions, due to code and network latency, the delta between inserted_at (calculated at entry insertion server side) and expires_at (calculated at original command invocation) will at least be some microseconds off. In some extreme cases, this will be up to 10s or more.

In most cases, the entries are within 1 second in delta, but this is still enough to cause the 59 minutes 59 seconds display for the original 1h infraction, for example. This rounding will enable most legacy entries without a historical last_applied entry (currently defaults to their original inserted_at value at the site side) to most likely still display a whole unit of time.

In essence, this new function and its usage in humanize_delta will cause a previous 59 minutes, 59.9 seconds duration to round as 1 hour which should be desired behavior considering the minimum precision is 1 second.

This generic application, whilst not strictly necessary for infractions given the new last_applied field, will make future and existing usages of humanize_delta less likely to cause similar errors for local datetime deltas which may be off by some milliseconds due to code latency.

Comment on lines 97 to 107
payload = {
"actor": ctx.author.id, # Don't use ctx.message.author; antispam only patches ctx.author.
"hidden": hidden,
"reason": reason,
"type": infr_type,
"user": user.id,
"active": active,
"dm_sent": dm_sent
"dm_sent": dm_sent,
"last_applied": current_time.isoformat(),
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to make sure I understand, you're supplying last_applied, but what sets inserted_at? I thought the goal was to make the two identical in the beginning. Is it done on the site's end?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, the site is setting inserted_at when the entry is inserted. The goal of the new attribute last_applied is to provide a datetime that is calculated on command run at the bot side, which should remove some of the server / network latency issues. In addition, the last_applied time is actually calculated together with the delta, meaning that the absolute delta of last_applied and expires_at is exactly equal to the infraction (for example 1 hour) down to the microsecond.

- Used arrow.utcnow to reduce complexity and import
- Changed `duration` parameter names to `duration_or_expiry` to more accurately reflect options for help
- Updated docstring to be more explicit on parameter fields
- Corrected datetime patching
- Added new usage of `last_applied`  time for duration calculation in `apply_infraction`
- Used arrow.utcnow to reduce complexity and import
Given API updates, the fallback is not needed
- Used new method of dict subset comparison instead of datetime patching for better compat. with argument types
Corrected test case to use `datetime.utcnow()` to be consistent with target
- Added new infraction delta calculations to updated infractions.
- Updates of infraction durations now also update the `last_applied` field.
- `inserted_at` is now sent by the bot client to denote the original unmodified infraction application time
@ionite34 ionite34 force-pushed the infraction-durations branch from fb028d1 to 6a87a38 Compare August 16, 2022 20:38
Comment thread bot/exts/moderation/infraction/_utils.py Outdated
Copy link
Copy Markdown
Contributor

@wookie184 wookie184 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@ionite34
Copy link
Copy Markdown
Contributor Author

ionite34 commented Aug 19, 2022

DM and resend DM style has been modified in dcd946b pursuant to discussions.

New style:

  • Re-ordered expires dynamic timestamp to be after duration.
  • Removed optional remaining time in favor of detected (Edited) flag

img

Copy link
Copy Markdown
Contributor

@minalike minalike left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mina test, mina like. 👍🏻

Copy link
Copy Markdown
Member

@mbaruh mbaruh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, thanks!

@mbaruh mbaruh enabled auto-merge August 19, 2022 19:20
@mbaruh mbaruh merged commit dc9cb79 into main Aug 19, 2022
@mbaruh mbaruh deleted the infraction-durations branch August 19, 2022 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: API Related to or causes API changes a: frontend Related to output and formatting p: 3 - low Low Priority s: needs review Author is waiting for someone to review and approve t: enhancement Changes or improvements to existing features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Infraction display durations off-by-one Mute/tempbans, etc. durations are 1 second off in bot's messages and DMs

4 participants