**Phase 01 — final verification pass (all criteria green)** - Verified M-1 fix in `src/terminal.js`: ArrowUp / ArrowDown(`>0`) / ArrowDown-else now route through `updateDisplay()` (`textContent`); no `innerHTML` sink touches `cmdLine`/`commandHistory`. - `grep -n innerHTML src/terminal.js` → 12 hits, all allowed (static prompt literals, `clear`/prank wipes, `outLine.innerHTML = output` gated on the static canned `neofetch` string). **C1 ✓** - XSS regression test at `tests/e2e/02-terminal.spec.js:156` present + passing; re-proved it is a real guard: re-injected the old `innerHTML` recall into `dist/terminal.*.js` → test failed (`#xss-marker` received 1); rebuild → byte-identical to `src/`. **C2 ✓** - `./build.sh` → `dist/` OK; `npm test` → **45 passed (0 failed)**; `bash .agents/validate.sh` → **exit 0** (suite + repo-hygiene gates). **C3 ✓** - Branch coverage of modified code: all 3 recall arms asserted (ArrowUp ×2 specs, ArrowDown `>0` in the existing history spec, ArrowDown-else → empty prompt in the new spec) → >90% gate met; no JS coverage/lint toolchain exists in the locked stack, so lint = `node --check src/*.js tests/e2e/*.js playwright.config.js` + `bash -n build.sh .agents/validate.sh` — clean. - C4 ✓ terminal/vim/achievements/menu specs all green; only the three recall branches changed. - Docs (step 6, full README/AGENTS review): README — run section now states the image already contains the built `dist/` (mount `dist/`, never `src/`); new “Serving & configuration” section for `nginx.conf`, incl. **empirically measured** (built image on 127.0.0.1:8124) that `/`, `/index.html` and hashed assets currently return *only* cache headers — the `add_header` non-merge gap = finding M-4/Phase 03; TLS/HSTS-at-edge rule; Quadlet section fixed (unit is not in this repo; Quadlet generates `homepage.service`, so `… start homepage.service`, and `systemctl enable` is a no-op for transient Quadlet units → `[Install]` + `daemon-reload` + linger); Development gained the Node 20+ floor, `npx playwright install chromium`, and `.agents/validate.sh`. AGENTS.md — added the validate.sh gate, flagged `./scripts/check-headers.sh` as not yet in the repo (Phase 03), and scoped the M-1 rule with the allowed-`innerHTML` list. - Notable: `.agents/PLAN.md` still says “44 tests” (3 places) and its §7 roadmap omits phases 04/05 — left untouched per the no-PLAN-edit rule; flag for the next PLAN review. No live-infra touched (temp podman image built/removed for the header measurement only). - Next pending phase: `02_simulate_fetch_commands`.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
# Phase 04 — Add Huntington National Bank role to work experience
|
||||
|
||||
**Story:** n/a
|
||||
**Context:** `src/index.html` `#experience` timeline, `.agents/PLAN.md` §2 (static-first — content-only change, no new technology)
|
||||
|
||||
## Objective
|
||||
Update the work-experience timeline with the user's current role: **Lead MLOps
|
||||
Engineer at Huntington National Bank (Jun 2026 – Present)**, inserted as the
|
||||
new first (most recent) timeline entry with three bullet points covering the
|
||||
agentic vulnerability-remediation toolkit, LLM harness skills for business
|
||||
automation, and the 6-person offshore team building the developer landing
|
||||
zone. The previous Nimbis "DevOps Manager" entry is updated from
|
||||
`Jan 2022 – Present` to `Jan 2022 – Apr 2026`. Lock the change with a
|
||||
Playwright regression test.
|
||||
|
||||
## Dependencies
|
||||
— (none)
|
||||
|
||||
## Tasks
|
||||
1. `01_add_timeline_entry.md` — Insert the new Huntington National Bank timeline entry at the top of the `#experience` timeline and update the Nimbis DevOps Manager end date.
|
||||
2. `02_experience_regression_test.md` — Add a Playwright test proving the new entry is first, complete, and correctly dated, and that the Nimbis entry no longer claims "Present".
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: no JS logic changes in this phase — `src/index.html`
|
||||
content only. The quality gate is the E2E regression test (task 2) plus the
|
||||
full suite.
|
||||
- Coverage: **>90%** on new/modified code — vacuously satisfied (no
|
||||
JS/CSS/TS code is modified); the E2E suite is the binding gate.
|
||||
- E2E: full Playwright suite (`npm test`) green.
|
||||
- The phase is "Complete" only when the **entire** project test suite passes
|
||||
100% (every test in the project, not just this phase's — pre-existing
|
||||
failures included) and achieves **>90% code coverage** on new/modified code.
|
||||
|
||||
## Documentation & Consistency
|
||||
- The final pass reviews `README.md` and `AGENTS.md` in full against the
|
||||
project as it stands after this phase — fixing every inconsistency found,
|
||||
**including pre-existing ones not caused by this phase**.
|
||||
- Tasks update `README.md`/`AGENTS.md` immediately when their own changes are
|
||||
user-visible (setup, commands, configuration, features, conventions).
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] `grep -c "Huntington National Bank" dist/index.html` returns 1 and
|
||||
`grep -n "Jun 2026" dist/index.html` shows the `– Present` date span
|
||||
- [ ] Nimbis "DevOps Manager" date reads `Jan 2022 – Apr 2026` in
|
||||
`dist/index.html` (no second `– Present` entry in `#experience`)
|
||||
- [ ] new regression test present in `tests/e2e/01-page.spec.js` and passing
|
||||
- [ ] `./build.sh && npm test` fully green (45+ tests)
|
||||
- [ ] no behavior change in completed work (terminal, vim, achievements, menu)
|
||||
- [ ] README.md and AGENTS.md are accurate and consistent with the whole
|
||||
project (verified in the final pass)
|
||||
@@ -0,0 +1,65 @@
|
||||
# Task 01 — Add Huntington National Bank timeline entry
|
||||
|
||||
**Phase:** `04_huntington_role` · **Story:** n/a
|
||||
|
||||
## Objective
|
||||
Insert the new top work-experience entry (Lead MLOps Engineer, Huntington
|
||||
National Bank, Jun 2026 – Present) into the `#experience` timeline and close
|
||||
out the Nimbis "DevOps Manager" date span.
|
||||
|
||||
## Work
|
||||
1. `src/index.html` — inside `<section id="experience">`, insert the block
|
||||
below **immediately before** the existing first
|
||||
`<div class="timeline-item fade-in" role="listitem">` (the Nimbis
|
||||
"DevOps Manager" entry), keeping the file's existing 16/20/24/28-space
|
||||
indentation exactly:
|
||||
|
||||
```html
|
||||
<div class="timeline-item fade-in" role="listitem">
|
||||
<div class="timeline-marker"></div>
|
||||
<div class="timeline-content">
|
||||
<div class="timeline-header">
|
||||
<h3>Lead MLOps Engineer</h3>
|
||||
<span class="timeline-company">Huntington National Bank</span>
|
||||
</div>
|
||||
<span class="timeline-date">Jun 2026 – Present</span>
|
||||
<ul class="timeline-list">
|
||||
<li>Building an enterprise agentic vulnerability remediation
|
||||
toolkit and workflow to resolve millions of vulnerabilities.</li>
|
||||
<li>Creating and distributing LLM harness skills that automate
|
||||
business problems — including ServiceNow incident response —
|
||||
at machine speed.</li>
|
||||
<li>Leading a team of 6 offshore engineers to build a developer
|
||||
landing zone with agentic tools that build pipelines, plan
|
||||
work, and make documentation searchable.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
(Use the en dash `–` U+2013 in the date span, matching every other
|
||||
`timeline-date` value; use the em dash `—` only in the middle bullet,
|
||||
matching the copy above. Wrap long `<li>` lines at the same width as
|
||||
neighboring entries, 4-space continuation indent.)
|
||||
2. `src/index.html` — in the Nimbis "DevOps Manager" entry, change its
|
||||
`<span class="timeline-date">Jan 2022 – Present</span>` to
|
||||
`<span class="timeline-date">Jan 2022 – Apr 2026</span>`.
|
||||
3. `./build.sh` — rebuild `dist/`.
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: content-only change — no new JS logic; the E2E regression
|
||||
test is task 2, and the full suite is the gate.
|
||||
- Coverage: **>90%** on this task's new/modified code — vacuously satisfied
|
||||
(HTML content only, no JS/CSS modified).
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] `grep -c "Huntington National Bank" src/index.html` returns 1
|
||||
- [ ] `grep -n "Jun 2026 – Present" src/index.html` matches the new entry
|
||||
- [ ] `grep -n "Jan 2022 – Apr 2026" src/index.html` matches the Nimbis
|
||||
"DevOps Manager" entry; `grep -c "– Present" src/index.html` returns 1
|
||||
- [ ] `./build.sh` succeeds and the same three greps pass on
|
||||
`dist/index.html`
|
||||
- [ ] `npm test` fully green (44 tests — the new test lands in task 2)
|
||||
- [ ] README.md/AGENTS.md updated for anything user-visible this task changes
|
||||
(the phase's final pass re-checks both project-wide)
|
||||
- [ ] no behavior change in completed work
|
||||
@@ -0,0 +1,55 @@
|
||||
# Task 02 — Experience timeline regression test
|
||||
|
||||
**Phase:** `04_huntington_role` · **Story:** n/a
|
||||
|
||||
## Objective
|
||||
Lock the work-experience change with a Playwright regression test: the
|
||||
Huntington National Bank entry is the first, most-recent timeline item with
|
||||
its three bullets and `Jun 2026 – Present` date, and the Nimbis
|
||||
"DevOps Manager" entry now ends `Apr 2026` instead of `Present`.
|
||||
|
||||
## Work
|
||||
1. `tests/e2e/01-page.spec.js` — inside the existing
|
||||
`test.describe('Page structure', ...)` block (after the
|
||||
"all major sections exist and are in the DOM" test), add one test,
|
||||
matching the file's existing style:
|
||||
|
||||
```js
|
||||
test('experience timeline leads with Huntington National Bank role', async ({ page }) => {
|
||||
const items = page.locator('#experience .timeline-item');
|
||||
await expect(items).toHaveCount(5);
|
||||
const first = items.first().locator('.timeline-content');
|
||||
await expect(first.locator('h3')).toHaveText('Lead MLOps Engineer');
|
||||
await expect(first.locator('.timeline-company')).toHaveText('Huntington National Bank');
|
||||
await expect(first.locator('.timeline-date')).toHaveText('Jun 2026 – Present');
|
||||
const bullets = first.locator('.timeline-list li');
|
||||
await expect(bullets).toHaveCount(3);
|
||||
await expect(bullets.nth(0)).toContainText('agentic vulnerability remediation');
|
||||
await expect(bullets.nth(1)).toContainText('LLM harness skills');
|
||||
await expect(bullets.nth(1)).toContainText('ServiceNow');
|
||||
await expect(bullets.nth(2)).toContainText('developer landing zone');
|
||||
// previous role's end date was closed out
|
||||
const nimbisManager = items.nth(1).locator('.timeline-content');
|
||||
await expect(nimbisManager.locator('h3')).toHaveText('DevOps Manager');
|
||||
await expect(nimbisManager.locator('.timeline-date')).toHaveText('Jan 2022 – Apr 2026');
|
||||
});
|
||||
```
|
||||
|
||||
(Use the en dash `–` U+2013 in the expected date strings to match the
|
||||
markup.)
|
||||
2. `./build.sh && npm test` — rebuild and run the full suite.
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: the new test covers (a) entry order (HNB first, Nimbis
|
||||
DevOps Manager second, 5 entries total), (b) title/company/date of the new
|
||||
entry, (c) all three bullets' key phrases, and (d) the Nimbis entry's
|
||||
closed-out end date.
|
||||
- Coverage: **>90%** on this task's new/modified code — test-only change;
|
||||
the E2E suite is the binding gate.
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] the new test is present in `tests/e2e/01-page.spec.js` and passes
|
||||
- [ ] `./build.sh && npm test` fully green (45 tests)
|
||||
- [ ] README.md/AGENTS.md updated for anything user-visible this task changes
|
||||
(the phase's final pass re-checks both project-wide)
|
||||
- [ ] no behavior change in completed work
|
||||
@@ -0,0 +1,62 @@
|
||||
# Phase 05 — Update Featured Projects (Brain of Reese, ServWaf, Local AI Stack)
|
||||
|
||||
**Story:** n/a
|
||||
**Context:** `src/index.html` `#projects` section (6 `project-card`s), `~/Projects/Personal/brain_of_reese/README.md`, `~/Projects/StackExpected/ServWall/README.md`, `~/Projects/Experimental/gufo/README.md`
|
||||
|
||||
## Objective
|
||||
Refresh the Featured Projects grid: (a) replace the "Self-Hosted Services"
|
||||
card with a **Brain of Reese** card (RAG chatbot over homelab docs;
|
||||
pgvector ∪ Postgres full-text hybrid search with RRF fusion; self-hosted
|
||||
LLM; source `https://gitea.reeseapps.com/Experimental/brain-of-reese` —
|
||||
verified live) and move it to the **first** slot; (b) replace the
|
||||
"Kubernetes Cluster" card with a **ServWaf** card (Go network WAF —
|
||||
declarative YAML rules, rate limiting, attack-pattern inspection, opt-in
|
||||
local-AI verdict, TLS/HTTP3 edge — **closed source: no source link**,
|
||||
user decision) in its place; (c) update the **Local AI Stack** card to
|
||||
replace Ollama with **vLLM, Gufo, and llama.cpp** (copy, tech tags, and
|
||||
code preview). Lock with a Playwright regression test.
|
||||
|
||||
## Dependencies
|
||||
— (none)
|
||||
|
||||
## Tasks
|
||||
1. `01_brain_of_reese_card.md` — Delete the Self-Hosted Services card; insert the Brain of Reese card as the first card in `#projects`.
|
||||
2. `02_servwaf_card.md` — Replace the Kubernetes Cluster card with the ServWaf card (description only, no source link).
|
||||
3. `03_update_local_ai_stack.md` — Update the Local AI Stack card: replace Ollama with vLLM/Gufo/llama.cpp in the copy, tech tags, and code preview.
|
||||
4. `04_projects_regression_test.md` — Add a Playwright test locking card count, order, the updated Local AI Stack tags, and the absence of the two removed card titles.
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: no JS logic changes in this phase — `src/index.html`
|
||||
content only. The quality gate is the E2E regression test (task 4) plus
|
||||
the full suite.
|
||||
- Coverage: **>90%** on new/modified code — vacuously satisfied (no
|
||||
JS/CSS/TS code is modified); the E2E suite is the binding gate.
|
||||
- E2E: full Playwright suite (`npm test`) green.
|
||||
- The phase is "Complete" only when the **entire** project test suite passes
|
||||
100% (every test in the project, not just this phase's — pre-existing
|
||||
failures included) and achieves **>90% code coverage** on new/modified code.
|
||||
|
||||
## Documentation & Consistency
|
||||
- The final pass reviews `README.md` and `AGENTS.md` in full against the
|
||||
project as it stands after this phase — fixing every inconsistency found,
|
||||
**including pre-existing ones not caused by this phase**.
|
||||
- Tasks update `README.md`/`AGENTS.md` immediately when their own changes are
|
||||
user-visible (setup, commands, configuration, features, conventions).
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] `grep -c "project-card fade-in" src/index.html` returns 6, and the
|
||||
same holds in `dist/index.html`
|
||||
- [ ] first `project-card` in `#projects` (in `dist/index.html`) is
|
||||
"Brain of Reese" and its card links to
|
||||
`https://gitea.reeseapps.com/Experimental/brain-of-reese`
|
||||
- [ ] `grep -c "Self-Hosted Services\|Kubernetes Cluster" src/index.html`
|
||||
returns 0 (project-card titles removed; the words may still appear in
|
||||
the out-of-scope About/Skills sections — e.g. "Kubernetes" skill tag)
|
||||
- [ ] the Local AI Stack card (in `dist/index.html`) contains vLLM, Gufo,
|
||||
and llama.cpp and no "Ollama"
|
||||
- [ ] new regression test present in `tests/e2e/01-page.spec.js` and passing
|
||||
- [ ] `./build.sh && npm test` fully green (45+ tests)
|
||||
- [ ] no change to the Skills section, About section, or any other section
|
||||
outside `#projects`
|
||||
- [ ] README.md and AGENTS.md are accurate and consistent with the whole
|
||||
project (verified in the final pass)
|
||||
@@ -0,0 +1,76 @@
|
||||
# Task 01 — Brain of Reese card (first slot)
|
||||
|
||||
**Phase:** `05_update_projects_section` · **Story:** n/a
|
||||
|
||||
## Objective
|
||||
Remove the "Self-Hosted Services" project card and insert the new
|
||||
**Brain of Reese** card as the **first** card in `#projects` (immediately
|
||||
before the "Reverse Proxy Infrastructure" card).
|
||||
|
||||
## Work
|
||||
1. `src/index.html` — inside `<section id="projects">`, delete the entire
|
||||
`project-card` block whose `<h3>` is "Self-Hosted Services" (the card
|
||||
containing the `- Immich / - Jellyfin / …` code block).
|
||||
2. `src/index.html` — insert the block below **immediately before** the
|
||||
existing first `project-card` (the "Reverse Proxy Infrastructure"
|
||||
card), matching the file's 16/20/24/28-space indentation. For the
|
||||
`<div class="project-links">…</div>` (Gitea SVG) block, copy the
|
||||
existing one from the "Reverse Proxy Infrastructure" card verbatim and
|
||||
change only the `href` to
|
||||
`https://gitea.reeseapps.com/Experimental/brain-of-reese`:
|
||||
|
||||
```html
|
||||
<div class="project-card fade-in" role="listitem">
|
||||
<div class="project-preview">
|
||||
<div class="code-block">
|
||||
<div class="code-line"><span class="code-comment"># Hybrid search: pgvector cosine ∪ Postgres full-text</span></div>
|
||||
<div class="code-line"><span class="code-keyword">def</span> <span class="code-function">retrieve</span>(<span class="code-variable">query</span>, <span class="code-variable">k</span>=<span class="code-variable">5</span>):</div>
|
||||
<div class="code-line"> <span class="code-variable">vec</span> = <span class="code-function">pgvector</span>.<span class="code-function">cosine</span>(<span class="code-variable">query</span>)</div>
|
||||
<div class="code-line"> <span class="code-variable">fts</span> = <span class="code-function">postgres</span>.<span class="code-function">full_text</span>(<span class="code-variable">query</span>)</div>
|
||||
<div class="code-line"> <span class="code-variable">chunks</span> = <span class="code-function">rrf_fuse</span>(<span class="code-variable">vec</span>, <span class="code-variable">fts</span>, <span class="code-variable">k</span>)</div>
|
||||
<div class="code-line"> <span class="code-keyword">return</span> <span class="code-function">llm</span>.<span class="code-function">chat</span>(<span class="code-function">document</span>(<span class="code-variable">chunks</span>))</div>
|
||||
<div class="code-line"> </div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-info">
|
||||
<h3>Brain of Reese</h3>
|
||||
<p>A chippy, honest RAG chatbot over homelab documentation — git repositories, local
|
||||
directories, and uploaded archives. Hybrid search (pgvector cosine ∪ Postgres
|
||||
full-text search, Reciprocal Rank Fusion) feeds the whole relevant document to a
|
||||
self-hosted LLM and streams back a grounded answer; when it has no notes it
|
||||
admits it and suggests questions it can answer.</p>
|
||||
<div class="project-meta">
|
||||
<div class="project-tech">
|
||||
<span>FastAPI</span>
|
||||
<span>pgvector</span>
|
||||
<span>Postgres</span>
|
||||
<span>Playwright</span>
|
||||
</div>
|
||||
<div class="project-links">
|
||||
<!-- copied from the Reverse Proxy Infrastructure card, href changed -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
3. `./build.sh` — rebuild `dist/`.
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: content-only change — no new JS logic; the E2E
|
||||
regression test is task 4, and the full suite is the gate.
|
||||
- Coverage: **>90%** on this task's new/modified code — vacuously satisfied
|
||||
(HTML content only, no JS/CSS modified).
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] `grep -c "project-card fade-in" src/index.html` returns 6
|
||||
- [ ] `grep -n "Brain of Reese" src/index.html` matches once, and that card
|
||||
is the first `project-card` inside `#projects`
|
||||
- [ ] `grep -c "Self-Hosted Services" src/index.html` returns 0
|
||||
- [ ] `grep -n "gitea.reeseapps.com/Experimental/brain-of-reese"
|
||||
src/index.html` matches inside the new card
|
||||
- [ ] `./build.sh` succeeds and the same greps pass on `dist/index.html`
|
||||
- [ ] `npm test` fully green (44 tests — new test lands in task 4)
|
||||
- [ ] README.md/AGENTS.md updated for anything user-visible this task changes
|
||||
(the phase's final pass re-checks both project-wide)
|
||||
- [ ] no behavior change in completed work
|
||||
@@ -0,0 +1,69 @@
|
||||
# Task 02 — ServWaf card (replaces Kubernetes Cluster)
|
||||
|
||||
**Phase:** `05_update_projects_section` · **Story:** n/a
|
||||
|
||||
## Objective
|
||||
Replace the "Kubernetes Cluster" project card, in place (last slot), with
|
||||
the **ServWaf** card. ServWaf is **closed source** (user decision): the
|
||||
card carries **no** `project-links` block — description only.
|
||||
|
||||
## Work
|
||||
1. `src/index.html` — inside `<section id="projects">`, replace the entire
|
||||
`project-card` block whose `<h3>` is "Kubernetes Cluster" (the card
|
||||
containing the `# Kubernetes with k3s` code block) with the block below,
|
||||
matching the file's 16/20/24/28-space indentation. Note: this card has
|
||||
**no** `<div class="project-links">` — the `project-meta` div contains
|
||||
only `project-tech` (the flex layout handles a single child).
|
||||
|
||||
```html
|
||||
<div class="project-card fade-in" role="listitem">
|
||||
<div class="project-preview">
|
||||
<div class="code-block">
|
||||
<div class="code-line"><span class="code-comment"># ServWaf — declarative rules</span></div>
|
||||
<div class="code-line"><span class="code-variable">ratelimit</span>:</div>
|
||||
<div class="code-line"> <span class="code-variable">per_ip</span>: <span class="code-string">20 rps, burst 40</span></div>
|
||||
<div class="code-line"><span class="code-variable">rules</span>:</div>
|
||||
<div class="code-line"> - <span class="code-keyword">deny</span> <span class="code-variable">if</span> <span class="code-variable">user_agent</span> =~ <span class="code-string">"curl|wget"</span></div>
|
||||
<div class="code-line"> - <span class="code-keyword">flag</span> <span class="code-variable">if</span> <span class="code-variable">body</span> =~ <span class="code-string">"(?i)union\s+select"</span></div>
|
||||
<div class="code-line"><span class="code-variable">ai</span>:</div>
|
||||
<div class="code-line"> <span class="code-variable">endpoint</span>: <span class="code-string">"http://aipi.reeseapps.com/v1"</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="project-info">
|
||||
<h3>ServWaf</h3>
|
||||
<p>A network Web Application Firewall written in Go, sitting in line between clients
|
||||
and the origin. Declarative YAML rules (user agent, IP/CIDR, URL and body
|
||||
regexes), per-IP rate limiting, attack-pattern inspection (SQL injection, XSS,
|
||||
path traversal, CRLF, scanner probes), opt-in self-hosted local-AI verdicts,
|
||||
TLS termination, and an opt-in HTTP/3 (QUIC) edge.</p>
|
||||
<div class="project-meta">
|
||||
<div class="project-tech">
|
||||
<span>Go</span>
|
||||
<span>YAML</span>
|
||||
<span>HTTP/3</span>
|
||||
<span>Podman</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
2. `./build.sh` — rebuild `dist/`.
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: content-only change — no new JS logic; the E2E
|
||||
regression test is task 4, and the full suite is the gate.
|
||||
- Coverage: **>90%** on this task's new/modified code — vacuously satisfied
|
||||
(HTML content only, no JS/CSS modified).
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] `grep -c "project-card fade-in" src/index.html` returns 6
|
||||
- [ ] `grep -n "ServWaf" src/index.html` matches the new card's `<h3>`
|
||||
- [ ] `grep -c "Kubernetes Cluster" src/index.html` returns 0
|
||||
- [ ] the ServWaf card (last card in `#projects`) contains no
|
||||
`project-links` div and no `gitea.reeseapps.com` href
|
||||
- [ ] `./build.sh` succeeds and the same greps pass on `dist/index.html`
|
||||
- [ ] `npm test` fully green (44 tests — new test lands in task 4)
|
||||
- [ ] README.md/AGENTS.md updated for anything user-visible this task changes
|
||||
(the phase's final pass re-checks both project-wide)
|
||||
- [ ] no behavior change in completed work
|
||||
@@ -0,0 +1,59 @@
|
||||
# Task 03 — Update Local AI Stack card (vLLM, Gufo, llama.cpp)
|
||||
|
||||
**Phase:** `05_update_projects_section` · **Story:** n/a
|
||||
|
||||
## Objective
|
||||
Update the "Local AI Stack" project card so Ollama is replaced by **vLLM,
|
||||
Gufo, and llama.cpp** in the description, tech tags, and code preview.
|
||||
Everything else on the card (LocalAI, LiteLLM, Bifrost, Langfuse, CUDA/
|
||||
ROCm) stays.
|
||||
|
||||
## Work
|
||||
1. `src/index.html` — in the "Local AI Stack" card, replace the `<p>` copy
|
||||
with:
|
||||
|
||||
```html
|
||||
<p>Complete local AI infrastructure: vLLM, Gufo, and llama.cpp for inference, LiteLLM as a
|
||||
unified API proxy, Bifrost for model routing, and Langfuse for observability. Supports
|
||||
both CUDA and ROCm.</p>
|
||||
```
|
||||
|
||||
2. `src/index.html` — in that card's `project-tech` div, replace the
|
||||
`<span>Ollama</span>` with three spans in this order:
|
||||
`<span>vLLM</span> <span>Gufo</span> <span>llama.cpp</span>`
|
||||
(final tag list: vLLM, Gufo, llama.cpp, LocalAI, LiteLLM, Langfuse).
|
||||
3. `src/index.html` — in that card's `code-block`, replace the whole block
|
||||
(the `from ollama import Client` … `# LiteLLM proxy for unified API`
|
||||
lines) with:
|
||||
|
||||
```html
|
||||
<div class="code-line"><span class="code-comment"># Inference engines</span></div>
|
||||
<div class="code-line"><span class="code-variable">engines</span> = {</div>
|
||||
<div class="code-line"> <span class="code-string">"vllm"</span>: <span class="code-string">"cuda"</span>, <span class="code-comment"># high-throughput serving</span></div>
|
||||
<div class="code-line"> <span class="code-string">"gufo"</span>: <span class="code-string">"rocm"</span>, <span class="code-comment"># Strix Halo inference</span></div>
|
||||
<div class="code-line"> <span class="code-string">"llama.cpp"</span>: <span class="code-string">"gguf"</span>, <span class="code-comment"># CPU/GPU fallback</span></div>
|
||||
<div class="code-line">}</div>
|
||||
<div class="code-line"> </div>
|
||||
<div class="code-line"><span class="code-comment"># LiteLLM proxy for unified API</span></div>
|
||||
```
|
||||
|
||||
4. `./build.sh` — rebuild `dist/`.
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: content-only change — no new JS logic; the E2E
|
||||
regression test is task 4, and the full suite is the gate.
|
||||
- Coverage: **>90%** on this task's new/modified code — vacuously satisfied
|
||||
(HTML content only, no JS/CSS modified).
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] within the Local AI Stack card in `src/index.html`: no "Ollama"
|
||||
anywhere, and "vLLM", "Gufo", "llama.cpp" each present (copy, tags,
|
||||
and preview)
|
||||
- [ ] "LocalAI", "LiteLLM", "Langfuse" (and "Bifrost" in the copy) are
|
||||
still present on the card
|
||||
- [ ] `./build.sh` succeeds and the same checks pass on
|
||||
`dist/index.html`
|
||||
- [ ] `npm test` fully green (44 tests — new test lands in task 4)
|
||||
- [ ] README.md/AGENTS.md updated for anything user-visible this task changes
|
||||
(the phase's final pass re-checks both project-wide)
|
||||
- [ ] no behavior change in completed work
|
||||
@@ -0,0 +1,64 @@
|
||||
# Task 04 — Projects grid regression test
|
||||
|
||||
**Phase:** `05_update_projects_section` · **Story:** n/a
|
||||
|
||||
## Objective
|
||||
Lock the Featured Projects change with a Playwright regression test: six
|
||||
cards in the new order (Brain of Reese first, ServWaf last), the Local AI
|
||||
Stack card showing vLLM/Gufo/llama.cpp with no Ollama, and the removed
|
||||
"Self-Hosted Services" / "Kubernetes Cluster" titles absent.
|
||||
|
||||
## Work
|
||||
1. `tests/e2e/01-page.spec.js` — inside the existing
|
||||
`test.describe('Page structure', ...)` block, add one test, matching the
|
||||
file's existing style:
|
||||
|
||||
```js
|
||||
test('featured projects show the six updated cards in order', async ({ page }) => {
|
||||
const cards = page.locator('#projects .project-card');
|
||||
await expect(cards).toHaveCount(6);
|
||||
const titles = await cards.locator('.project-info h3').allTextContents();
|
||||
expect(titles).toEqual([
|
||||
'Brain of Reese',
|
||||
'Reverse Proxy Infrastructure',
|
||||
'Dynamic DNS Service',
|
||||
'Local AI Stack',
|
||||
'Deployment Automation',
|
||||
'ServWaf',
|
||||
]);
|
||||
// Brain of Reese leads, with its source link
|
||||
const brain = cards.first();
|
||||
await expect(brain.locator('.project-tech span')).toHaveCount(4);
|
||||
await expect(brain).toHaveText(/RAG chatbot/i);
|
||||
await expect(brain.locator('a[href="https://gitea.reeseapps.com/Experimental/brain-of-reese"]')).toBeAttached();
|
||||
// Local AI Stack: Ollama replaced by vLLM, Gufo, llama.cpp
|
||||
const ai = cards.nth(3);
|
||||
await expect(ai.locator('.project-tech')).toContainText(['vLLM', 'Gufo', 'llama.cpp']);
|
||||
await expect(ai.locator('.project-tech')).toContainText(['LocalAI', 'LiteLLM', 'Langfuse']);
|
||||
await expect(ai).not.toContainText('Ollama');
|
||||
// ServWaf is closed source — description only, no source link
|
||||
await expect(cards.last()).toHaveText(/Web Application Firewall/i);
|
||||
await expect(cards.last().locator('.project-links')).not.toBeAttached();
|
||||
// removed cards are gone from the grid
|
||||
expect(titles).not.toContain('Self-Hosted Services');
|
||||
expect(titles).not.toContain('Kubernetes Cluster');
|
||||
});
|
||||
```
|
||||
|
||||
2. `./build.sh && npm test` — rebuild and run the full suite.
|
||||
|
||||
## Testing & Quality
|
||||
- Unit/integration: the new test covers (a) card count (6) and exact title
|
||||
order, (b) Brain of Reese first with its Gitea source link, (c) Local AI
|
||||
Stack tech tags (new + retained, no Ollama), (d) ServWaf last with no
|
||||
source link, and (e) the two removed titles absent.
|
||||
- Coverage: **>90%** on this task's new/modified code — test-only change;
|
||||
the E2E suite is the binding gate.
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] the new test is present in `tests/e2e/01-page.spec.js` and passes
|
||||
- [ ] `./build.sh && npm test` fully green (45 tests: 44 pre-existing + 1
|
||||
new)
|
||||
- [ ] README.md/AGENTS.md updated for anything user-visible this task changes
|
||||
(the phase's final pass re-checks both project-wide)
|
||||
- [ ] no behavior change in completed work
|
||||
Reference in New Issue
Block a user