repos
/ orchard main

orchard

mirror

Every site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.

blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics

4.4 KB · 129 lines · Go Raw History
  1package main
  2
  3import (
  4	"fmt"
  5	"regexp"
  6	"strings"
  7	"time"
  8)
  9
 10// A passage describes the future as of the day it was written, and a model
 11// repeating it says a thing "is scheduled for April 2026" in September. Two
 12// rounds of telling it not to did not hold, which is the usual result of asking
 13// a 4B to compare dates in prose, so the check happens here instead.
 14//
 15// This warns rather than rewrites. The sentence is the model's and may be a
 16// fair report of what a stale page said, so the honest thing is to say which
 17// line is out of date rather than to quietly edit an answer whose whole claim
 18// is that it was checked.
 19
 20var (
 21	// The ways an answer says a thing has not happened yet.
 22	futureTense = regexp.MustCompile(`(?i)\b(is|are|was|were|remains?|stays?)\s+(scheduled|planned|slated|expected|due|set)\b|` +
 23		`\b(will|is going to|are going to)\s+\w+|` +
 24		`\b(is|are)\s+(targeting|upcoming|forthcoming)\b|` +
 25		`\b(targets?|targeted for|scheduled for|planned for|due in|expected in)\b`)
 26
 27	// Month and year, which is as precise as these sentences get.
 28	monthYear = regexp.MustCompile(`(?i)\b(january|february|march|april|may|june|july|august|september|october|november|december)\s+(\d{4})\b`)
 29
 30	// The other half of the same bug. A live tracker page saying a mission "is
 31	// currently underway" was right the day it was written, and a model
 32	// repeating it months later says the mission is still flying.
 33	presentTense = regexp.MustCompile(`(?i)\b(is|are)\s+(currently|now|presently)\b|` +
 34		`\b(is|are)\s+(underway|under way|ongoing|active|in progress|in flight|tracking)\b|` +
 35		`\bcurrently\s+(active|underway|executing|running|flying)\b`)
 36
 37	// "April 2, 2026" as well as a bare month and year, since a tracker page
 38	// dates things to the day.
 39	dayMonthYear = regexp.MustCompile(`(?i)\b(january|february|march|april|may|june|july|august|september|october|november|december)\s+\d{1,2},?\s+(\d{4})\b`)
 40
 41	// A bare quarter or year on its own is too coarse to call stale, since
 42	// "early 2028" said in 2026 is fine.
 43	sentenceSplit = regexp.MustCompile(`(?m)[^.!?\n]+[.!?]?`)
 44)
 45
 46// staleNow flags a sentence saying something is happening now while dating it
 47// to a month that has already finished.
 48func staleNow(text string, now time.Time) []string {
 49	var out []string
 50	seen := map[string]bool{}
 51	for _, raw := range sentenceSplit.FindAllString(text, -1) {
 52		s := strings.TrimSpace(raw)
 53		if s == "" || !presentTense.MatchString(s) {
 54			continue
 55		}
 56		for _, re := range []*regexp.Regexp{dayMonthYear, monthYear} {
 57			var hit bool
 58			for _, m := range re.FindAllStringSubmatch(s, -1) {
 59				when, ok := monthStart(m[1], m[len(m)-1])
 60				if !ok {
 61					continue
 62				}
 63				if !when.AddDate(0, 1, 0).Before(truncMonth(now)) {
 64					continue
 65				}
 66				key := m[1] + m[len(m)-1]
 67				if seen[key] {
 68					hit = true
 69					continue
 70				}
 71				seen[key] = true
 72				hit = true
 73				out = append(out, fmt.Sprintf(
 74					"one line says this is happening now but dates it to %s %s, so it is describing what a source said at the time rather than today",
 75					strings.ToUpper(m[1][:1])+strings.ToLower(m[1][1:]), m[len(m)-1]))
 76			}
 77			if hit {
 78				break
 79			}
 80		}
 81	}
 82	return out
 83}
 84
 85// staleFutures returns a warning for each sentence claiming something is still
 86// ahead on a month that has already finished.
 87func staleFutures(text string, now time.Time) []string {
 88	var out []string
 89	seen := map[string]bool{}
 90	for _, raw := range sentenceSplit.FindAllString(text, -1) {
 91		s := strings.TrimSpace(raw)
 92		if s == "" || !futureTense.MatchString(s) {
 93			continue
 94		}
 95		for _, m := range monthYear.FindAllStringSubmatch(s, -1) {
 96			when, ok := monthStart(m[1], m[2])
 97			if !ok {
 98				continue
 99			}
100			// The month has to be fully behind us. Something "scheduled for
101			// September" on the 5th of September is not wrong.
102			if !when.AddDate(0, 1, 0).Before(truncMonth(now)) {
103				continue
104			}
105			key := m[1] + m[2]
106			if seen[key] {
107				continue
108			}
109			seen[key] = true
110			out = append(out, fmt.Sprintf(
111				"one line calls %s %s still upcoming, and it has passed, so the sources are older than the event",
112				strings.ToUpper(m[1][:1])+strings.ToLower(m[1][1:]), m[2]))
113		}
114	}
115	return out
116}
117
118func monthStart(name, year string) (time.Time, bool) {
119	t, err := time.Parse("January 2006", strings.ToUpper(name[:1])+strings.ToLower(name[1:])+" "+year)
120	if err != nil {
121		return time.Time{}, false
122	}
123	return t, true
124}
125
126func truncMonth(t time.Time) time.Time {
127	return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
128}