flags: rigorously define expiration milestone

There are two competing definitions of expiration milestone:
a) The last milestone in which a flag is present
b) The first milestone in which a flag is not present

The docs in //docs/flag_expiry.md and the code in //tools/flags
implemented (b), but the block comment in flag-metadata.md described
(a). Since that block comment has been much more widely read and
relied upon than either of the other two sources, this change makes
(a) the behavior everywhere. This will hopefully reduce confusion in
client teams about where their flags have gone :)

Bug: 1072433
Change-Id: I0f8fcbde2509b1bed05b98ac847c98595c74836f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2155841
Reviewed-by: Alexei Svitkine <[email protected]>
Reviewed-by: Nico Weber <[email protected]>
Commit-Queue: Elly Fong-Jones <[email protected]>
Cr-Commit-Position: refs/heads/master@{#760681}
diff --git a/tools/flags/generate_unexpire_flags.py b/tools/flags/generate_unexpire_flags.py
index 65b60d0..95d2d82 100755
--- a/tools/flags/generate_unexpire_flags.py
+++ b/tools/flags/generate_unexpire_flags.py
@@ -159,9 +159,12 @@
     raise ValueError('Can\'t find or understand //chrome/VERSION')
 
   progname = sys.argv[0]
-  update_file_if_stale(sys.argv[1], gen_features_impl(progname, mstone))
-  update_file_if_stale(sys.argv[2], gen_features_header(progname, mstone))
-  update_file_if_stale(sys.argv[3], gen_flags_fragment(progname, mstone))
+
+  # Note the mstone - 1 here: the listed expiration mstone is the last mstone in
+  # which that flag is present, not the first mstone in which it is not present.
+  update_file_if_stale(sys.argv[1], gen_features_impl(progname, mstone - 1))
+  update_file_if_stale(sys.argv[2], gen_features_header(progname, mstone - 1))
+  update_file_if_stale(sys.argv[3], gen_flags_fragment(progname, mstone - 1))
 
 
 if __name__ == '__main__':