Index: dust.rkt
==================================================================
--- dust.rkt
+++ dust.rkt
@@ -88,15 +88,23 @@
 (define (series-metas-title)
   (define series-pnode (metas-series-pagenode)) 
   (case series-pnode
     ['|| ""] ; no series specified
     [else (or (select-from-metas 'title series-pnode) "")]))
+
+(define article-ids (make-hash))
 
 ;; Generates a short ID for the current article
 (define (here-id [suffix #f])
+  (define maybe-hash (hash-ref article-ids (here-output-path) #f))
   (define here-hash
-    (substring (bytes->hex-string (sha1-bytes (path->bytes (here-output-path)))) 0 8))
+    (cond
+      [(not maybe-hash)
+       (let ([h (substring (bytes->hex-string (sha1-bytes (path->bytes (here-output-path)))) 0 8)])
+         (hash-set! article-ids (here-output-path) h)
+         h)]
+      [else maybe-hash]))
   (cond [(list? suffix) (apply string-append here-hash suffix)]
         [(string? suffix) (string-append here-hash suffix)]
         [else here-hash]))
 
 ;; “Touches” the last-modified date on the current article’s series, if there is one
@@ -235,12 +243,11 @@
 (define (disposition-values str)
   (cond [(string=? "" str) (values "" "")]
         [else (let ([splut (string-split str)])
                 (values (car splut) (string-join (cdr splut))))]))
 
-;; The format of a note’s ID is “HTML-driven” (used as an anchor link) but is included
-;; here since it also serves as a primary key in the DB.
+;; The format of a note’s ID is “HTML-driven” (used as an anchor link)
 (define (build-note-id txpr)
   (string-append (maybe-attr 'date (get-attrs txpr))
                  "_"
                  (uri-encode (maybe-attr 'author (get-attrs txpr) default-authorname))))