Jev's kind of a commit is small muted monospace in its column, and a repo's topic, the mechanical mark on a diff file, what changed between two versions of a commit, a comment's outdated or addressed note, and a range-diff's unchanged or rewritten are words in their colour, without the pill around them. The shelf filters on the index and owner pages are plain links, the chosen one bold over a thin accent bar, with their counts as faint numbers. A review's latest revision (r2) is a plain link, and "private" a coloured word. Only a review's status keeps a shape, where it matters: a small square label, white on its colour, on review pages, in branch and stack tables and in review lists, where it replaces the round dot. The live status says what it is in words, without a dot.
- commit
- 0259f3c859c8886e14569ed24a00c874a5fef1ba
- parent
- 28742881e180f6c49287b4be428cdd9441039bb8
- author
- cat <admin@dev.site>
- ci
- ✓ passed in 78s, signed by cat
- kind
- refactor risk score 2.1 of 3, Jev's estimate
- review
- #12 Square, hairline, textured: the site's design pass
ci attestation
forge-attestation 1 type ci commit 0259f3c859c8886e14569ed24a00c874a5fef1ba tree 43fef645fa4d5b7857d20a2cb5c0e3a942f67ad6 script .forge/ci 38df37c0d5a6382f60569079a0dd821094e37e4a result pass exit 0 started 2026-10-19T01:51:52Z duration 78s runner (not shown here; refs/notes/ci has it) system Darwin 25.5.0 arm64 env host log sha256:4bc6c1cfb5a7d76e7b5a4ace3158c417aec951a7bdd2d07010c5d230280a711d 253 lines |remote: review #4: /dami/greet/reviews/4/ |pushed wip/i18n |b901d96 running .forge/ci: greet.sh: say what it is | | sh: /bin/sh | | ok greet |b901d96 pass in 0s, signed |pushed main |remote: review #4: /dami/greet/reviews/4/ |pushed wip/i18n |4f82d04 running .forge/ci: wave at the world | | sh: /bin/sh | | FAIL greet : got 'hello, world o/', want 'hello, world' |4f82d04 fail in 1s, signed |forge: 1 commit(s) did not pass |remote: review #6: /dami/greet/reviews/6/ |pushed ana/wave |982d757 running .forge/ci: update the test for the wave | | sh: /bin/sh | | ok greet |982d757 pass in 0s, signed |remote: review #6: /dami/greet/reviews/6/ |pushed ana/wave |warning: You appear to have cloned an empty repository. |site home: deployed 7e53850 -> /sites/ana/dotfiles/home/ |created ana/notes |remote: review #1: /ana/notes/reviews/1/ |pushed ana/todo |landing #1 A todo list: ana/todo -> main |daf325f running .forge/ci: web, server and Python versions of greet | | sh: /bin/sh | | ok greet |daf325f pass in 0s, signed |pushed main |3c2a9cc running .forge/ci: messages: notes for the later regions | | sh: /bin/sh | | ok greet |3c2a9cc pass in 0s, signed |remote: review #7: /dami/greet/reviews/7/ |pushed dami/regions |created dami/forge |warning: You appear to have cloned an empty repository. |site guide: deployed 314d9be -> /sites/dami/forge/guide/ |(node:64132) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built ana/dotfiles in 1s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.TecxQS/wt/demo/root/.forge/www |(node:64256) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built ana/notes in 0s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.TecxQS/wt/demo/root/.forge/www |(node:64397) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built dami/forge in 1s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.TecxQS/wt/demo/root/.forge/www |(node:64530) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built dami/greet in 1s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.TecxQS/wt/demo/root/.forge/www |(node:65195) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built - in 0s -> /var/folders/b4/mv8w4c8j0zj0_mldppxdbdw00000gn/T/forge-ci.TecxQS/wt/demo/root/.forge/www |226 of 226 pages render the same without 11ty |guide: 4 files, links ok |ok
Signature: good, cat
| M | README.md | 4 | +- |
| M | site/ | 2 | +- |
| M | site/ | 25 | +++++++---------- |
| M | site/ | 44 | ++++++++++++++---------------- |
| M | site/ | 1 | + |
| M | site/ | 2 | +- |
@@ -1242,11 +1242,11 @@ first build takes minutes.
12421242 12431243 ## Reading pages12441244 1245-The index and each owner's page show repos as cards on shelves by category,1245+The index and each owner's page show repos as rows on shelves by category,12461246 newest first. A repo's category is one line in the bare repo's `category`12471247 file, next to `description` (`printf 'games\n' > /srv/git/dami/greet.git/category`).12481248 A repo without one goes on the shelf for what Jev says it is (a web app, a1249-library), and failing that on "other". Chips above the shelves show one shelf1249+library), and failing that on "other". Links above the shelves show one shelf12501250 alone, only repos with a site, or sort by name.12511251 12521252 A review page reads top to bottom: the stack, the layer's commits, then each@@ -18,7 +18,7 @@ ol.comments { list-style: none; margin: 0; padding: 0; }
1818 .comment-head .date { font: 12px var(--mono); color: var(--muted); }1919 .comment-head .date time { font-size: 1em; }2020 .comment-head .rev { font: 12px var(--mono); color: var(--muted); }21-.comment .tag { font-size: 0.8em; font-weight: 600; color: var(--warn); border: 1px solid currentColor; padding: 0 7px; }21+.comment .tag { font: 600 10.5px var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--warn); }2222 .comment .quote { margin: 8px 12px 0; border: 1px solid var(--border); background: var(--raised); overflow: hidden; }2323 .comment .quote .where { padding: 3px 10px; font: 12px/1.6 var(--mono); border-bottom: 1px solid var(--border); overflow-wrap: anywhere; }2424 .comment .quote pre { margin: 0; padding: 4px 10px; font: 12.5px/1.5 var(--mono); white-space: pre-wrap; overflow-wrap: anywhere; tab-size: 4; }@@ -83,11 +83,7 @@
8383 .rv { position: relative; display: grid; grid-template-columns: auto 1fr auto; column-gap: 10px; row-gap: 3px; align-items: baseline; padding: 10px 8px; border-bottom: 1px solid var(--border); }8484 .rv:hover, .rv.sel { background: var(--hover); }8585 .rv.sel { box-shadow: inset 2px 0 0 var(--accent); }86-.rv-mark { grid-row: 1 / 3; align-self: start; width: 9px; height: 9px; margin-top: 6px; background: var(--muted); }87-.rv-mark.open { background: var(--pass); }88-.rv-mark.draft { background: none; box-shadow: inset 0 0 0 2px var(--muted); }89-.rv-mark.merged { background: var(--merged); }90-.rv-mark.closed { background: var(--fail); }86+.rv > .status { grid-row: 1; }9187 .rv-title { min-width: 0; font-weight: 600; overflow-wrap: anywhere; }9288 .rv-title a::after { content: ''; position: absolute; inset: 0; }9389 .rv-side { display: flex; gap: 12px; align-items: baseline; justify-content: flex-end; white-space: nowrap; font: 12.5px var(--mono); }@@ -99,23 +95,22 @@
9995 .rv-meta .del { color: var(--fail); }10096 .rv-meta a, .rv-side a { position: relative; z-index: 1; }10197 .rv.layer { margin-left: calc(var(--depth) * 22px); border-left: 1px solid var(--border); }102-a.rev { font-size: 0.85em; color: var(--muted); border: 1px solid var(--border); padding: 0 4px; }10398 .appr { white-space: nowrap; font-weight: 600; color: var(--pass); }10499 .appr + .appr { margin-left: 8px; }105100 .appr.stale { color: var(--warn); font-weight: normal; }106101 @media (max-width: 720px) {107102 .rv { grid-template-columns: auto 1fr; }108103 .rv-side { grid-column: 2; justify-content: flex-start; }109- .rv-meta { grid-column: 2; }104+ .rv-meta { grid-column: 1 / 3; }110105 .rv.layer { margin-left: calc(var(--depth) * 12px); }111106 }112107 {% endcss %}113108 {% set last = r.revisions[r.revisions.length - 1] %}114109 <li class="rv{% if depth %} layer{% endif %}"{% if depth %} style="--depth: {{ depth }}"{% endif %}>115-<span class="rv-mark {{ r.status }}" title="{{ r.status }}"></span>110+{{ status(r.status) }}116111 <span class="rv-title"><a href="{{ repo.urls.review(r.id).href }}">{{ r.title }}</a></span>117112 <span class="rv-side">{{ reviewci(r.ci) }}{% if r.approvals.length %}<span>{{ approvals(r) }}</span>{% endif %}</span>118-<span class="rv-meta"><span class="num">#{{ r.id }}</span><span class="mono">{{ r.branch }} → {{ r.target }}</span>{% if r.author %}<span>{{ r.author }}</span>{% endif %}{% if r.commits.length %}<span>{{ r.commits.length | plural('commit') }}</span>{% endif %}{% if r.combinedStats and (r.combinedStats.add or r.combinedStats.del) %}<span class="num"><span class="add">+{{ r.combinedStats.add }}</span> <span class="del">−{{ r.combinedStats.del }}</span></span>{% endif %}<span class="date">{{ r.updated | ago }}</span>{% if last and last.view %}<a class="rev" href="{{ repo.urls.revision(r.id, last.n).href }}" title="what changed since r{{ last.prev }}">r{{ last.n }}</a>{% endif %}</span>113+<span class="rv-meta"><span class="num">#{{ r.id }}</span><span class="mono">{{ r.branch }} → {{ r.target }}</span>{% if r.author %}<span>{{ r.author }}</span>{% endif %}{% if r.commits.length %}<span>{{ r.commits.length | plural('commit') }}</span>{% endif %}{% if r.combinedStats and (r.combinedStats.add or r.combinedStats.del) %}<span class="num"><span class="add">+{{ r.combinedStats.add }}</span> <span class="del">−{{ r.combinedStats.del }}</span></span>{% endif %}<span class="date">{{ r.updated | ago }}</span>{% if last and last.view %}<a href="{{ repo.urls.revision(r.id, last.n).href }}" title="what changed since r{{ last.prev }}">r{{ last.n }}</a>{% endif %}</span>119114 </li>120115 {% endmacro %}121116 @@ -139,16 +134,16 @@ a.rev { font-size: 0.85em; color: var(--muted); border: 1px solid var(--border);
139134 {% endmacro %}140135 141136 {# The index and owner pages: repos as rows on shelves by kind (the shelves142- filter), with chips that jump to a shelf. ui.ts makes the chips filters and137+ filter), with links (.chip) that jump to a shelf. ui.ts makes them filters and143138 adds "has a site" and the sort; keys.ts walks the cards with j and k. #}144139 {% macro shelves(repos, owners = false) %}145140 {% css %}146-.shelf-bar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 0 0 4px; }141+.shelf-bar { display: flex; flex-wrap: wrap; gap: 4px 18px; align-items: baseline; margin: 0 0 4px; }147142 .shelf-bar .grow { flex: 1; }148-.chip { font: inherit; font-size: 0.85em; color: var(--muted); background: none; border: 1px solid var(--border); padding: 2px 11px; cursor: pointer; white-space: nowrap; }149-.chip:hover { color: var(--fg); background: var(--hover); text-decoration: none; }150-.chip[aria-pressed="true"] { color: var(--fg); background: var(--hover); border-color: var(--faint); }151-.chip .n { color: var(--faint); margin-left: 4px; font-variant-numeric: tabular-nums; }143+.chip { font: inherit; font-size: 0.9em; letter-spacing: normal; text-transform: none; color: var(--link); background: none; border: 0; padding: 4px 0; cursor: pointer; white-space: nowrap; }144+.chip:hover { color: var(--deep); background: none; text-decoration: none; }145+.chip[aria-pressed="true"] { color: var(--fg); font-weight: 600; box-shadow: inset 0 -2px 0 var(--accent); }146+.chip .n { font: 11px var(--mono); color: var(--faint); margin-left: 5px; font-variant-numeric: tabular-nums; }152147 .shelf-head { display: flex; align-items: baseline; gap: 8px; margin: 26px 0 0; padding-bottom: 6px; border-bottom: 1px solid var(--border); scroll-margin-top: 12px; }153148 .shelf-head h2 { margin: 0; padding: 0; border: 0; }154149 .shelf-head .n { font: 600 11px var(--mono); color: var(--faint); }@@ -127,21 +127,19 @@ details.clone > summary::-webkit-details-marker { display: none; }
127127 details.clone .panel { position: absolute; right: 0; top: calc(100% + 6px); z-index: 10; width: min(440px, 92vw); background: var(--raised); border: 1px solid var(--border); padding: 10px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); }128128 .copyrow { display: flex; gap: 6px; align-items: center; margin: 4px 0; }129129 .clone-note { margin: 6px 0 0; font-size: 0.85em; color: var(--muted); }130-.private-mark { font-size: 0.75em; font-weight: 600; color: var(--warn); border: 1px solid currentColor; padding: 0 7px; vertical-align: 2px; }131-.private-mark:hover { text-decoration: none; }130+.private-mark { font: 600 10.5px var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--warn); vertical-align: 2px; }131+.private-mark:hover { color: var(--warn); }132132 .copyrow label { width: 44px; font: 600 10.5px var(--mono); letter-spacing: 0.08em; color: var(--faint); }133133 .copyrow input { flex: 1; min-width: 0; font: 13px var(--mono); padding: 4px 6px; border: 1px solid var(--border); background: var(--bg); color: var(--fg); }134134 button, .btn { font: inherit; font-size: 0.85em; color: var(--fg); background: var(--subtle); border: 1px solid var(--border); padding: 3px 10px; cursor: pointer; }135135 button:hover, .btn:hover { background: var(--hover); text-decoration: none; }136136 137-/* live status */138-#live { font-size: 0.8em; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40vw; }139-#live span::before { content: ''; display: inline-block; width: 7px; height: 7px; margin-right: 6px; vertical-align: 1px; }140-#live .live-on::before { background: var(--pass); }141-#live .live-off::before { background: var(--faint); }142-#live .live-busy { color: var(--warn); }143-#live .live-busy::before { background: var(--warn); animation: live-pulse 1s ease-in-out infinite alternate; }144-@keyframes live-pulse { to { opacity: 0.2; } }137+/* live status: words, no dot */138+#live { font: 11px var(--mono); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40vw; }139+#live .live-on { color: var(--pass); }140+#live .live-off { color: var(--faint); }141+#live .live-busy { color: var(--warn); animation: live-pulse 1s ease-in-out infinite alternate; }142+@keyframes live-pulse { to { opacity: 0.4; } }145143 146144 main.wrap { padding-top: 20px; padding-bottom: 40px; }147145 main.wrap > :first-child { margin-top: 0; }@@ -203,12 +201,13 @@ table.list tbody tr.sel td:first-child { box-shadow: inset 2px 0 0 var(--accent)
203201 .hide-sm { display: none; }204202 }205203 206-/* statuses and CI */207-.status { font-weight: 600; white-space: nowrap; }208-.status.open { color: var(--pass); }209-.status.draft { color: var(--muted); }210-.status.merged { color: var(--merged); }211-.status.closed { color: var(--fail); }204+/* statuses and CI. A review's status is the one filled shape: a small205+ square label, white on the status colour (the same in both modes, so the206+ white stays readable). */207+.status { display: inline-block; font: 600 10px/1.5 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: #fff; background: #5b6169; padding: 0 6px; white-space: nowrap; vertical-align: 1px; }208+.status.open { background: #0e8420; }209+.status.merged { background: #3148f6; }210+.status.closed { background: #c7162b; }212211 .ci { white-space: nowrap; font-weight: 600; }213212 .ci[title] { cursor: help; }214213 .ci.pass { color: var(--pass); }@@ -371,18 +370,17 @@ details.att pre, details.howto pre { white-space: pre-wrap; overflow-wrap: anywh
371370 .markdown h2 { font-size: 1.25em; }372371 }373372 /* jev: commits and repos */374-.jev-kind, .jev-topic { display: inline-block; padding: 0 6px; border: 1px solid var(--border); font-size: 0.75rem; line-height: 1.5; font-weight: 500; color: var(--muted); white-space: nowrap; vertical-align: 1px; }375-.jev-kind.feat { color: var(--pass); }376-.jev-kind.fix { color: var(--merged); }373+/* What Jev says a commit or a repo is: plain words, quiet. */374+.jev-kind { font: 12px var(--mono); color: var(--muted); white-space: nowrap; }375+.jev-topic { color: var(--muted); white-space: nowrap; }377376 /* Jev's risk score, 0 to 3: a small number, colored once it is moderate. */378-.jev-score { font-size: 0.8rem; font-variant-numeric: tabular-nums; color: var(--faint); white-space: nowrap; }377+.jev-score { font: 12px var(--mono); font-variant-numeric: tabular-nums; color: var(--faint); white-space: nowrap; }379378 .jev-score.moderate { color: var(--warn); }380379 .jev-score.high { color: var(--fail); font-weight: 600; }381380 .jev-mismatch { font-size: 0.85em; color: var(--faint); cursor: help; }382381 .jev-note { font-size: 0.8rem; font-style: italic; color: var(--faint); }383382 /* The log: Jev's type in a narrow column on the left. */384383 table.log th.kind, table.log td.kind { width: 1%; white-space: nowrap; padding-right: 4px; }385-table.log td.kind .jev-kind { vertical-align: 0; }386384 table.log td.risk { width: 1%; }387385 @media (max-width: 720px) {388386 /* Stacked: the type leads the line under the subject. */@@ -400,8 +398,8 @@ table.log td.risk { width: 1%; }
400398 .notes summary:hover { color: var(--fg); }401399 402400 /* jev: review pages */403-.jev-mech, .jev-change { display: inline-block; padding: 0 6px; border: 1px dashed currentColor; font-size: 0.75rem; line-height: 1.5; font-weight: 500; color: var(--muted); white-space: nowrap; }401+.jev-mech, .jev-change { font: 12px var(--mono); color: var(--muted); white-space: nowrap; }404402 .jev-change.behavior, .jev-sum.behavior { color: var(--warn); }405403 .jev-sum { font-size: 0.9em; color: var(--muted); }406404 summary .jev-sum { margin-left: 6px; font-weight: normal; }407-.comment .tag.jev-addressed { color: var(--pass); border-style: dashed; }405+.comment .tag.jev-addressed { color: var(--pass); }@@ -17,6 +17,7 @@ pagination:
1717 .cmt-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; padding: 8px 12px 0; font-size: 0.9em; }1818 .cmt-head a, .cmt-head .date { font: 12px var(--mono); }1919 .cmt-head time { font-size: 1em; }20+.cmt-head .tag { font: 600 10.5px var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--warn); }2021 .cmt-head a { color: var(--muted); }2122 .cmt .markdown { padding: 4px 12px 8px; font-size: 0.95rem; line-height: 1.55; }2223 .cmt .markdown > :last-child { margin-bottom: 0; }@@ -11,7 +11,7 @@ pagination:
1111 {% block content %}1212 {% css %}1313 /* range-diff: a block per pair of commits */14-.pk { font-size: 0.75em; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; padding: 0 5px; border: 1px solid currentColor; }14+.pk { font: 600 10.5px var(--mono); text-transform: uppercase; letter-spacing: 0.08em; }1515 .pk.same { color: var(--muted); }1616 .pk.changed { color: var(--warn); }1717 .pk.add { color: var(--add-fg); }