Compare commits

..

1 Commits

Author SHA1 Message Date
Timmy Agent
2f53409614 feat(lab-005): Deploy AI agent fleet on available laptops (#530)
Some checks failed
Self-Healing Smoke / self-healing-smoke (pull_request) Failing after 27s
Smoke Test / smoke (pull_request) Failing after 29s
Agent PR Gate / gate (pull_request) Failing after 49s
Agent PR Gate / report (pull_request) Successful in 17s
- Add configs/laptop-fleet-manifest.yaml (production manifest for 6 machines)
- Add docs/LAB-005-laptop-fleet-deployment.md (generated deployment plan)
- Add ansible/playbooks/deploy_laptop_fleet.yml (Ansible playbook for Linux laptops)
- Add ansible/inventory/laptops.ini (fleet inventory with role groups)
- Add configs/hermes-laptop-anchor.service (24/7 systemd user service)
- Add configs/hermes-laptop-daylight.service (peak-hours systemd user service)
- Add configs/hermes-laptop-daylight.timer (systemd timer for 10:00 start)
- Expand tests to verify production manifest, plan, playbook, and services
2026-04-22 01:48:33 -04:00
9 changed files with 341 additions and 206 deletions

View File

@@ -0,0 +1,27 @@
[laptop_anchor]
# 24/7 anchor agents — lowest idle wattage, reliable adapters
timmy-anchor-a ansible_host=TIMMY_ANCHOR_A_IP ansible_user=timmy
[laptop_daylight]
# Daylight compute nodes — peak solar hours only
timmy-daylight-a ansible_host=TIMMY_DAYLIGHT_A_IP ansible_user=timmy
timmy-daylight-b ansible_host=TIMMY_DAYLIGHT_B_IP ansible_user=timmy
[laptop_pending]
# Machines awaiting hardware repair before production duty
timmy-daylight-c ansible_host=TIMMY_DAYLIGHT_C_IP ansible_user=timmy
[desktop_nas]
# Heavy compute + 4TB SSD NAS — daylight only due to power draw
timmy-desktop-nas ansible_host=TIMMY_DESKTOP_NAS_IP ansible_user=timmy
[laptops:children]
laptop_anchor
laptop_daylight
laptop_pending
desktop_nas
[laptops:vars]
ansible_python_interpreter=/usr/bin/python3
timmy_home=/home/timmy/timmy
timmy_repo=https://forge.alexanderwhitestone.com/Timmy_Foundation/timmy-home.git

View File

@@ -0,0 +1,137 @@
---
- name: Deploy Hermes agent fleet on available laptops
hosts: laptops
gather_facts: true
vars:
timmy_user: "{{ ansible_user }}"
timmy_dir: "/home/{{ timmy_user }}/timmy"
hermes_repo: "https://forge.alexanderwhitestone.com/Timmy_Foundation/timmy-home.git"
hermes_agent_repo: "https://forge.alexanderwhitestone.com/Timmy_Foundation/hermes-agent.git"
tasks:
- name: Ensure required packages are installed
ansible.builtin.package:
name:
- git
- python3
- python3-pip
- python3-venv
- tmux
- curl
- jq
- sqlite3
state: present
become: true
when: ansible_os_family in ['Debian', 'RedHat', 'Archlinux']
- name: Ensure timmy directory exists
ansible.builtin.file:
path: "{{ timmy_dir }}"
state: directory
mode: "0755"
- name: Clone timmy-home repository
ansible.builtin.git:
repo: "{{ hermes_repo }}"
dest: "{{ timmy_dir }}/timmy-home"
version: main
depth: 1
- name: Clone hermes-agent repository
ansible.builtin.git:
repo: "{{ hermes_agent_repo }}"
dest: "{{ timmy_dir }}/hermes-agent"
version: main
depth: 1
- name: Create Python virtual environment
ansible.builtin.command:
cmd: "python3 -m venv {{ timmy_dir }}/venv"
creates: "{{ timmy_dir }}/venv/bin/python"
- name: Install Python dependencies
ansible.builtin.pip:
name:
- requests
- pyyaml
virtualenv: "{{ timmy_dir }}/venv"
- name: Ensure systemd user directory exists
ansible.builtin.file:
path: "{{ ansible_env.HOME | default('/home/' + timmy_user) }}/.config/systemd/user"
state: directory
mode: "0755"
when: ansible_os_family in ['Debian', 'RedHat', 'Archlinux']
- name: Deploy anchor agent systemd user service
ansible.builtin.template:
src: "../../configs/hermes-laptop-anchor.service"
dest: "{{ ansible_env.HOME | default('/home/' + timmy_user) }}/.config/systemd/user/hermes-laptop-anchor.service"
mode: "0644"
when:
- inventory_hostname in groups['laptop_anchor']
- ansible_os_family in ['Debian', 'RedHat', 'Archlinux']
notify: Reload user systemd
- name: Deploy daylight agent systemd user service
ansible.builtin.template:
src: "../../configs/hermes-laptop-daylight.service"
dest: "{{ ansible_env.HOME | default('/home/' + timmy_user) }}/.config/systemd/user/hermes-laptop-daylight.service"
mode: "0644"
when:
- inventory_hostname in groups['laptop_daylight']
- ansible_os_family in ['Debian', 'RedHat', 'Archlinux']
notify: Reload user systemd
- name: Deploy daylight agent systemd timer
ansible.builtin.template:
src: "../../configs/hermes-laptop-daylight.timer"
dest: "{{ ansible_env.HOME | default('/home/' + timmy_user) }}/.config/systemd/user/hermes-laptop-daylight.timer"
mode: "0644"
when:
- inventory_hostname in groups['laptop_daylight']
- ansible_os_family in ['Debian', 'RedHat', 'Archlinux']
notify: Reload user systemd
- name: Enable and start anchor agent service
ansible.builtin.systemd:
name: hermes-laptop-anchor.service
state: started
enabled: true
scope: user
when:
- inventory_hostname in groups['laptop_anchor']
- ansible_os_family in ['Debian', 'RedHat', 'Archlinux']
- name: Enable daylight agent timer
ansible.builtin.systemd:
name: hermes-laptop-daylight.timer
state: started
enabled: true
scope: user
when:
- inventory_hostname in groups['laptop_daylight']
- ansible_os_family in ['Debian', 'RedHat', 'Archlinux']
- name: Create fleet status script
ansible.builtin.copy:
dest: "{{ timmy_dir }}/scripts/status.sh"
content: |
#!/bin/bash
echo "=== {{ inventory_hostname }} Status ==="
echo ""
echo "Services:"
systemctl --user is-active hermes-laptop-anchor.service 2>/dev/null && echo " anchor: RUNNING" || true
systemctl --user is-active hermes-laptop-daylight.service 2>/dev/null && echo " daylight: RUNNING" || true
echo ""
echo "Disk Usage:"
df -h $HOME | tail -1
echo ""
echo "Memory:"
free -h 2>/dev/null | grep Mem || vm_stat 2>/dev/null | head -5
mode: "0755"
handlers:
- name: Reload user systemd
ansible.builtin.command: systemctl --user daemon-reload
changed_when: true

View File

@@ -0,0 +1,15 @@
[Unit]
Description=Hermes Laptop Anchor Agent (24/7)
After=network.target
[Service]
Type=simple
WorkingDirectory=%h/timmy/hermes-agent
ExecStart=%h/timmy/venv/bin/python %h/timmy/hermes-agent/run_agent.py
Restart=always
RestartSec=30
Environment="HOME=%h"
Environment="HERMES_HOME=%h/.hermes"
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,16 @@
[Unit]
Description=Hermes Laptop Daylight Agent
After=network.target
[Service]
Type=simple
WorkingDirectory=%h/timmy/hermes-agent
ExecStart=%h/timmy/venv/bin/python %h/timmy/hermes-agent/run_agent.py
Restart=on-failure
RestartSec=30
RuntimeMaxSec=6h
Environment="HOME=%h"
Environment="HERMES_HOME=%h/.hermes"
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,9 @@
[Unit]
Description=Run Hermes daylight agent during peak solar hours
[Timer]
OnCalendar=*-*-* 10:00:00
Persistent=true
[Install]
WantedBy=timers.target

View File

@@ -0,0 +1,67 @@
# LAB-005: Laptop Fleet Manifest
# Production manifest for the 6-machine Timmy Foundation laptop fleet.
# Edit this file when hardware changes, then regenerate the deployment plan:
# python3 scripts/plan_laptop_fleet.py configs/laptop-fleet-manifest.yaml --markdown > docs/LAB-005-laptop-fleet-deployment.md
fleet_name: timmy-laptop-fleet
machines:
- hostname: timmy-anchor-a
machine_type: laptop
ram_gb: 16
cpu_cores: 8
os: macOS
adapter_condition: good
idle_watts: 11
always_on_capable: true
notes: candidate 24/7 anchor agent
- hostname: timmy-anchor-b
machine_type: laptop
ram_gb: 8
cpu_cores: 4
os: Linux
adapter_condition: good
idle_watts: 13
always_on_capable: true
notes: candidate 24/7 anchor agent
- hostname: timmy-daylight-a
machine_type: laptop
ram_gb: 32
cpu_cores: 10
os: macOS
adapter_condition: ok
idle_watts: 22
always_on_capable: true
notes: higher-performance daylight compute
- hostname: timmy-daylight-b
machine_type: laptop
ram_gb: 16
cpu_cores: 8
os: Linux
adapter_condition: ok
idle_watts: 19
always_on_capable: true
notes: daylight compute node
- hostname: timmy-daylight-c
machine_type: laptop
ram_gb: 8
cpu_cores: 4
os: Windows
adapter_condition: needs_replacement
idle_watts: 17
always_on_capable: false
notes: repair power adapter before production duty
- hostname: timmy-desktop-nas
machine_type: desktop
ram_gb: 64
cpu_cores: 12
os: Linux
adapter_condition: good
idle_watts: 58
always_on_capable: false
has_4tb_ssd: true
notes: desktop plus 4TB SSD NAS and heavy compute during peak sun

View File

@@ -0,0 +1,30 @@
# Laptop Fleet Deployment Plan
Fleet: timmy-laptop-fleet
Machine count: 6
24/7 anchor agents: timmy-anchor-a, timmy-anchor-b
Desktop/NAS: timmy-desktop-nas
Daylight schedule: 10:00-16:00
## Role mapping
| Hostname | Role | Schedule | Duty cycle |
|---|---|---|---|
| timmy-anchor-a | anchor_agent | 24/7 | continuous |
| timmy-anchor-b | anchor_agent | 24/7 | continuous |
| timmy-daylight-a | daylight_agent | 10:00-16:00 | peak_solar |
| timmy-daylight-b | daylight_agent | 10:00-16:00 | peak_solar |
| timmy-daylight-c | daylight_agent | 10:00-16:00 | peak_solar |
| timmy-desktop-nas | desktop_nas | 10:00-16:00 | daylight_only |
## Machine inventory
| Hostname | Type | RAM | CPU cores | OS | Adapter | Idle watts | Notes |
|---|---|---:|---:|---|---|---:|---|
| timmy-anchor-a | laptop | 16 | 8 | macOS | good | 11 | candidate 24/7 anchor agent |
| timmy-anchor-b | laptop | 8 | 4 | Linux | good | 13 | candidate 24/7 anchor agent |
| timmy-daylight-a | laptop | 32 | 10 | macOS | ok | 22 | higher-performance daylight compute |
| timmy-daylight-b | laptop | 16 | 8 | Linux | ok | 19 | daylight compute node |
| timmy-daylight-c | laptop | 8 | 4 | Windows | needs_replacement | 17 | repair power adapter before production duty |
| timmy-desktop-nas | desktop | 64 | 12 | Linux | good | 58 | desktop plus 4TB SSD NAS and heavy compute during peak sun |

View File

@@ -1,206 +0,0 @@
# MATH-005 Attack Packet: √2 Continued Fraction [2;2] Pattern
**Parent:** MATH-002 Scout List — Candidate #1 (Rank S)
**Source:** OEIS A002193 comments — open question about continued fraction patterns
**Issue:** timmy-home#881
**Attack Date:** 2026-04-29
**Agent:** Timmy (sovereign first-attack)
---
## Candidate Summary (from Scout List)
> **Question:** Investigate why the [2;2] continued fraction period appears in the convergents of √2 — and whether this pattern appears with unusual frequency in "non-quadratic" approximants.
- **Source:** OEIS A002193 (comments section)
- **Domain:** Number Theory / Continued Fractions
- **Why bounded:** Computationally checkable across 10^6 convergents; requires only modular arithmetic and comparison.
- **Expected artifact:** Computational evidence note + OEIS comment / short arXiv:num-th note.
- **Verification path:** Compute convergents of √2 via recurrence, detect whether [2,2] snippet appears patterned vs. random in quadratic field approximants.
---
## Literature Search
### Known facts about √2 continued fraction
√2 has the simplest non-trivial periodic continued fraction:
```
√2 = [1; 2, 2, 2, 2, ...] (pure periodic after first term)
```
This follows from the Pell equation: if x = √2, then x satisfies x² = 2, giving the recurrence.
The convergents are:
| n | Fraction (p/q) | Decimal approximation | Error |
|---|----------------|----------------------|-------|
| 1 | 1/1 | 1.0 | 0.4142 |
| 2 | 3/2 | 1.5 | 0.0858 |
| 3 | 7/5 | 1.4 | 0.0142 |
| 4 | 17/12 | 1.416666... | 0.00245 |
| ... | ... | ... | ... |
The [2,2] snippet corresponds to: `1 + 1/(2 + 1/2) = 1 + 1/(2.5) = 7/5 = 1.4` — exactly convergent #3.
### OEIS A002193 background
A002193: Continued fraction for √2 = 1.4142... The comments section (as of 2026) contains an open question phrased:
> "Is there a reason why the [2;2] period appears with prominence in non-quadratic approximants, or is this a coincidence?"
The phrasing "non-quadratic approximants" is ambiguous. Interpretation options:
1. **Rational approximants** (the convergents themselves are degree-1, not quadratic)
2. **Approximants of non-quadratic irrationals** (e.g., π, e, √[3]{2})
### Prior work references
- Hurwitz's theorem on Diophantine approximation
- Khinchin's "Continued Fractions" (standard reference)
- OEIS entries for periodic CF patterns in √n
---
## Computational Evidence
### √2 CF extraction
First 20 CF terms for √2:
```
[1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
```
The [2,2] pattern appears at positions (1,2), (2,3), ... — continuous infinite repetition.
### Other quadratic irrationals sampled
| n | √n CF (first 12 terms) | [2,2] count |
|----|------------------------|-------------|
| 2 | [1,2,2,2,2,2,2,2,2,2,2,2] | ∞ (pure period) |
| 3 | [1,1,2,1,4,1,2,1,4,1,2,1,...] | 0 |
| 5 | [2,4,4,4,4,4,4,4,4,4,4,4,...] | 0 |
| 6 | [2,2,4,2,4,2,4,2,4,2,4,2,...] | 2 |
| 7 | [2,1,1,1,4,1,1,1,4,1,1,1,...] | 0 |
| 10 | [3,6,6,6,6,6,6,6,6,6,7,1,...] | 0 |
| 13 | [3,1,1,1,1,6,1,1,1,1,6,1,...] | 0 |
| 17 | [4,8,8,8,8,8,8,8,8,8,8,8,...] | 0 |
| 41 | [6,2,2,12,2,2,12,2,2,12,2,2,...] | 6 |
Among 43 non-square √n (n < 50), **17 contain [2,2]** at least once (~39%).
### Transcendentals and random reals sampled
| x | CF (first 12 terms) | [2,2] count |
|---|---------------------|-------------|
| π | [3,7,15,1,292,1,1,1,2,1,3,1,...] | 0 |
| e | [2,1,2,1,1,4,1,1,6,1,1,8,...] | 0 |
| φ | [1,1] (pure periodic) | 0 |
| rand(2.7) | [2,1,2,2,1,469124..., ...] | 1 |
[2,2] appears by chance in random numbers as well. Among 10 random draws in [1,5], 2 showed at least one [2,2] occurrence.
### Convergent values of interest
The snippet [2;2] as a finite CF evaluates exactly to:
```
[2;2] = 2 + 1/2 = 5/2? No — careful:
[2;2] interpreted as standalone CF = 2 + 1/2 = 2.5
But in context of √2: [1;2,2] = 1 + 1/(2 + 1/2) = 1 + 1/(2.5) = 1 + 0.4 = 1.4 = 7/5
```
So the [2,2] "snippet" means two consecutive 2s in the CF term sequence after the first term.
---
## Attempted Analysis
### Why √2 yields [2,2]
The quadratic equation x² = 2 gives the recurrence:
```
x = 1 + 1/x => x = (x+1)/x after rearranging?
Actually: x = 1 + 1/(1 + 1/x)? Let me derive properly:
√2 = 1 + (√2 - 1) = 1 + 1/(1/(√2-1)) = 1 + 1/((√2+1)/1) = 1 + 1/(√2+1)
But √2+1 ≈ 2.414, whose integer part is 2. So a₂ = 2.
Then 1/(√2+1 - 2) = 1/(√2-1) = √2+1 again — period 1 with a=2 repeated.
```
This pure period-1 of constant term 2 is special to √2 and other "silver ratios" like [n; 2n, 2n, ...].
Actually, numbers with form √(m²+1) sometimes have continued fraction [m; 2m, 2m, ...]. For √2: m=1 → [1; 2,2,2,...]. For √5: m=2 → [2;4,4,4,...]. For √10: m=3 → [3;6,6,6,...].
So [2,2] appears for √2 because it belongs to the family √(1+1) with period-1 term 2.
### Why [2,2] appears in other quadratic irrationals
Examining √6: CF = [2;2,4,2,4,2,4,...] — this has a period-2 pattern: [2; (2,4)]. The [2,2] occurs crossing period boundaries: terms 1-2: [2,2] then [2,4] then [2,4]...
√41: CF period [6,2,2,12] — contains [2,2] as a contiguous pair within the period.
The pattern arises naturally in periodic CFs that have consecutive 2s somewhere in the period.
### About "non-quadratic approximants"
Interpretation 1: The **convergents themselves** are rational numbers (algebraic degree 1, not quadratic). The convergent sequence of √2 includes 7/5 — a rational number whose continued fraction (if computed self-referentially) is [1;2,2] — which contains the [2,2] snippet. This is tautological: any convergent is a rational approximant of √2, and the snippet simply encodes that convergent's own CF structure.
Interpretation 2: **Approximants of non-quadratic numbers**. Our random sample shows [2,2] appears by chance in transcendentals (e.g., rand(2.7) had it). The frequency is not obviously elevated.
### Computational limitations
Our survey only inspects first 3040 CF terms and 50 small quadratic radicands. The OEIS comment may refer to a deeper statistical study across thousands of numbers. We did not perform hypothesis testing.
---
## Gap Analysis
| What we know | What remains open |
|---|---|
| √2 has CF [1;2,2,2,...] → [2,2] appears infinitely | The original OEIS question's framing ("non-quadratic approximants") remains ambiguous — we need the exact wording |
| Other √n sometimes have [2,2] in their period | No statistical comparison: is [2,2] more frequent than, say, [1,1] or [3,3]? |
| Random numbers occasionally hit [2,2] by chance | No analysis of "why prominence?" — what metric defines prominence? |
| No connection proven between [2,2] and approximation quality | Open: Is there an information-theoretic reason [2,2] maximizes something? |
**Speculative hypothesis:** [2,2] is the shortest repeating pattern >1 in a periodic CF. For √2, the fundamental unit in (√2) is 1+√2 ≈ 2.414, which has CF [2;2,2,2,...]. This might reflect group structure of the unit group.
---
## Outcome Classification
**Partial progress**
We have:
- ✓ Located the candidate and verified the [2,2] snippet in √2 CF
- ✓ Computed statistical evidence across 40+ numbers
- ✓ Identified that other √n also exhibit [2,2] when their period contains consecutive 2s
- ✓ Clarified the ambiguity in "non-quadratic approximants"
We have *not*:
- ✗ Provided a rigorous proof of why the pattern appears in √2 (this is a standard result about simple periodic CFs)
- ✗ Answered the OEIS question conclusively
- ✗ Submitted an OEIS comment / created a short note
---
## Artifacts Generated
This attack packet itself is the primary artifact. A companion Python script could be created to reproduce the surveys, but for this smallest-attack we embed computed tables directly.
**Verification path:** Readers can recompute √2 convergents via standard recurrence and observe the [2,2] pattern.
---
## Next Attack Recommendations
Based on this first pass:
1. **If classification is Partial:** Attack the next-ranked candidate from MATH-002 (either #2 or next Rank S if multiple exist).
2. **If this proves too elementary:** Move to a Rank A candidate with computational flavor.
3. **If a rigorous proof is desired:** Study the theory of continued fractions for quadratic irrationals in Cassels' "An Introduction to Diophantine Approximation."
---
*"An honest first attack means showing your work, your ignorance, and your next step — all in the same document."*

View File

@@ -50,3 +50,43 @@ def test_manifest_template_is_valid_yaml() -> None:
data = yaml.safe_load(Path("docs/laptop-fleet-manifest.example.yaml").read_text())
assert data["fleet_name"] == "timmy-laptop-fleet"
assert len(data["machines"]) == 6
def test_production_manifest_exists_and_is_valid() -> None:
assert Path("configs/laptop-fleet-manifest.yaml").exists()
data = yaml.safe_load(Path("configs/laptop-fleet-manifest.yaml").read_text())
assert data["fleet_name"] == "timmy-laptop-fleet"
assert len(data["machines"]) == 6
plan = build_plan(data)
assert plan["desktop_nas"] == "timmy-desktop-nas"
assert len(plan["anchor_agents"]) == 2
def test_deployment_plan_generated() -> None:
assert Path("docs/LAB-005-laptop-fleet-deployment.md").exists()
content = Path("docs/LAB-005-laptop-fleet-deployment.md").read_text()
assert "24/7 anchor agents: timmy-anchor-a, timmy-anchor-b" in content
assert "Daylight schedule: 10:00-16:00" in content
assert "desktop_nas" in content
def test_ansible_playbook_exists() -> None:
assert Path("ansible/playbooks/deploy_laptop_fleet.yml").exists()
def test_ansible_laptop_inventory_exists() -> None:
assert Path("ansible/inventory/laptops.ini").exists()
content = Path("ansible/inventory/laptops.ini").read_text()
assert "[laptop_anchor]" in content
assert "[laptop_daylight]" in content
assert "[desktop_nas]" in content
def test_systemd_service_templates_exist() -> None:
assert Path("configs/hermes-laptop-anchor.service").exists()
assert Path("configs/hermes-laptop-daylight.service").exists()
assert Path("configs/hermes-laptop-daylight.timer").exists()
anchor = Path("configs/hermes-laptop-anchor.service").read_text()
daylight = Path("configs/hermes-laptop-daylight.service").read_text()
assert "Restart=always" in anchor
assert "RuntimeMaxSec=6h" in daylight