steid

@jamesgill /

steid/plans/current.md
6.2 KBCode·Blame·Raw
ab7fea9chore: plans setup1mo
1# Current
2
3> Keep this file short. One active step, one ordered backlog. Completed work moves to
4> [progress.md]progress.md. If this file starts reading like a changelog, it has
5> drifted — that's exactly what went wrong last time.
6
dce0bf3feat: browse a repository's files and history8d
7## Active: Milestone 6 — Writing
a814db5feat: push and clone private repositories with a token8d
8
dce0bf3feat: browse a repository's files and history8d
9**Goal:** posts, written in markdown, at `/{handle}/posts/{slug}`, appearing on the
10profile. The second portfolio feature, and the one that makes Steid something other than
11a git host.
a814db5feat: push and clone private repositories with a token8d
12
dce0bf3feat: browse a repository's files and history8d
13**Not planned yet.** Steps get laid out at the start of the milestone.
8608574feat: personal access tokens, as a domain type8d
14
be4fac5docs: correct the Topcoat guidance in CLAUDE.md24d
15### Open
16
dce0bf3feat: browse a repository's files and history8d
17- **Which markdown crate**, and whether rendering is trusted. `pulldown-cmark` is the
18 obvious choice and is not currently a dependency. Raw HTML in markdown is the decision
19 inside it: a single-author instance can trust its own input, but the moment Milestone 7
20 adds a second user that assumption is a stored-XSS hole. Deciding now is cheaper than
21 retrofitting a sanitiser.
22- **Whether a repository's README renders on its page.** It is the feature that makes a
23 repo page look like a portfolio piece rather than a file list, and it falls out of the
24 markdown pipeline this milestone builds — so it belongs here rather than back in 5.
be4fac5docs: correct the Topcoat guidance in CLAUDE.md24d
25
e0856ebfeat: clone a public repository over HTTP8d
26### Carried over — small, unblocked
d7b99d9docs: record milestone 0 progress and routing findings1mo
27
47db238feat: serve the git protocol through http-backend, behind a port8d
28- **A client that disappears mid-request leaves the body-copy task waiting.** The copy
e0856ebfeat: clone a public repository over HTTP8d
29 into git's stdin runs in its own task and nothing cancels it if the connection drops.
47db238feat: serve the git protocol through http-backend, behind a port8d
30 Bounded by the backend exiting and closing the pipe, but not by anything deliberate.
a814db5feat: push and clone private repositories with a token8d
31- **`REMOTE_USER` is not set on the backend**, so a push is recorded in the repository's
32 reflog without naming who made it. Steid knows the actor by then; it simply is not
33 passed through. Small, and worth doing before anything reads reflogs.
34- **No rate limiting on token authentication.** A token is 256 bits so guessing is not
35 the worry; unbounded hashing on an open endpoint is.
36- **Tokens have no expiry and no last-used timestamp.** Both deliberate omissions for
37 now — see [0007]decisions/0007-tokens-over-http-basic.md — but a token list with no
38 "last used" makes it hard to know which are safe to revoke.
e0856ebfeat: clone a public repository over HTTP8d
39- **A subprocess per git request.** Unlike Milestone 3's once-per-creation, this is on a
40 hot path and has not been measured. Milestone 5 is where that bill comes due.
41- **Streaming is by construction, not by measurement.** The response body is never
42 collected, but no clone large enough to prove it has been run.
6a2a925docs: close Milestone 3, plan Milestone 4a8d
43- **An orphaned repo directory is possible** if the process dies between the record
44 write and the filesystem write, and it then blocks re-creating that name. The durable
45 fix is a reconciliation sweep on boot
46 ([architecture.md]architecture.md#db-plus-filesystem-writes); clearing one is a
47 manual `rm` today, since repo deletion does not exist.
48- **The duplicate-name check races.** The loser is caught by `init_bare` or the unique
49 constraint, but surfaces as an opaque storage error rather than "name taken".
50- **Bare repos created on macOS carry `ignorecase = true`.** A migration gotcha if the
51 data directory ever moves to Linux.
dce0bf3feat: browse a repository's files and history8d
52- **Light mode is still untested**, and now there is much more surface to get it wrong
53 on — the file tree, the blob view and the log all shipped without anyone looking at
54 them in light mode.
55- **Submodule rendering was never seen**, only compiled: no fixture contained one.
56- **The `/log` page shows no branch indicator** when no revision is given, because
57 `repo_log` does not return the revision it resolved. A second query or a small
58 application change, neither urgent.
59- **A per-file last-commit column is still absent**, deliberately — see
60 [0006]decisions/0006-git-binary-behind-narrow-ports.md#amendment--20260829-the-milestone-5-read-path.
61 Wanting it is the trigger to move to a kept-alive `cat-file --batch`, not to reopen
62 `gix`.
2eb8681docs: put git next, plan the repo model24d
63- **Fonts are not loaded.** The theme names Geist and IBM Plex Mono; both fall back
64 today. Topcoat's `font-fontsource` feature handles it.
65- **Light mode is untested.** The palette defines it; nobody has looked at it.
f0444b7docs: plan milestone 2 in two phases1mo
66- **No rate limiting** on `/auth/login` or `/auth/setup`.
076dbc9docs: close milestone 1, open milestone 21mo
67- **`sweep_expired` is never called**, so expired session rows accumulate. Expiry is
68 enforced on read, so this is tidiness, not a hole.
2eb8681docs: put git next, plan the repo model24d
69- **CSRF.** `SameSite=Lax` covers the common case. Forms now exist, so this is decidable
70 rather than hypothetical.
ab7fea9chore: plans setup1mo
71
72## Backlog
73
74Ordered. Pull from the top.
75
a814db5feat: push and clone private repositories with a token8d
761. **Milestone 6 — Writing.** Posts, markdown, `/{handle}/posts/{slug}`. Still open
2eb8681docs: put git next, plan the repo model24d
77 whether writing or projects/showcases is the better first portfolio feature.
ab7fea9chore: plans setup1mo
78
79## Open questions
80
bd48b4bdocs: serve git over smart HTTP, reorder roadmap portfolio-first1mo
81- **Topcoat is early** (v0.5.0, first released 2026-07-22, breaking changes expected
82 by its own authors). Expect churn that isn't feature work.
83- Topcoat ships Tailwind without Node, which reopens the design system attempt #1
84 dropped purely to avoid an npm build step — see [ui.md]ui.md.
85
86## Routing findings (Milestone 0)
87
88- **Topcoat 0.5 requires rustc ≥ 1.95.** On an older toolchain `cargo add topcoat`
89 silently resolves to an empty `topcoat v0.0.0` placeholder instead of failing. Local
90 stable is now 1.97.1.
91- `Router::builder().discover()` collects `#[page]`-annotated items **at link time**,
92 so pages can live in any module. Layering is our choice, not the framework's.
93- `module_router!` derives each URL from the module tree rather than a path string.
aaefaabfeat: root handles, grouped routes, reserved-handle denylist1mo
94 Still deferred. Application routes now group cleanly (`auth/login`, `api/me`), but
95 handles sit at the root ([0004]decisions/0004-root-handles-grouped-routes.md), so a
96 parameterised root segment still has to coexist with static ones. Worth checking how
97 `module_router!` handles that before committing to it.
bd48b4bdocs: serve git over smart HTTP, reorder roadmap portfolio-first1mo
98- Path and query params are read from `Cx` via `path_param!` / `#[query_params]`, not
99 injected as handler arguments. Parses are memoized per request.
100- Layouts wrap by path prefix and nest outermost-first, and a layout can catch a page's
101 `NotFoundError` to render a branded 404.
102- `HOST` / `PORT` configure the bind address, so `STEID_LISTEN_ADDR` is gone.
103- `Body` is a boxed `http_body::Body` used for both requests and responses, with
104 `into_data_stream()` to read and `Body::new()` to wrap a stream — pack data can
ca76e1bdocs: fix milestone cross-references after the reorder24d
105 stream both directions without buffering. This is what makes Milestone 4 viable.