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
22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,28 @@ jobs:
key: qmd-models-v1
- run: npx vitest run

e2e:
name: E2E Tests
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '24'
- run: npm install
- name: Cache qmd models
uses: actions/cache@v4
with:
path: ~/.cache/qmd/models
key: qmd-models-v1
# qmd refuses LLM ops when CI=true; node-llama-cpp rejects empty CI via
# env-var.asBool. Unset CI so both see it as absent (qmd default: enabled,
# node-llama-cpp default: "false").
- run: |
unset CI
npx vitest run --config vitest.e2e.config.ts

install-npm-global:
name: Test npm global install
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ coverage

# logs
logs
!test/e2e/corpus/logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json

Expand Down
39 changes: 39 additions & 0 deletions test/e2e/corpus/logs/cooking-diary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: Cooking Diary
created: 2024-01-01T08:00:00.000Z
modified: 2024-03-01T08:00:00.000Z
tags: ["cooking", "diary"]
type: log
---

## 2024-02-27T19:30:00.000Z {#e-c001000000000001}

Made carbonara tonight — proper Roman style with guanciale and pecorino romano. The sauce broke the first attempt because I added the egg mixture while the pan was still on high heat. Started over, removed the pan from the heat, let it cool for a minute, then added the egg-pecorino paste with a splash of pasta water. Tossed vigorously — silky and coating. The guanciale was key; pancetta I tried last month didn't have the same fat quality or depth of flavor.

## 2024-02-22T20:00:00.000Z {#e-c001000000000002}

Third attempt at sourdough this week. Finally nailed the bulk fermentation timing — 4.5 hours at 74°F kitchen temperature. The dough doubled and had visible bubbles on the surface. Shaping has improved; the banneton left a nice pattern. Baked in the Dutch oven: 500°F covered 20 minutes, then 450°F uncovered 22 minutes. The crust crackled as it cooled. Open crumb — probably 75% hydration was right for this flour.

## 2024-02-16T19:00:00.000Z {#e-c001000000000003}

Beef stock from roasted bones. Used knuckle bones and marrow bones, roasted at 425°F for 50 minutes — they came out a deep mahogany. Deglazed the pan to get the fond. Simmered for 8 hours with mirepoix, parsley stems, and bay leaves. Skimmed foam three times. Strained through cheesecloth. The stock set to a very firm jelly in the fridge. Concentrated, rich, and slightly gelatinous — exactly right.

## 2024-02-10T18:30:00.000Z {#e-c001000000000004}

Tried sous vide strip steak for the first time. Set the bath to 131°F for 2 hours. Finished in a screaming hot cast iron skillet with clarified butter for 60 seconds per side. Crust was beautiful but I should have dried the steak more thoroughly after the bath — there was a bit of steaming before the Maillard reaction took hold. The interior was perfectly edge-to-edge medium-rare. No grey band at all.

## 2024-02-04T20:00:00.000Z {#e-c001000000000005}

Knife skills practice — julienne carrots and zucchini. My julienne strips are still uneven (2–4mm range). The issue is the guiding hand: my knuckles aren't staying consistent. Need to be more conscious of the spacing. The cuts on the zucchini looked better than the carrots because the zucchini is softer and more forgiving. Will practice this every Sunday until it's automatic.

## 2024-01-28T19:30:00.000Z {#e-c001000000000006}

Chicken stock attempt. Used a carcass from a roasted chicken plus extra backs and necks. Did not roast this time — made a white stock. Brought to a simmer slowly and skimmed extensively. Simmered 4 hours. The stock has good body (gelatinous) and clean flavor. Better than my previous attempts where I boiled rather than simmered — that produced a greasy, cloudy result.

## 2024-01-20T13:00:00.000Z {#e-c001000000000007}

Practiced sourdough scoring — the slash before baking that controls oven spring direction. Used a lame (razor blade on a stick) at a 30-degree angle to the surface rather than perpendicular. The ear rose beautifully. Previous loaves had flat, blunt scores because I was holding the blade straight up. The angled slash creates an overhang that lifts as a flap during the steam phase.

## 2024-01-15T20:00:00.000Z {#e-c001000000000008}

Experimented with pasta dough hydration. Standard recipe is 100g 00 flour to 1 egg yolk. Tried adding a tablespoon of olive oil — the pasta was silkier but harder to roll thin without tearing. Reverted to the simpler recipe. Also tried the Marcella Hazan approach of 100g flour to 1 whole egg (no oil): slightly stiffer dough, rolled out fine to pasta sheets, held up better in the boiling water.
47 changes: 47 additions & 0 deletions test/e2e/corpus/logs/dev-journal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
title: Dev Journal
created: 2024-01-01T08:00:00.000Z
modified: 2024-03-01T08:00:00.000Z
tags: ["dev", "journal"]
type: log
---

## 2024-02-28T14:00:00.000Z {#e-d001000000000001}

Traced a subtle Rust lifetime bug today. The issue was that a reference to a temporary was being held across an await point. The fix was to clone the value before the async block. Lifetimes and async in Rust interact in non-obvious ways because the compiler cannot allow references to live in the state machine across suspension points if they point to stack memory that may not exist when the task resumes.

## 2024-02-25T10:00:00.000Z {#e-d001000000000002}

Spent the morning profiling a slow database query. The culprit was a missing index on the foreign key column in a JOIN. Adding the index dropped query time from 800ms to 12ms. EXPLAIN ANALYZE in PostgreSQL is invaluable — always run it before assuming you know where the bottleneck is.

## 2024-02-20T09:30:00.000Z {#e-d001000000000003}

Learned about Go's `sync.Map` today. It is designed for cases where entries are written once and read many times, or when goroutines access disjoint keys. For most use cases, a regular map with a `sync.RWMutex` is simpler and more flexible. The sync.Map documentation explicitly says it should not be used as a general-purpose concurrent map replacement.

## 2024-02-15T16:00:00.000Z {#e-d001000000000004}

Debugged a race condition in a Node.js service. Two async functions were both checking-and-then-setting a value in Redis without a lock. The fix was a Lua script in Redis that performs the check-and-set atomically. Redis processes Lua scripts in a single-threaded atomic operation — no interleaving is possible.

## 2024-02-10T11:00:00.000Z {#e-d001000000000005}

Explored WebAssembly (Wasm) for running compute-intensive code in the browser. The main insight: Wasm does not automatically make code faster than JavaScript for most tasks. It shines when: (1) porting existing C/C++/Rust code, (2) running tight numeric loops that the JS JIT cannot optimize as well, (3) avoiding GC pauses in latency-sensitive code.

## 2024-02-05T13:00:00.000Z {#e-d001000000000006}

Investigated CSS container queries. Unlike media queries that respond to the viewport, container queries respond to the parent container's size. This makes reusable components truly self-contained — the component adapts to its context, not the global viewport. Browser support is now strong enough for production use.

## 2024-01-30T09:00:00.000Z {#e-d001000000000007}

Learned that Python's `asyncio.gather` runs coroutines concurrently but not in parallel (still single-threaded). For CPU-bound work, you need `ProcessPoolExecutor` via `loop.run_in_executor`. The distinction between concurrency (managing multiple tasks) and parallelism (running them simultaneously on multiple cores) is often blurred in Python documentation.

## 2024-01-25T14:30:00.000Z {#e-d001000000000008}

Discovered the `git bisect` command properly today. Binary search through commits to find the one that introduced a bug. Start with `git bisect start`, mark the bad commit, mark a known good commit, and then run your test script. Git checks out the midpoint commit each time. Saves enormous time compared to manually checking commits.

## 2024-01-20T10:00:00.000Z {#e-d001000000000009}

Explored eBPF for observability. Linux's eBPF allows attaching small sandboxed programs to kernel events (system calls, network packets, function calls) without kernel modules or reboots. Tools like Cilium, Falco, and bpftrace are built on it. The main limitation is the verifier — programs must be provably terminating and memory-safe.

## 2024-01-15T08:00:00.000Z {#e-d001000000000010}

Fixed a memory leak in a C++ application. The issue was a `shared_ptr` cycle: object A held a `shared_ptr` to B, and B held a `shared_ptr` back to A. Neither reference count ever reached zero. The fix was to make one of the back-pointers a `weak_ptr`. The `weak_ptr` does not increment the reference count and must be promoted to `shared_ptr` before use.
39 changes: 39 additions & 0 deletions test/e2e/corpus/logs/reading-log.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: Reading Log
created: 2024-01-01T08:00:00.000Z
modified: 2024-03-01T08:00:00.000Z
tags: ["reading", "books"]
type: log
---

## 2024-02-20T20:00:00.000Z {#e-r001000000000001}

**The Art of Doing Science and Engineering** — Richard Hamming. A series of lectures on how to have a great career in technical fields. The central argument: you need to study successes more than failures, develop good taste in problems, and work on important problems rather than merely tractable ones. The chapter on learning to learn is the most practically useful. Hamming argues that the way you think about a problem determines what solutions you can find — changing your mental model is more powerful than adding information.

## 2024-02-12T21:00:00.000Z {#e-r001000000000002}

**Thinking, Fast and Slow** — Daniel Kahneman. The dual-process theory of cognition: System 1 (fast, automatic, heuristic) and System 2 (slow, deliberate, analytical). Most interesting to me was the section on cognitive biases as features rather than bugs — they are energy-saving heuristics that fail under specific conditions. The chapter on anchoring has permanently changed how I approach salary negotiations and pricing.

## 2024-02-05T19:30:00.000Z {#e-r001000000000003}

**A Pattern Language** — Christopher Alexander. A catalog of architectural and urban design patterns at every scale — from room proportions to city streets. Alexander argues that certain spatial configurations repeatedly produce buildings and places that feel alive and comfortable to humans, and these are not a matter of taste but of objective measurable qualities. The concept of pattern languages directly inspired the software design patterns movement. A beautiful and unusual book.

## 2024-01-28T20:00:00.000Z {#e-r001000000000004}

**The Design of Everyday Things** — Don Norman. The seminal book on affordances, signifiers, and feedback loops in product design. The central insight: when something is hard to use, the fault is almost always the design, not the user. Every bad UI I encounter now has a Norman critique attached to it in my head. Conceptual models and the gulf of evaluation/execution are frameworks I use constantly.

## 2024-01-20T19:00:00.000Z {#e-r001000000000005}

**The Pragmatic Programmer** — Hunt and Thomas. One of the books that shaped how I think about software craftsmanship. The DRY principle, tracer bullets, broken windows — all from here. The most lasting idea: your career is your responsibility, not your employer's. Invest in your skills deliberately. Re-reading it now reveals how much I had absorbed without knowing where it came from.

## 2024-01-12T21:00:00.000Z {#e-r001000000000006}

**Range** — David Epstein. A counterargument to the 10,000-hour rule and early specialization. Epstein argues that breadth of experience — especially early in a career — produces better long-term outcomes in complex, "wicked" learning environments where feedback is delayed and rules change. Tiger Woods-style early specialization works in well-defined domains; most of life is a kind of-learning environment where range is an advantage.

## 2024-01-05T20:30:00.000Z {#e-r001000000000007}

**Hackers and Painters** — Paul Graham. A collection of essays on creativity, programming, and startups. The essay "Beating the Averages" is the famous Lisp advocacy piece. The most interesting essay for me was "How to Make Wealth" — the argument that startups are a compressed way to do decades of economic value creation in a few years. Worth reading for the intellectual honesty even where you disagree with the conclusions.

## 2024-01-02T19:00:00.000Z {#e-r001000000000008}

**Why We Sleep** — Matthew Walker. A comprehensive case for the importance of sleep backed by neuroscience. The most alarming finding: sleeping less than 6 hours per night for two weeks produces cognitive impairment equivalent to 24 hours of total sleep deprivation, but subjects rate themselves as only slightly impaired. We are catastrophically bad at self-assessing sleep deprivation. The sections on memory consolidation during slow-wave and REM sleep were new to me and changed how I think about when to study.
47 changes: 47 additions & 0 deletions test/e2e/corpus/logs/workout-log.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
title: Workout Log
created: 2024-01-01T08:00:00.000Z
modified: 2024-03-01T08:00:00.000Z
tags: ["fitness", "workout"]
type: log
---

## 2024-02-29T07:00:00.000Z {#e-w001000000000001}

Long run: 18 miles at easy pace (9:30/mile average). Felt strong through mile 14, then the usual fatigue hit. Took two gels at miles 7 and 13. Hip flexors tight at the end — need to stretch more consistently. Weather was cold (38°F) and windy; wore a light jacket and gloves. Recovery drink immediately after. Legs feel heavy but not damaged.

## 2024-02-26T06:30:00.000Z {#e-w001000000000002}

Strength session — lower body focus. Deadlifts: 5×5 at 225 lbs. Hip hinge felt solid, kept the bar close throughout. Moved to Romanian deadlifts 3×10 at 155 lbs for hamstring isolation. Finished with Bulgarian split squats 3×8 each leg at bodyweight — balance is improving. No lower back discomfort during or after. PR on the conventional deadlift last week was 265 lbs, this week maintaining volume.

## 2024-02-22T07:30:00.000Z {#e-w001000000000003}

Tempo run: 8 miles with 5 miles at marathon goal pace (8:00/mile). Used a heart rate monitor — aerobic threshold is around 155 bpm for me. Held 152–158 bpm through the tempo section, which felt controlled but uncomfortable. Warm-up and cool-down 1.5 miles each at easy pace. Legs felt springy; good session overall.

## 2024-02-18T11:00:00.000Z {#e-w001000000000004}

Yoga session — 60 minutes of Vinyasa flow. Sun salutations to warm up, then held warrior sequences and pigeon pose for 2 minutes each side. Chaturanga has improved significantly; no longer collapsing in the shoulders. The instructor cued to engage the serratus anterior — I could feel the difference immediately. Hip flexors loosened considerably by the end.

## 2024-02-14T07:00:00.000Z {#e-w001000000000005}

Track workout: 6×800m at 5k pace (3:30 each), 90-second recovery between intervals. Splits: 3:28, 3:31, 3:29, 3:33, 3:32, 3:27 (negative split on the last one). Breathing felt labored from rep 3 onward. VO2 max training is uncomfortable but the adaptations are worth it. Total volume: 2.5 miles warm-up/cool-down plus 3 miles of intervals.

## 2024-02-10T08:00:00.000Z {#e-w001000000000006}

Climbing session at the gym — 2 hours. Warmed up on 5.10s, then worked a 5.12a project (roof section with sustained crimps). Managed to link the crux sequence twice but couldn't complete the full route. Ring finger felt slightly tender after — backed off immediately. Did 30 minutes of antagonist training: rubber band extensions, wrist curls, and reverse wrist curls.

## 2024-02-06T07:00:00.000Z {#e-w001000000000007}

Recovery run: 5 miles very easy (10:30/mile). Cadence drill — focused on keeping turnover above 170 steps per minute. Cadence work reduces ground contact time and overstriding injuries. Felt sluggish for the first two miles then loosened up. No aches; ready for the long run Saturday.

## 2024-02-02T06:30:00.000Z {#e-w001000000000008}

Upper body strength session. Overhead press: 4×6 at 95 lbs. Bench press: 4×8 at 155 lbs. Pull-ups: 4×8 (weighted, +20 lbs belt). Dumbbell rows: 3×12 each side at 65 lbs. Finished with face pulls and band pull-aparts for shoulder health. Pressing strength is slowly recovering since the focus shifted to marathon training.

## 2024-01-28T08:00:00.000Z {#e-w001000000000009}

Long run: 16 miles. First 10 miles with a running partner at 9:45/mile, last 6 alone at 9:15/mile (negative split). Practicing finishing strong. Consumed 3 gels and a pack of chews. Stomach handled it fine — no GI issues this time. Had moderate discomfort between miles 13–15 which is normal for this distance.

## 2024-01-20T07:00:00.000Z {#e-w001000000000010}

Stair climbing workout — 45 minutes on the StairMaster at moderate resistance. Supplements running without the impact. Heart rate held at 145–155 bpm throughout. Good aerobic stimulus on a recovery week. Followed by 20 minutes of stretching: hip flexors, hamstrings, IT band, calves. Foam rolled quads and glutes.
40 changes: 40 additions & 0 deletions test/e2e/corpus/notes/cooking/knife-skills-julienne.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: Knife Skills — Julienne Cuts
created: 2024-01-18T09:00:00.000Z
modified: 2024-01-18T09:00:00.000Z
tags: ["cooking", "knife", "technique"]
type: note
---

Julienne is a knife cut that produces thin matchstick strips, classically 2–3mm × 2–3mm × 5–6cm. Mastering it requires correct knife grip, stable board technique, and a sharp blade.

## Knife Grip

Use the "pinch grip": thumb and index finger pinch the blade just above the bolster, with the other three fingers wrapped around the handle. This grip provides control and reduces fatigue compared to holding only the handle.

The guiding hand uses the "claw grip": fingertips curled under, knuckles forward, touching the flat of the blade. The knuckles guide the blade and protect the fingertips.

## Stabilizing the Vegetable

Round vegetables must be flattened before julienning. Cut a thin slice off one side to create a stable flat surface. Work with the flat side down — the vegetable won't rock.

## Julienne Sequence (carrots)

1. Peel and trim the carrot into a rectangle (or cut into 5–6cm segments).
2. Slice lengthwise into planks 2–3mm thick, keeping them even.
3. Stack the planks and slice lengthwise again into 2–3mm strips.
4. The result is uniform matchsticks.

## Board Technique

A damp paper towel under the cutting board prevents it from sliding. Position the board close to the edge of the counter so your elbow can drop naturally. Choppy, vertical knife movements tire the arm; use a rocking or push-pull motion depending on what you're cutting.

## Keeping Cuts Uniform

Uniformity matters for even cooking, not just aesthetics. If half the strips are thick and half thin, some will be undercooked and others overcooked. Slow down before you speed up — consistent 2mm slices require attention to the guiding hand's spacing, not speed.

## Brunoise

A brunoise is julienne cut further: stack the julienne strips and cut crosswise into 2–3mm cubes. It is the finest dice in classical French knife work and is used for mirepoix, consommé garnishes, and fine brunoise sauces.

A sharp knife makes every cut safer and more precise. A dull blade requires more force, increasing the chance of slipping. Hone before each session and sharpen regularly.
Loading
Loading