From 52d4301ba3e0b7c86900ebeb21375ea05a7fb1f0 Mon Sep 17 00:00:00 2001 From: Eugene Mutembei <103780583+CodeWithEugene@users.noreply.github.com> Date: Mon, 28 Sep 2026 19:59:03 +0300 Subject: [PATCH 1/3] chore: stop tracking the local .claude directory --- .claude/.proven-config-version | 1 - .claude/launch.json | 11 --------- .claude/proven-config.json | 42 ---------------------------------- .gitignore | 3 +++ 4 files changed, 3 insertions(+), 54 deletions(-) delete mode 100644 .claude/.proven-config-version delete mode 100644 .claude/launch.json delete mode 100644 .claude/proven-config.json diff --git a/.claude/.proven-config-version b/.claude/.proven-config-version deleted file mode 100644 index dbdc100..0000000 --- a/.claude/.proven-config-version +++ /dev/null @@ -1 +0,0 @@ -sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319 \ No newline at end of file diff --git a/.claude/launch.json b/.claude/launch.json deleted file mode 100644 index e4adc5c..0000000 --- a/.claude/launch.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "version": "0.0.1", - "configurations": [ - { - "name": "hackvillage-dev", - "runtimeExecutable": "pnpm", - "runtimeArgs": ["run", "dev", "--port", "3001"], - "port": 3001 - } - ] -} diff --git a/.claude/proven-config.json b/.claude/proven-config.json deleted file mode 100644 index 47fc170..0000000 --- a/.claude/proven-config.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "adoptedAt": 1790236604980, - "championId": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319", - "manifest": { - "schema": "ruflo.proven-config/v1", - "policy": { - "ref": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319", - "value": { - "alpha": 0.3, - "subjectWeight": 1, - "mmrLambda": 0.5, - "bodyWeight": 1.5, - "typePenaltyFactor": 0.5 - } - }, - "layer": "framework/node-cli", - "compatibility": { - "ruflo": ">=3.24.0" - }, - "benchmark": { - "corpus": "ADR-081-labelled-v1", - "corpusHash": "sha256:2f700b5c363e20a3bd88ce2bc9b87bbbbaa61732c6177894c6ec37890f888982" - }, - "receipt": { - "heldOutDelta": 0.07381404928570845, - "redblue": "PASS", - "drift": 0, - "canary": { - "rollbackRate": 0, - "latencyP95": 244.612458000076, - "costPerTask": 0 - }, - "receiptCoverage": 1 - }, - "platform": [ - "linux", - "macOS", - "windows" - ] - }, - "previous": "" -} \ No newline at end of file diff --git a/.gitignore b/.gitignore index df08d10..6600e5a 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,6 @@ next-env.d.ts # claude-flow local tooling data .claude-flow/ + +# Claude Code local settings (per-machine, never committed) +.claude/ From ca5bc371703f78ed0b797213e2bad24a432cddb2 Mon Sep 17 00:00:00 2001 From: Eugene Mutembei <103780583+CodeWithEugene@users.noreply.github.com> Date: Mon, 28 Sep 2026 20:08:46 +0300 Subject: [PATCH 2/3] style(ui): rule the blog grid into shared-line cells, center the footer partnership on mobile --- app/globals.css | 37 +++++++++++++++++------- components/patterns/site-footer.tsx | 44 ++++++++++++++++++++--------- 2 files changed, 57 insertions(+), 24 deletions(-) diff --git a/app/globals.css b/app/globals.css index 7ebc94b..756b415 100644 --- a/app/globals.css +++ b/app/globals.css @@ -905,25 +905,33 @@ color: var(--color-ink); } - /* Blog (app/(marketing)/blog, components/patterns/blog-card.tsx). */ + /* Blog (app/(marketing)/blog, components/patterns/blog-card.tsx). + Posts sit in a ruled band: it runs out to the frame's side rules and the + cells share hairlines (right and bottom), like the landing page grids. */ .blog-grid { + --blog-line: color-mix(in srgb, var(--color-ink) 10%, transparent); + --blog-cols: 3; display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 16px; + grid-template-columns: repeat(var(--blog-cols), minmax(0, 1fr)); + margin-inline: calc(-1 * var(--lp-gutter, 0px)); + border-top: 1px solid var(--blog-line); } .blog-card { display: flex; height: 100%; flex-direction: column; overflow: hidden; - border: 1px solid color-mix(in srgb, var(--color-ink) 10%, transparent); - border-radius: var(--radius-card); + border-right: 1px solid var(--blog-line); + border-bottom: 1px solid var(--blog-line); background: var(--color-surface); - transition: border-color 200ms ease, box-shadow 200ms ease; + transition: background-color 200ms ease; + } + /* The last cell in each row leans on the frame's own side rule. */ + .blog-grid > .blog-card:nth-child(3n) { + border-right-color: transparent; } .blog-card:hover { - border-color: color-mix(in srgb, var(--color-brand) 45%, transparent); - box-shadow: var(--shadow-card); + background: color-mix(in srgb, var(--color-brand) 5%, var(--color-surface)); } .blog-back { display: inline-flex; @@ -953,12 +961,21 @@ } @media (max-width: 1023px) { .blog-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); + --blog-cols: 2; + } + .blog-grid > .blog-card:nth-child(3n) { + border-right-color: var(--blog-line); + } + .blog-grid > .blog-card:nth-child(2n) { + border-right-color: transparent; } } @media (max-width: 639px) { .blog-grid { - grid-template-columns: minmax(0, 1fr); + --blog-cols: 1; + } + .blog-grid > .blog-card:nth-child(n) { + border-right-color: transparent; } } diff --git a/components/patterns/site-footer.tsx b/components/patterns/site-footer.tsx index 7ee9b2f..07df1fa 100644 --- a/components/patterns/site-footer.tsx +++ b/components/patterns/site-footer.tsx @@ -57,6 +57,27 @@ const FOOTER_SECTIONS: { title: string; links: { label: string; href: string }[] const LINK_CLASS = "text-sm text-body-copy transition-colors hover:text-ink"; +function Partnership() { + return ( + <> +

In partnership with:

+ + {/* eslint-disable-next-line @next/next/no-img-element -- SVG wordmark, no raster source */} + Salamander Tech Hub + + + ); +} + export function SiteFooter() { const year = new Date().getFullYear(); @@ -149,20 +170,15 @@ export function SiteFooter() { -

In partnership with:

- - {/* eslint-disable-next-line @next/next/no-img-element -- SVG wordmark, no raster source */} - Salamander Tech Hub - +
+ +
+ + + {/* Mobile: the partnership gets its own centered row under the columns + (lg keeps it at the foot of "Contact Us"). */} +
+
From 77814737740b41098583676de14a9f385c15d02c Mon Sep 17 00:00:00 2001 From: Eugene Mutembei <103780583+CodeWithEugene@users.noreply.github.com> Date: Mon, 28 Sep 2026 20:09:06 +0300 Subject: [PATCH 3/3] ci: reject AI co-author trailers in commit messages --- commitlint.config.mjs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/commitlint.config.mjs b/commitlint.config.mjs index 521776d..906dbb6 100644 --- a/commitlint.config.mjs +++ b/commitlint.config.mjs @@ -1,10 +1,26 @@ // Conventional Commits per CONTRIBUTING.md — scopes from the documented set. // Scope is optional for repo-level commits (docs:, chore:); when present it // must come from the enum. +// Commits are authored by the maintainers alone: AI tools are never credited as +// co-authors (GitHub would list them as repo contributors), so the trailer an +// assistant suggests by default fails CI instead of slipping into a squash merge. +const AI_COAUTHOR = /^co-authored-by:.*(claude|anthropic)/im; + /** @type {import('@commitlint/types').UserConfig} */ export default { extends: ["@commitlint/config-conventional"], + plugins: [ + { + rules: { + "no-ai-coauthor": ({ raw }) => [ + !AI_COAUTHOR.test(raw ?? ""), + "remove the AI Co-authored-by trailer: maintainers are the only authors", + ], + }, + }, + ], rules: { + "no-ai-coauthor": [2, "always"], "scope-enum": [ 2, "always",