Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions docs/agent-runs/directory-routes/feature-list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
{
"task": "directory-routes",
"last_updated": "2026-07-19",
"items": [
{
"id": "F001",
"priority": 1,
"status": "completed",
"description": "Load and validate the small Seedit directory registry without allowing directory slugs into account subscriptions.",
"verification": [
"Focused directory-list normalization and winner-selection tests pass."
],
"files": [
"src/data/seedit-directories",
"src/data/vendored-directory-lists.ts",
"src/hooks/use-directory-list.ts",
"src/lib/utils/directory-list-utils.ts"
],
"notes": "Directory data is allowed only for short-route discovery and consented update offers."
},
{
"id": "F002",
"priority": 2,
"status": "completed",
"description": "Resolve reserved /s/<slug> routes to the current winning community while keeping explicit address and post routes canonical.",
"verification": [
"/s/funny renders the current winner, /s/funny.bso remains exact, and all /comments/<cid> paths contain an exact address."
],
"files": [
"src/hooks/use-resolved-community-route.ts",
"src/lib/utils/community-route-utils.ts",
"src/views/community/community.tsx",
"src/views/post-page/post-page.tsx",
"src/components/exact-community-action-route"
],
"notes": "Home and subscription navigation must never resolve directory slugs at read time."
},
{
"id": "F003",
"priority": 3,
"status": "completed",
"description": "Disclose the exact winner on directory routes and make the existing Join action subscribe only to that exact address.",
"verification": [
"Desktop and mobile browser checks confirm one Join meaning and a keyboard-accessible exact-address link."
],
"files": [
"src/components/sidebar/sidebar.tsx",
"src/components/header/header.tsx",
"src/components/subscribe-button/subscribe-button.tsx",
"src/components/directory-auto-switch-control"
],
"notes": "Preserve Seedit's compact old.reddit visual language."
},
{
"id": "F004",
"priority": 4,
"status": "completed",
"description": "Offer consented add, keep, keep-both, or per-directory auto-follow behavior when a directory winner changes, while persisting exact addresses only.",
"verification": [
"Focused transition tests prove manual subscriptions survive and auto-follow rewrites only subscriptions attributable to the changed slot."
],
"files": [
"src/components/directory-subscription-reconciler",
"src/components/directory-subscription-updates-notice",
"src/lib/utils/directory-subscriptions.ts",
"src/lib/utils/directory-account-transforms.ts",
"src/lib/utils/starter-account.ts"
],
"notes": "No silent changes without a prior explicit opt-in, and every automatic change receives an informational notice."
},
{
"id": "F005",
"priority": 5,
"status": "completed",
"description": "Document the route-only directory boundary and update user-facing copy and generated AI context where required.",
"verification": [
"Documentation states that directories govern entry routes, while subscriptions and permalinks remain exact."
],
"files": [
"docs/architecture/directory-routes.md",
"public/translations"
],
"notes": "Run yarn llms:generate for public-facing documentation changes."
},
{
"id": "F006",
"priority": 6,
"status": "completed",
"description": "Complete static, unit, React quality, multi-engine browser, responsive, theme, and throttled navigation verification.",
"verification": [
"168 tests, production build, lint, type-check, Knip, AI workflow parity, changed-scope React Doctor, generated LLM context, and git diff --check pass.",
"Chrome, Firefox, and WebKit pass at 1440x1000 and 390x844; Chromium also passes warm navigation under the repository's mid-throttle profile."
],
"files": [],
"notes": "Verified with Node 22.12.0 and fresh isolated browser sessions. Full-repository React Doctor retains pre-existing findings outside this change; changed-scope React Doctor reports no issues."
}
]
}
24 changes: 24 additions & 0 deletions docs/agent-runs/directory-routes/progress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Progress Log

## 2026-07-19

- Item: F001
- Summary: Created the isolated worktree, loaded product and design context, started three read-only audits, and confirmed the supported agent-init command starts the branch-scoped development server.
- Files: `docs/agent-runs/directory-routes/feature-list.json`, `docs/agent-runs/directory-routes/progress.md`
- Verification: `./scripts/agent-init.sh`
- Blockers: none
- Next: Finish source archaeology and implement the directory registry as a route-only input.

- Item: F001-F005
- Summary: Implemented versioned deterministic directory snapshots, route-only resolution, exact-address Join and permalink behavior, atomic subscription provenance, consented winner-change actions, per-slot automatic switching with safe undo, exact action-route redirects, localized disclosure/update UI, and the architecture decision record.
- Files: `src/data/seedit-directories/`, `src/hooks/use-directory-list.ts`, `src/hooks/use-resolved-community-route.ts`, `src/lib/utils/directory-subscriptions.ts`, `src/lib/utils/directory-account-transforms.ts`, `src/components/directory-*`, `src/components/exact-community-action-route/`, `docs/architecture/directory-routes.md`
- Verification: 25 test files / 168 tests; build, lint, type-check, Knip, AI workflow parity, generated LLM context, changed-scope React Doctor, translation coverage, and `git diff --check` pass.
- Blockers: Full-repository React Doctor still exits on pre-existing findings outside this change; changed-scope React Doctor reports no issues.
- Next: Finish the multi-engine desktop/mobile and throttled Chromium browser pass, then split the Seedit diff into focused commits without pushing it.

- Item: F006
- Summary: Completed the final quality gate and browser matrix. Directory aliases disclose and join the exact winner, exact-address routes remain exact, submit aliases canonicalize before rendering, and no directory slug enters account subscriptions.
- Files: `docs/agent-runs/directory-routes/feature-list.json`, `docs/agent-runs/directory-routes/progress.md`
- Verification: 25 test files / 168 tests; build, lint, type-check, Knip, AI workflow parity, changed-scope React Doctor, generated LLM context, and `git diff --check`; Chrome, Firefox, and WebKit at 1440x1000 and 390x844; Chromium mid-throttle warm navigation; light and dark themes; no horizontal overflow.
- Blockers: Full-repository React Doctor retains pre-existing findings outside this change; external P2P router CORS/404/521 failures were observed during browser verification but produced no directory-feature exceptions.
- Next: Review the four focused local commits; keep the Seedit branch unpushed until explicitly approved.
56 changes: 56 additions & 0 deletions docs/architecture/directory-routes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Seedit directory routes

## Status

Accepted.

## Decision

Seedit directory codes are mutable discovery routes, not subscription identities.

- `/s/funny` resolves the finalized `funny` directory snapshot and displays its deterministic winner.
- `/s/funny.bso` and `/s/funny-posting.bso` identify exact communities.
- `account.subscriptions` contains only exact community addresses or public keys. A directory code is never stored there.
- The home feed reads the exact subscription array directly and never resolves directory codes.
- Joining from `/s/funny` atomically subscribes to the exact current winner and records Seedit-only directory provenance.
- Generated post permalinks always use the post owner's exact community address and `/comments/<cid>`.
- A winner change does not alter a subscription by default. Seedit presents an inline choice to switch, keep both, or keep the current community.
- Automatic switching is an explicit per-directory preference. An automatic change produces a persistent notice with undo.

The short route is therefore a contested front door. The user's feed and durable links remain pinned to identities they can inspect and carry to another Bitsocial client.

## Snapshot rules

Directory payloads use `schemaVersion: 1` and a monotonically increasing `revision`. The revision is the atomic change boundary: candidate membership or winner selection must not change at the same revision.

Candidates are ordered deterministically by:

1. score, descending;
2. `addedAt`, ascending;
3. exact address, ascending.

Clients do not rotate to another candidate based on local availability. Every client using the same finalized snapshot must resolve the same winner.

The current `bitsocialnet/lists` publication is a bootstrap transport for these snapshots. It does not define the eventual decentralized voting or finalization protocol.

## Subscription provenance

Seedit stores directory provenance separately from the portable exact subscription array. Each tracked slot records:

- its exact attributable subscription address;
- the last acknowledged winner address and revision;
- whether the user explicitly enabled automatic switching.

This metadata lets Seedit offer winner-change actions without inventing a second kind of subscription. Other Bitsocial clients can ignore it and still read the user's exact subscriptions correctly.

## Defaults

Seedit's default-subscription list remains a list of exact addresses. A default entry may also include `directoryCode` and `directoryRevision` to record which finalized directory snapshot selected it. New accounts receive exact subscriptions plus the matching Seedit provenance; existing accounts retain their exact choices until they act on an update or previously enabled automatic switching.

## Rejected alternatives

- Directory codes in `account.subscriptions`: this makes feeds change at read time and is not portable across clients.
- Directory-coded post permalinks: a winner change can make an old post URL resolve through the wrong community.
- Client-local offline failover: two clients could resolve the same short route to different communities.
- Permanent Seedit-owned community subdomains: community identity should remain portable between Bitsocial clients.
- Administrator allocation of short names: this recreates the centralized veto power the directory mechanism is meant to replace.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"start:preview": "node scripts/start-preview.js",
"ai-workflow:check": "node scripts/validate-ai-workflow.mjs",
"llms:generate": "node scripts/generate-llms-files.mjs",
"sync:directories": "node scripts/sync-directories.js",
"build": "cross-env NODE_ENV=production PUBLIC_URL=./ GENERATE_SOURCEMAP=false vite build",
"build:preload": "cross-env NODE_ENV=production vite build --config electron/vite.preload.config.js",
"build-netlify": "cross-env NODE_OPTIONS=\"--max_old_space_size=4096\" NODE_ENV=production PUBLIC_URL=./ GENERATE_SOURCEMAP=true VITE_COMMIT_REF=$COMMIT_REF CI='' vite build",
Expand Down
12 changes: 11 additions & 1 deletion public/translations/ar/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -391,5 +391,15 @@
"settings_upgrade_error_saving": "تعذّر حفظ ترقية الإعدادات.",
"settings_upgrade_review_notice": "تتوفر ترقية للإعدادات",
"settings_upgrade_review_button": "مراجعة",
"settings_upgrade_never_show_again": "عدم العرض مرة أخرى"
"settings_upgrade_never_show_again": "عدم العرض مرة أخرى",
"directory_route_currently_recommends": "يوصي s/{{directoryCode}} حاليًا بـ",
"directory_auto_switch_label": "تبديل هذا الاشتراك تلقائيًا عندما يتغير s/{{directoryCode}}",
"directory_recommendation_changed": "يوصي s/{{directoryCode}} الآن بـ",
"directory_auto_switch_help": "سيستبدل Seedit هذا الاشتراك بالمجتمع الموصى به حديثًا. يمكنك إيقاف هذا الخيار في أي وقت.",
"directory_you_still_follow": "لا تزال تتابع",
"switch_to_community": "التبديل إلى {{communityAddress}}",
"keep_both_communities": "الاحتفاظ بكليهما",
"keep_community": "الاحتفاظ بـ {{communityAddress}}",
"directory_automatic_switch_notice": "تغيّر s/{{directoryCode}}، لذا حوّل Seedit اشتراكك من {{fromAddress}} إلى {{toAddress}}.",
"dismiss": "تجاهل"
}
12 changes: 11 additions & 1 deletion public/translations/bn/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -391,5 +391,15 @@
"settings_upgrade_error_saving": "সেটিংস আপগ্রেড সংরক্ষণ করা যায়নি।",
"settings_upgrade_review_notice": "সেটিংস আপগ্রেড উপলভ্য",
"settings_upgrade_review_button": "পর্যালোচনা করুন",
"settings_upgrade_never_show_again": "আর কখনও দেখাবেন না"
"settings_upgrade_never_show_again": "আর কখনও দেখাবেন না",
"directory_route_currently_recommends": "s/{{directoryCode}}-এর বর্তমান সুপারিশ:",
"directory_auto_switch_label": "s/{{directoryCode}} পরিবর্তন হলে স্বয়ংক্রিয়ভাবে এই সাবস্ক্রিপশনটি পরিবর্তন করুন",
"directory_recommendation_changed": "s/{{directoryCode}} এখন সুপারিশ করছে",
"directory_auto_switch_help": "Seedit এই সাবস্ক্রিপশনটি নতুনভাবে সুপারিশ করা কমিউনিটি দিয়ে প্রতিস্থাপন করবে। আপনি যেকোনো সময় এটি বন্ধ করতে পারেন।",
"directory_you_still_follow": "আপনি এখনও অনুসরণ করছেন",
"switch_to_community": "{{communityAddress}}-এ স্যুইচ করুন",
"keep_both_communities": "দুটিই রাখুন",
"keep_community": "{{communityAddress}} রাখুন",
"directory_automatic_switch_notice": "s/{{directoryCode}} পরিবর্তিত হয়েছে, তাই Seedit আপনার সাবস্ক্রিপশন {{fromAddress}} থেকে {{toAddress}}-এ পরিবর্তন করেছে।",
"dismiss": "খারিজ করুন"
}
12 changes: 11 additions & 1 deletion public/translations/cs/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -391,5 +391,15 @@
"settings_upgrade_error_saving": "Upgrade nastavení se nepodařilo uložit.",
"settings_upgrade_review_notice": "je k dispozici upgrade nastavení",
"settings_upgrade_review_button": "zkontrolovat",
"settings_upgrade_never_show_again": "již nikdy nezobrazovat"
"settings_upgrade_never_show_again": "již nikdy nezobrazovat",
"directory_route_currently_recommends": "s/{{directoryCode}} aktuálně doporučuje",
"directory_auto_switch_label": "automaticky přepnout toto předplatné, když se s/{{directoryCode}} změní",
"directory_recommendation_changed": "s/{{directoryCode}} nyní doporučuje",
"directory_auto_switch_help": "Seedit nahradí toto předplatné nově doporučenou komunitou. Tuto možnost můžete kdykoli vypnout.",
"directory_you_still_follow": "Stále sledujete",
"switch_to_community": "přejít na {{communityAddress}}",
"keep_both_communities": "ponechat obě",
"keep_community": "ponechat {{communityAddress}}",
"directory_automatic_switch_notice": "s/{{directoryCode}} se změnilo, takže Seedit převedl vaše předplatné z {{fromAddress}} na {{toAddress}}.",
"dismiss": "Zavřít"
}
12 changes: 11 additions & 1 deletion public/translations/da/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -391,5 +391,15 @@
"settings_upgrade_error_saving": "Indstillingsopgraderingen kunne ikke gemmes.",
"settings_upgrade_review_notice": "opgradering af indstillinger er tilgængelig",
"settings_upgrade_review_button": "gennemgå",
"settings_upgrade_never_show_again": "vis aldrig igen"
"settings_upgrade_never_show_again": "vis aldrig igen",
"directory_route_currently_recommends": "s/{{directoryCode}} anbefaler i øjeblikket",
"directory_auto_switch_label": "skift automatisk dette abonnement, når s/{{directoryCode}} ændres",
"directory_recommendation_changed": "s/{{directoryCode}} anbefaler nu",
"directory_auto_switch_help": "Seedit erstatter dette abonnement med det nyligt anbefalede fællesskab. Du kan til enhver tid slå dette fra.",
"directory_you_still_follow": "Du følger stadig",
"switch_to_community": "skift til {{communityAddress}}",
"keep_both_communities": "behold begge",
"keep_community": "behold {{communityAddress}}",
"directory_automatic_switch_notice": "s/{{directoryCode}} er ændret, så Seedit skiftede dit abonnement fra {{fromAddress}} til {{toAddress}}.",
"dismiss": "Luk"
}
12 changes: 11 additions & 1 deletion public/translations/de/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -391,5 +391,15 @@
"settings_upgrade_error_saving": "Das Einstellungs-Upgrade konnte nicht gespeichert werden.",
"settings_upgrade_review_notice": "Upgrade für Einstellungen verfügbar",
"settings_upgrade_review_button": "prüfen",
"settings_upgrade_never_show_again": "nie wieder anzeigen"
"settings_upgrade_never_show_again": "nie wieder anzeigen",
"directory_route_currently_recommends": "s/{{directoryCode}} empfiehlt derzeit",
"directory_auto_switch_label": "dieses Abonnement automatisch wechseln, wenn sich s/{{directoryCode}} ändert",
"directory_recommendation_changed": "s/{{directoryCode}} empfiehlt jetzt",
"directory_auto_switch_help": "Seedit ersetzt dieses Abonnement durch die neu empfohlene Community. Du kannst dies jederzeit deaktivieren.",
"directory_you_still_follow": "Du folgst weiterhin",
"switch_to_community": "zu {{communityAddress}} wechseln",
"keep_both_communities": "beide behalten",
"keep_community": "{{communityAddress}} behalten",
"directory_automatic_switch_notice": "s/{{directoryCode}} hat sich geändert, daher hat Seedit dein Abonnement von {{fromAddress}} zu {{toAddress}} gewechselt.",
"dismiss": "Ausblenden"
}
12 changes: 11 additions & 1 deletion public/translations/el/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -391,5 +391,15 @@
"settings_upgrade_error_saving": "Δεν ήταν δυνατή η αποθήκευση της αναβάθμισης ρυθμίσεων.",
"settings_upgrade_review_notice": "διατίθεται αναβάθμιση ρυθμίσεων",
"settings_upgrade_review_button": "έλεγχος",
"settings_upgrade_never_show_again": "να μην εμφανιστεί ξανά"
"settings_upgrade_never_show_again": "να μην εμφανιστεί ξανά",
"directory_route_currently_recommends": "Το s/{{directoryCode}} προτείνει αυτή τη στιγμή",
"directory_auto_switch_label": "αυτόματη αλλαγή αυτής της συνδρομής όταν αλλάζει το s/{{directoryCode}}",
"directory_recommendation_changed": "Το s/{{directoryCode}} προτείνει τώρα",
"directory_auto_switch_help": "Το Seedit θα αντικαταστήσει αυτήν τη συνδρομή με τη νέα προτεινόμενη κοινότητα. Μπορείτε να απενεργοποιήσετε αυτήν την επιλογή ανά πάσα στιγμή.",
"directory_you_still_follow": "Εξακολουθείτε να ακολουθείτε",
"switch_to_community": "μετάβαση στο {{communityAddress}}",
"keep_both_communities": "διατήρηση και των δύο",
"keep_community": "διατήρηση του {{communityAddress}}",
"directory_automatic_switch_notice": "Το s/{{directoryCode}} άλλαξε, οπότε το Seedit μετέφερε τη συνδρομή σας από το {{fromAddress}} στο {{toAddress}}.",
"dismiss": "Κλείσιμο"
}
Loading
Loading