~/ klt.codes
v0.3.2 · Tampa, FL
project retros

What each milestone shipped, and why.

Project-level retros, written at milestone close. Sanitized for public reading. The sequence reads as the platform's actual evolution.

RETRO · 260511
2026-05-09 — 2026-05-11

Personal site — work-page IA + contact-form spam mitigation

Reframed /work/ around kinds-of-engagement instead of nine vague rows, and layered real spam rejection underneath the contact form's existing proof-of-work — honeypot, min-fill-time, DNSBL, and content rules — without removing the cost layer. Three PRs in a single operator-day, plus a release tagged with the retro and operator review bundled into the same commit.

shipped

Work page rebuilt as four category cards (AI-operated software delivery, AI-era security & governance, platform engineering & client delivery, independent / IP-heavy product work), each linking the existing per-project pages as examples — #108, PR #111; contact form layered with real spam-rejection on top of the cost-only PoW: hidden honeypot field, min-fill-time gate via eager page-load challenge fetch + minimum five-second submit delay, Spamhaus ZEN DNSBL at challenge issuance with fail-open behaviour, content rules covering URL-count cap, keyword deny-list, and a byte-level UTF-8 non-Latin ratio threshold — #109, PR #112; operator microcopy pass on /aboutme and /contact pages — tightened the early-career timeline (NYC basement, not Tampa bedroom), reordered the relationship line, trimmed the outro to the three-Ds frame, replaced the inbox-as-platform contact subhead with a sharper anti-bot framing — PR #113.

decisions

Card layout chosen over a denser section-list for /work, picked from a previewed A/B at the start of the session; the section-list was closer to the current dense-terminal aesthetic but couldn't carry the visual separation the four-kinds framing needed. Spam-mitigation scope landed at honeypot + min-fill + DNSBL + content-rules; the alternative was adding an LLM-judge layer up front at roughly $0.0001 per message, but the conventional anti-spam stack went in first as the layer-one rejection floor, deferring LLM-judge until something actually slips through. Eager challenge fetch — issuing the HMAC challenge on page load instead of submit click — was required for the min-fill gate to measure actual form-fill duration, which in turn forced KLTC_CHALLENGE_TTL up from 5min to 30min so an idle tab survives the longer window between issuance and submit; a small architectural shift behind a small-looking spam control. Auto-mode classifier denial of legitimate skill-gate generation was surfaced and resolved mid-session via an autoMode.allow rule scoped to the exact platform-skill-gate command pattern; the new tradeoff was documented in agent memory so the next session inherits the fix rather than rediscovers it. Release-flow chicken-and-egg between /review and milestone closure was named before kicking off, leading to a procedural override — run /review first to land the retro and operator review with the version bump, then close the milestone manually with the skill's auto-/review step skipped — rather than blindly invoking the close skill and ending up with a duplicate retro.

bottom line

Meta-process attention paid for itself twice this sprint — once when an over-matched memory rule blocked a legitimate skill flow and the fix was a scoped allow rule rather than a memory edit, and once when the operator paused before triggering milestone closure to name the duplicate-/review loop before it ran. Both moves were the same shape: spot the tooling self-loop before it executes, override at the right layer, write the rule down so the next session inherits it.

RETRO · 260508
2026-05-08

Personal site — operational closeout

Closing out the public-cutover milestone's operational tail in a single session: operator runbook, mobile-responsive pass, credential-rotation workflow, cert-renewal cadence, and unblocking the non-public tier's cert validation. Multiple changes merged in one operator-day; the release tag held until end-of-sprint to bundle the page-asset refresh into the same prod deploy.

shipped

Operator runbook for the public-prod surface (per-operator file, not committed); mobile-responsive layout pass — clamp-sized headings, stacked grids under tablet portrait, terminal block scrolls inside its container instead of breaking the outer layout; leak-proof credential-rotation script — operator-only setters use hidden-input prompts piped to the secret store and pushed via shell stdin; agent-safe verification commands return only structural status, never values; cert-renewal cadence corrected after discovering the public host's cert pipeline differs from the standard ACME pattern; non-public tier cert validation unblocked by separating the gate config into a parent file the host UI can manage and a nested path-bypass file that allows validation challenges through; small content addition — a few credentials added to the resume and a /log post framing them as substrate fluency rather than a pivot.

decisions

Closed the cert-renewal-cadence issue with forward-dated verification rather than holding it open until the next renewal window — the durable mechanism is the runbook plus calendar reminder, not the issue tracker. Refactored the gate config from a complex one-file form to a two-file structure when the host's configuration UI couldn't manage the original; UI shape is opinionated and fixed, separating concerns is cheaper than fighting it. Held the release tag for end-of-sprint after the page-asset refresh, rather than cutting incrementally — one coherent prod deploy is worth more than three near-deploys. Named a third-party-host pipeline as 'not the standard ACME shape' once and made it durable, after the wrong assumption cost a debug iteration.

bottom line

The operator’s role expanded this period from merge-gate-reviewer to runtime-agent-supervisor — agent boundary violations named at the moment they happen, not at code review.

RETRO · 260507
2026-05-07

Personal site — polish pass + first public cutover

Two milestones in one operator-day. Morning: a polish pass on the prior build — stale-content purge, layout fix, version-label cleanup, a hard route rename, portability-driven copy revisions. Afternoon to evening: the site went public for the first time, with a hardened, dependency-free contact form.

shipped

Polish pass: stale-content purge across home and work pages; resume layout fix; version-label cleanup so it tracks the site rather than the underlying platform; a hard route rename; portability-driven copy revisions; a small process-tooling iteration applied to its first artifact in the same sprint. Cutover: hardened contact form with server-side proof-of-work, replay block, and per-network rate limit; deploy workflow expanded to all three tiers with auth gates on the non-public ones; site went public end-to-end including the contact form.

decisions

Stateless server-side spam mitigation chosen over a stateful pattern, driven by the public host's constraints. Dependency-free server-side primitives chosen over a vendored library — same audit-visibility posture used for deployment boundaries earlier, applied this time to a security boundary. Manual workflow trigger added when a third-party service issue blocked validation on the non-public tiers. Closed the cutover milestone with non-public tiers unvalidated end-to-end — the public-facing tier was verified live, and the non-public tiers are a redundancy not a gate.

bottom line

Two milestones, same shape — the convention-naming-as-architecture pattern landed again, this time applied to a security boundary instead of a deployment one.

RETRO · 260506
2026-05-06

Personal site — design system port

Ported the V2 design handoff into the site and replaced the previous build as primary. The most significant event was the mid-promotion discovery that the higher-tier environments had been provisioned in name but never wired for the site, which forced an environment-naming convention into existence that now applies to every future tenant.

shipped

Full V2 route set live, replacing the prior build; design system port (tokens, theme, shell, accent palette, content collections); site search; tag filtering on the log; SEO basics; minimal-disclosure contact page with a client-side proof-of-work UI; prior version preserved at a stable historical URL; sanitised resume download; environment-prefixed hostnames with per-tier overlays; release cut and the internally-reviewable tier live.

decisions

Stateless server-side spam mitigation chosen over a stateful backend, driven by the constraints of the eventual public host. Deploy-tier model named explicitly. Milestone split mid-sprint, with the public-prod work deferred to its own milestone. Environment-prefix hostname convention adopted. CI breakage worked around manually for a routine change; the CI fix itself filed as visible debt.

bottom line

The visible delivery was the design system port. The invisible delivery was the environment-naming convention — the second milestone in a row where a personal-site sprint produced reusable platform structure under operator architectural pressure.

RETRO · 260430
2026–04–30

Personal site & static-hosting service

A small site shipped end-to-end on a single day, but the gravitational mass of the work sat in the platform underneath. Building this surfaced 'no per-site image per content change' as a hard requirement, which triggered the construction of a generalized static-hosting service the same session.

shipped

Site live (5 pages + RSS); shared nginx with dev/uat/prod overlays; runner-driven deploy via SSH+rsync; orchestrator identity provisioned mid-flow.

decisions

CMS rejected for a 4-page showcase. Per-image-rebuild rejected. Static-hosting built as a multi-tenant service. Platform service gets dev/uat/prod, not just per-site content.

bottom line

The site itself is what the milestone said it would be. The platform underneath is materially better than it was 24 hours earlier.

RETRO · 260429
2026–04–15 → 2026–04–29

v0.7.0 platform release + first client engagement

The largest sprint in the platform's history, running in parallel with the first paying client engagement under a brand-new architectural model. Both closed the same day.

shipped

541 merged PRs across six repos in 15 days. Multi-layer code-review pattern, docs-agent quality gate, cross-repo reconciliation, ADR capturing the architectural pivot.

decisions

Multi-tenancy retired in favor of solo-agency model. Per-change fanout rejected in favor of cron reconciliation. Docs-monorepo redesign caught before ship.

bottom line

92.6% of write traffic was AI-authored; operator role was direction-setting and merge-gating. The merge-gate function held under volume.

RETRO · 260414
2026–04–10 → 2026–04–14

Persistent-memory infrastructure + chain-wiring bug fixes

Mid-sprint focus on the unglamorous fixes that compound: persistent memory loaded into every session, synthetic chain runs catching wiring bugs that unit tests didn't.

shipped

Six independent chain-wiring bugs fixed. Persistent-memory file pattern. Naming convention for recurring patterns.

decisions

Memory loading is infrastructure, not documentation. Unit tests do not catch chain bugs; end-to-end runs do.

bottom line

Highest-leverage fix of the period was the boring one: every session reads structured memory at load time.

RETRO · 260413
2026–04–13

Multi-repo state coordination

Six PRs across four repos, sequenced in dependency order, merged without explicit ordering prompts. Confirmed the operator pattern for multi-repo orchestration.

shipped

Cross-repo state changes that previously required explicit ordering now flow naturally.

decisions

Identity-naming is an architectural skill, not a process step.

bottom line

Confirmed reproducible pattern. Documented for future onboardings.

RETRO · 260412
2026–04–12

Static-hosting pattern decision

Rejected a working pattern that, at scale, would have become a tax on every future engagement. Replaced with a generalized service.

shipped

Architecture decision; preliminary scaffolding for the new pattern.

decisions

Per-image rebuild for content changes is rejected as the canonical client-onboarding pattern.

bottom line

The visible cost of the pivot was a cleanup. The real cost — had we accepted the original pattern — would have been every future engagement paying the wiring tax.

RETRO · 260408
2026–04–08

Architectural reconsideration over workaround

A bug surfaced. The proposed fix was a one-off. The bug was actually the symptom of an underlying pattern. The architectural change retired the bug class.

shipped

ADR capturing the decision and the alternatives considered.

decisions

When a fix is a workaround, the fix is not done. The right fix is whatever retires the class.

bottom line

ADRs are commitments. The commitment is to the class fix, not the symptomatic one.