constitution · epochs · watch · epoch 3

comparison

c_16fc6778276f (tommy-mor) vs c_60c575d6de0d (tommy-mor)

download prompt · raw event · cmp_9a7f86a19e32e0

council reasoning

~anthropic/claude-sonnet-latest · winner A · 6:4 · permalink

Side A removes actual dead code (an unused function) and a small CSS tweak, both of which affect runtime behavior/code cleanliness in the shipped product. Side B merely deletes a design/planning markdown document, which has no functional impact and only removes documentation that could still have reference value.

~x-ai/grok-latest · winner A · 2:1 · permalink

A removes dead Rust API surface (expand_room_new_thread_rpc_value) and a small mistaken CSS border rule in live server code, which improves maintainability of the running product. B only deletes an internal design doc (PLAN.md) with no effect on behavior, types, or UX—useful housekeeping, but less lasting substance than cleaning actual code paths.

openai/gpt-chat-latest · winner A · 4:1 · permalink

Side A makes a small but concrete codebase cleanup by removing an unused Rust helper (`expand_room_new_thread_rpc_value`) and adjusts the retro theme CSS by dropping explicit left/right border overrides on the thread compose textarea. Side B only deletes `PLAN.md`, removing a design document without changing runtime behavior or improving the implementation.

sides

A — c_16fc6778276f (tommy-mor)

message

[e202d8bd] nit

diff preview

diff --git a/server/src/html/forum.rs b/server/src/html/forum.rs
index 9d9eae409e9df24d6946a6f8782da9b1d536fe3c..f6e45b05bb92126966e304619f80ef1d45be7a4b 100644
--- a/server/src/html/forum.rs
+++ b/server/src/html/forum.rs
@@ -1051,13 +1051,6 @@ pub(crate) fn expand_public_new_thread_rpc_value() -> String {
     template_json_compact(&HtmlUiAction::ExpandPublicNewThreadForm).expect("static json")
 }
 
-pub(crate) fn expand_room_new_thread_rpc_value(nav: &ThreadNav) -> String {
-    template_json_compact(&HtmlUiAction::ExpandRoomNewThreadForm {
-        room_wire: nav.room_wire.clone(),
-    })
-    .expect("static json")
-}
-
 pub(crate) fn login_to_post_hint_markup() -> Markup {
     html! {
         p class="muted" { "log in to post" }
diff --git a/server/static/theme_retro_craft.css b/server/static/theme_retro_craft.css
index fa23d5088e4966d3ebd7e95d4c7f8f8bbebae266..00714575bfa533d1d9c66653b9089642e2b0a6ca 100644
--- a/server/static/theme_retro_craft.css
+++ b/server/static/theme_retro_craft.css
@@ -468,8 +468,6 @@ body.view-ontology #controls {
   }
   section#thread-compose textarea {
     border-radius: 0;
-    border-left: none;
-    border-right: none;
     box-sizing: border-box;
     display: block;
     margin: 0;

download full diff A

B — c_60c575d6de0d (tommy-mor)

message

[e3da4045] Delete PLAN.md

diff preview

diff --git a/PLAN.md b/PLAN.md
deleted file mode 100644
index aa1158978da3ee6da362f2704b30c937eb3367cd..0000000000000000000000000000000000000000
--- a/PLAN.md
+++ /dev/null
@@ -1,385 +0,0 @@
-# Extensible URLs — Design Plan
-
-*Addresses [#134](https://github.com/sortersocial/slug/issues/134)*
-
----
-
-## Problem Statement
-
-External URLs (`-/host/path`) already exist as first-class garden items: they have `ItemId::Web` identity, `parent()`/child edges, breadcrumbs, and rankings. But the system only knows about external items that a human manually declared via the DSL. There is no mechanism to:
-
-1. **Automatically discover children** of an external URL (e.g. list the current issues under `github.com/org/repo/issues`).
-2. **Navigate the URL hierarchy** the way you can navigate `~/` — clicking into `github.com/org` should show repos, clicking a repo should show its structure (issues, pulls, commits, etc.).
-3. **Display the external page itself** when visiting a leaf item (currently shows "This is an external scope." with a disabled agent button).
-4. **Keep external children in sync** as the upstream source changes (new issues opened, repos created, etc.).
-
-The goal: URL structure becomes a votable/explorable ontology identical in UX to `~/`, with per-domain resolvers that can populate children automatically.
-
----
-
-## Current Architecture (relevant subsystems)
-
-### Item identity pipeline
-
-```
-User input ("~/a/b", "-/github.com/org/repo", "https://example.com/foo")
-  → canonicalize_item()         [types/src/item_wire.rs]
-      → normalize_http_identity_url()  [types/src/url_normalize.rs]
-  → ItemId::parse()             [types/src/item_id.rs]
-  → ItemId { Root | Local | Web | Opaque }
-```
-
-**Key properties of `ItemId::Web`:**
-- Storage form is a normalized `https://…` string.
-- `parent()` strips the last path segment (host-only items have no parent).
-- `display_path()` renders as `-/host/path`.
-- Parent→child edges are built by `add_child_edge` in the reducer when items are ingested.
-
-### URL normalization (`url_normalize.rs`)
-
-Currently handles:
-- Query-pair sorting (lexicographic by lowercase key, then value).
-- YouTube family: `youtu.be`, `/embed/`, `/v/`, `/shorts/`, `m.youtube.com` → canonical `www.youtube.com/watch?v=ID` or `www.youtube.com/shorts/ID`.
-- `host_preserves_dash_path_case` — YouTube hosts keep case (video IDs are case-sensitive); all other hosts lowercase path segments.
-
-### External resolver (`external_resolver.rs`)
-
-A trait stub:
-```rust
-pub trait ExternalResolver: Send + Sync {
-    fn domain_match(&self) -> &'static str;
-    fn normalize(&self, path: &str) -> String;
-    async fn fetch_body(&self, item: &ItemId) -> Result<String, String>;
-}
-```
-
-Only `DefaultExternalResolver` exists (returns "external fetch not implemented").
-
-### Garden rendering (`html/garden.rs`, `html/breadcrumb_path.rs`)
-
-- `ExternalOntologyPath::from_input` parses `/-/*path` into segments for breadcrumbs.
-- `render_scope_view` shows the item body (if any), children rankings, and vote history.
-- When an external item has no body: shows "This is an external scope." + disabled "Kick off an Agent Run to import and rank items" button.
-- Breadcrumbs split by `/` from the `https://` storage form — each segment is clickable.
-
-### DSL parsing (`dsl.rs`)
-
-Items can be referenced as:
-- `~/path/segments` — slug ontology.
-- `-/host/path/segments` — external items.
-- `https://...` / `http://...` — full URLs.
-
-The `-/` lexer accepts: alphanumeric, `_-/.?=&%:#+@~` — broad enough for query strings and fragments.
-
-### Thread/ingest model
-
-Items live in the garden; threads provide the temporal context. An `Ingest` event contains raw DSL text in a `thread_tag`. The DSL is parsed during `apply_ingest_to_content`, which creates items, registers bodies, records votes, and builds `item_children` edges.
-
----
-
-## Design
-
-### 1. Ingesting external URLs into threads
-
-**Mechanism:** External URLs are already valid DSL item references. A user (or automated agent) can write:
-
-```
--/github.com/sortersocial/slug/issues
-  The issues list for the slug repo.
-```
-
-This already works today — it creates an `ItemId::Web("https://github.com/sortersocial/slug/issues")` with a body, registers parent edges up through `github.com/sortersocial/slug` → `github.com/sortersocial` → `github.com`, and makes it browsable at `/-/github.com/sortersocial/slug/issues`.
-
-**What needs to change for auto-population:** When someone navigates to (or explicitly requests) an external scope, the system should be able to auto-populate its children. This is the job of domain-specific resolvers.
-
-### 2. Domain resolver system
-
-Extend the existing `ExternalResolver` trait into a **registry of domain resolvers**.
-
-```rust
-pub trait DomainResolver: Send + Sync {
-    /// Host patterns this resolver handles (e.g. "github.com").
-    fn matches_host(&self, host: &str) -> bool;
-
-    /// Given a parent external URL, discover its direct children.
-    /// Returns (child_url, title, optional_body) tuples.
-    async fn list_children(&self, parent: &ItemId) -> Result<Vec<ResolvedChild>, ResolverError>;
-
-    /// Fetch/compute a body for a single item (e.g. issue description, README excerpt).
-    async fn fetch_body(&self, item: &ItemId) -> Result<String, ResolverError>;
-
-    /// Domain-specific URL normalization beyond the generic pipeline.
-    fn normalize(&self, url: &str) -> Option<String>;
-}
-
-pub struct ResolvedChild {
-    pub url: String,      // canonical URL
-    pub title: String,    // display title
-    pub body: Option<String>,
-}
-```
-
-**Registry:** `AppState` holds a `Vec<Arc<dyn DomainResolver>>`. On boot, register configured resolvers (initially just GitHub). Resolver lookup: find first where `matches_host(item_host)` returns true; fall back to `DefaultResolver` (which can still do generic things like fetching `<title>` tags).
-
-**Synthetic ingests:** When a resolver returns children, the server creates synthetic `Ingest` events attributed to a system principal (e.g. `@system:resolver`). These go through the normal `write_actor` → JSONL → reducer pipeline so they are durable, replayable, and show up in thread feeds.
-
-**Thread assignment:** Resolver-created items should land in a thread. Candidates:
-- **Option A:** `#import/<host>` (e.g. `#import/github.com`) — groups all resolver activity by domain.
-- **Option B:** `#import/<parent_path>` (e.g. `#import/github.com/org/repo/issues`) — groups by the scope that was resolved.
-- **Recommendation: Option B.** It's more specific and gives users a thread to follow for a particular external scope. Thread tag format: `import:<display_path>` (e.g. `import:-/github.com/org/repo/issues`). The `:` separates the thread namespace from user-created `#` threads while reusing the same `canonicalize_tag` pipeline.
-
-### 3. URL canonicalization
-
-The existing pipeline (`canonicalize_item` → `normalize_http_identity_url` → `ItemId::parse`) is already solid. Extend it:
-
-#### 3a. Current canonicalization rules (keep)
-- Lowercase host.
-- Lowercase path segments (except case-sensitive hosts like YouTube).
-- Sort query pairs by lowercase key.
-- YouTube: `youtu.be/ID` → `youtube.com/watch?v=ID`, `/embed/ID` → `/watch?v=ID`, etc.
-- Strip default ports (80/443).
-- Trim trailing slashes (host-only).
-
-#### 3b. New canonicalization rules (add)
-
-**Fragment stripping:**
-- By default, strip `#fragment` from URLs used as item identity. Fragments identify within-page positions, not distinct resources. `github.com/org/repo/issues/42` and `github.com/org/repo/issues/42#issuecomment-123` should resolve to the same item.
-- Exception: some sites use fragments as primary routing (e.g. single-page apps). Resolver-specific `normalize` can preserve fragments where the domain requires it.
-- Implementation: add `strip_fragment(u: &mut Url)` call in `normalize_http_identity_url`, before `sort_query_pairs`.
-
-**Scheme normalization:**
-- Already handled: `http://` and `https://` both pass through `canonicalize_item`. However, `http://example.com` and `https://example.com` produce different `ItemId::Web` values.
-- Policy decision: **prefer `https://`**. In `normalize_http_identity_url`, if scheme is `http`, upgrade to `https` (with an opt-out list for known http-only sites if needed).
-- This is debatable. Alternative: leave scheme as-is, since some sites genuinely differ. Start with scheme-preserving and let resolver `normalize()` handle specific cases.
-
-**Trailing-path slash normalization:**
-- Currently `strip_redundant_root_slash` only handles host-only URLs. Extend to strip trailing `/` from all paths: `github.com/org/repo/` → `github.com/org/repo`.
-- Already partially handled in `canonicalize_item` which trims trailing `/` from each segment during construction.
-
-**`www.` stripping:**
-- Currently only done for YouTube. Consider generalizing: `www.example.com` → `example.com` for identity purposes.
-- Risk: some sites serve different content at `www.` vs bare domain. Start with YouTube only; add to resolver `normalize()` per domain.
-
-#### 3c. Additional URL equivalences to handle
-
-| Input form | Canonical form | Notes |
-|---|---|---|
-| `youtu.be/ID` | `https://www.youtube.com/watch?v=ID` | Already handled |
-| `youtube.com/embed/ID` | `https://www.youtube.com/watch?v=ID` | Already handled |
-| `youtube.com/shorts/ID` | `https://www.youtube.com/shorts/ID` | Already handled (kept as shorts) |
-| `m.youtube.com/watch?v=ID` | `https://www.youtube.com/watch?v=ID` | Already handled |
-| `github.com/ORG/REPO` | `https://github.com/org/repo` | Path lowercased (already handled by generic lowercasing) |
-| `github.com/ORG/REPO.git` | `https://github.com/org/repo` | Strip `.git` suffix — add to GitHub resolver `normalize()` |
-| `x.com/user/status/123` | `https://x.com/user/status/123` | Preserve as-is (or normalize `twitter.com` → `x.com`) |
-| `twitter.com/user/status/123` | `https://x.com/user/status/123` | Add Twitter→X rewrite in `url_normalize.rs` |
-| `reddit.com/r/sub/comments/id/…` | normalize to canonical Reddit URL | Reddit resolver |
-| URL with tracking params (`utm_*`, `fbclid`, etc.) | Strip known tracking params | Generic rule in `normalize_http_identity_url` |
-
-### 4. Query parameters
-
-Query parameters are tricky because they serve multiple purposes:
-
-**Identity-bearing:** `youtube.com/watch?v=ID` — the `v` param is the resource identity. Stripping it destroys the reference. Same for search queries, filter params on some sites.
-
-**Tracking/noise:** `?utm_source=…`, `?fbclid=…`, `?ref=…` — these should be stripped for canonical identity.
-
-**Pagination/state:** `?page=2`, `?sort=newest` — debatable. In the URL-as-ontology model, `github.com/org/repo/issues?page=2` probably shouldn't be a separate item from `github.com/org/repo/issues`.
-
-**Proposed policy:**
-
-1. **Generic stripping of known tracking params** in `normalize_http_identity_url`:
-   ```
-   utm_source, utm_medium, utm_campaign, utm_term, utm_content,
-   fbclid, gclid, ref, ref_src, ref_cta, ref_loc,
-   si (YouTube share tracking)
-   ```
-
-2. **Generic stripping of pagination params** (when not identity-bearing):
-   ```
-   page, per_page, offset, limit, cursor, after, before
-   ```
-   This is aggressive — resolver `normalize()` can re-add them if a domain treats pagination as identity.
-
-3. **Preserve all other query params** and sort them (already done).
-
-4. **Per-domain overrides** via `DomainResolver::normalize()`:
-   - GitHub: strip `?tab=…` on repo pages (just UI state).
-   - YouTube: preserve `v`, `list`; strip `t` (timestamp), `si`, `pp`, `feature`.
-   - Let each resolver declare which params are identity-bearing vs noise.
-
-### 5. Breadcrumbs for URL structures
-
-**Current state:** `ExternalOntologyPath` splits the stored `https://host/path` into segments for breadcrumbs. Each segment links to `/

… preview truncated; 10,654 characters omitted

download full diff B

Hardlinks — judgments / attempts / prompt

prompt download

judgments

attempts

Prompt text is loaded only by the download route.