diff --git a/ChangeLog b/ChangeLog
index 9cd97f0710aadf172d30c65fdc96eb20d267cd1b..c87c2aaab11f0281abbfb8329b544b0f640f0fbc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,11 @@ Changes in version 0.1.2.3-alpha - 2006-10-??
     - If most authorities set a (newly defined) BadExit flag for a server,
       do not consider it as a general-purpose exit.  Only consider
       authorities that advertise themselves as listing bad exits.
+    - Start making it possible for servers to publish less often: never
+      discard a descriptor simply for being too old until either it is
+      recommended by no authorities, or until we get a better one for the
+      same router.  Make caches consider retaining old recommended
+      routers for even longer.
 
   o Minor features, controller:
     - Add a REASON field to CIRC events; for backward compatibility, this
diff --git a/doc/TODO b/doc/TODO
index 6d8b09ec330cb869751e0f7ee39f7d9c5932c47b..0f15446a5c3b09646f63a2ab792c4b1c174788ec 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -142,8 +142,8 @@ x   - Better estimates in the directory of whether servers have good uptime
 x     - spec
 d     - implement
 
-  - A more efficient dir protocol.
-N   - Later, servers will stop generating new descriptors simply
+  o Changes towards a more efficient dir protocol.
+    o Later, servers will stop generating new descriptors simply
       because 18 hours have passed: we must start tolerating this now.
 
   - Critical but minor bugs, backport candidates.
diff --git a/doc/dir-spec.txt b/doc/dir-spec.txt
index 92039ef25119a35f361468e23b5c72e05f19891c..949c2f91f46a494f040e9c29de0ee722635f63ba 100644
--- a/doc/dir-spec.txt
+++ b/doc/dir-spec.txt
@@ -628,7 +628,7 @@ $Id$
    from an authority, they should not need to go to the authority directly
    again.)
 
-5.2. Downloading router descriptors
+5.2. Downloading and storing router descriptors
 
    Clients try to have the best descriptor for each router.  A descriptor is
    "best" if:
@@ -665,6 +665,12 @@ $Id$
    No descriptors are downloaded until the client has downloaded more than
    half of the network-status documents.
 
+   Clients retain the most recent descriptor they have downloaded for each
+   router so long as it is not too old (currently, 48 hours), OR so long as
+   it is recommended by at least one networkstatus AND no "better"
+   descriptor has been downloaded.  [Versions of Tor before 0.1.2.3-alpha
+   would discard descriptors simply for being published too far in the past.]
+
 5.3. Managing downloads
 
    When a client has no live network-status documents, it downloads
diff --git a/src/or/or.h b/src/or/or.h
index d617a950860502e01bf663e55e4652340153224f..1ca35c46fb2eb79281a0be2d2d552f10d16ec1ce 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -188,8 +188,8 @@
 /** How old can a router get before we (as a server) will no longer
  * consider it live? In seconds. */
 #define ROUTER_MAX_AGE_TO_PUBLISH (60*60*20)
-/** How old do we let a saved descriptor get before removing it? */
-#define OLD_ROUTER_DESC_MAX_AGE (60*60*60)
+/** How old do we let a saved descriptor get before force-removing it? */
+#define OLD_ROUTER_DESC_MAX_AGE (60*60*24*5)
 /** How old do we let a networkstatus get before ignoring it? */
 #define NETWORKSTATUS_MAX_AGE (60*60*24)
 
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index 02e6f9650a85d23e9e39bc2c7b497ab5a8f0da0a..2f7e0e096efe17c9fc56782b6a3d4574f9506d5f 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1999,8 +1999,8 @@ routerlist_remove_old_cached_routers_with_id(time_t cutoff, int lo, int hi,
 }
 
 /** Deactivate any routers from the routerlist that are more than
- * ROUTER_MAX_AGE seconds old; remove old routers from the list of
- * cached routers if we have too many.
+ * ROUTER_MAX_AGE seconds old and not recommended by any networkstatuses;
+ * remove old routers from the list of cached routers if we have too many.
  */
 void
 routerlist_remove_old_routers(void)
@@ -2012,32 +2012,37 @@ routerlist_remove_old_routers(void)
   routerinfo_t *router;
   signed_descriptor_t *sd;
   digestmap_t *retain;
-  or_options_t *options = get_options();
   if (!routerlist || !networkstatus_list)
     return;
 
   retain = digestmap_new();
   cutoff = now - OLD_ROUTER_DESC_MAX_AGE;
-  if (options->DirPort) {
-    SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
-      {
-        SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
-          if (rs->published_on >= cutoff)
-            digestmap_set(retain, rs->descriptor_digest, (void*)1));
-      });
-  }
+  /* Build a list of all the descriptors that _anybody_ recommends. */
+  SMARTLIST_FOREACH(networkstatus_list, networkstatus_t *, ns,
+    {
+      SMARTLIST_FOREACH(ns->entries, routerstatus_t *, rs,
+        if (rs->published_on >= cutoff)
+          digestmap_set(retain, rs->descriptor_digest, (void*)1));
+    });
 
-  cutoff = now - ROUTER_MAX_AGE;
-  /* Remove too-old members of routerlist->routers. */
-  for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
-    router = smartlist_get(routerlist->routers, i);
-    if (router->cache_info.published_on <= cutoff &&
-        !digestmap_get(retain, router->cache_info.signed_descriptor_digest)) {
-      /* Too old.  Remove it. */
-      log_info(LD_DIR,
-               "Forgetting obsolete (too old) routerinfo for router '%s'",
-               router->nickname);
-      routerlist_remove(routerlist, router, i--, 1);
+  /* If we have a bunch of networkstatuses, we should consider pruning current
+   * routers that are too old and that nobody recommends.  (If we don't have
+   * enough networkstatuses, then we should get more before we decide to kill
+   * routers.) */
+  if (smartlist_len(networkstatus_list) > get_n_v2_authorities() / 2) {
+    cutoff = now - ROUTER_MAX_AGE;
+    /* Remove too-old unrecommended members of routerlist->routers. */
+    for (i = 0; i < smartlist_len(routerlist->routers); ++i) {
+      router = smartlist_get(routerlist->routers, i);
+      if (router->cache_info.published_on <= cutoff &&
+          !digestmap_get(retain,router->cache_info.signed_descriptor_digest)) {
+        /* Too old: remove it.  (If we're a cache, just move it into
+         * old_routers.) */
+        log_info(LD_DIR,
+                 "Forgetting obsolete (too old) routerinfo for router '%s'",
+                 router->nickname);
+        routerlist_remove(routerlist, router, i--, 1);
+      }
     }
   }
 
@@ -2052,8 +2057,8 @@ routerlist_remove_old_routers(void)
     }
   }
 
-  /* Now we're looking at routerlist->old_routers for extraneous
-   * members. (We'd keep all the members if we could, but we'd like to save
+  /* Now we might have to look at routerlist->old_routers for extraneous
+   * members. (We'd keep all the members if we could, but we need to save
    * space.) First, check whether we have too many router descriptors, total.
    * We're okay with having too many for some given router, so long as the
    * total number doesn't approach max_descriptors_per_router()*len(router).
@@ -3595,10 +3600,6 @@ client_would_use_router(routerstatus_t *rs, time_t now, or_options_t *options)
      * But, if we want to have a complete list, fetch it anyway. */
     return 0;
   }
-  if (rs->published_on + ROUTER_MAX_AGE < now) {
-    /* This one is too old to consider. */
-    return 0;
-  }
   if (rs->published_on + ESTIMATED_PROPAGATION_TIME > now) {
     /* Most caches probably don't have this descriptor yet. */
     return 0;