<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://walter.teitelbaum.us/feed.xml" rel="self" type="application/atom+xml" /><link href="https://walter.teitelbaum.us/" rel="alternate" type="text/html" /><updated>2026-10-04T17:34:45-07:00</updated><id>https://walter.teitelbaum.us/feed.xml</id><title type="html">Walter Teitelbaum</title><subtitle>Welcome to my site. Feel free to have a look around.</subtitle><author><name>Walter Teitelbaum</name><email>walter@teitelbaum.us</email></author><entry><title type="html">AbyssBench: Checking Controller Timing</title><link href="https://walter.teitelbaum.us/2026/10/04/abyssbench/" rel="alternate" type="text/html" title="AbyssBench: Checking Controller Timing" /><published>2026-10-04T00:00:00-07:00</published><updated>2026-10-04T00:00:00-07:00</updated><id>https://walter.teitelbaum.us/2026/10/04/abyssbench</id><content type="html" xml:base="https://walter.teitelbaum.us/2026/10/04/abyssbench/"><![CDATA[<p>A controller can issue the right command while the machine continues doing the wrong thing. <a href="https://github.com/jewbee2000/abyssbench">AbyssBench</a> explores that distinction: when a sensor reading becomes stale or an actuator stops responding, did the controller issue the required response before its deadline—and does the recorded evidence actually establish that?</p>

<p>I see it as a small tool for engineers developing control logic or reviewing test logs. It combines pytest with <a href="https://github.com/nickovic/rtamt">RTAMT</a>, an existing temporal monitoring library. Its contribution is the surrounding workflow: explicit timing rules, repeatable traces, and evidence that keeps commands separate from measured behavior.</p>

<h2 id="how-it-is-used">How it is used</h2>

<p>I would start with the <a href="https://github.com/jewbee2000/abyssbench#try-it-locally-powershell-python-312">installation and offline demo</a>. The <a href="https://github.com/jewbee2000/abyssbench/blob/main/docs/API.md">public API walkthrough</a> offers two starting points: import a supported JSONL or explicitly mapped CSV trace, or supply a trusted Python controller to the example simulator. Define acceptable ranges, measurement age, response deadlines, and prohibited transitions; run the check; then inspect each rule’s verdict and supporting events. Incomplete observation windows remain inconclusive. A recent packet carrying an old measurement does not become fresh just because it arrived recently.</p>

<h2 id="a-small-example">A small example</h2>

<p>The pump-and-valve example makes the distinction visible. The simulated valve sticks closed at 500 milliseconds. At 1,010 milliseconds, the controller detects the persistent mismatch and issues pump-off and valve-open commands. The valve remains closed. The response check can pass because the required commands were issued; that says nothing about mechanical recovery.</p>

<figure class="experiment-figure">
  <a href="/assets/files/agentic-engineering/abyss-timing.png"><img src="/assets/files/agentic-engineering/abyss-timing.png" alt="Simulation timeline: a valve sticks at 500 milliseconds and the controller issues safe commands at 1,010 milliseconds while the valve remains closed." loading="lazy" width="1920" height="1120" /></a>
  <figcaption>Recorded simulation events: commanded and actual valve positions remain separate.</figcaption>
</figure>

<h2 id="validation-and-limits">Validation and limits</h2>

<p>The original release passed 116 tests. The publication review nevertheless found two edge cases: a single observation could crash the monitor, and a command preceding a fault at the same timestamp could incorrectly satisfy its response rule. Both were repaired; the publication audit passed <strong>124 tests</strong>. The <a href="https://github.com/jewbee2000/abyssbench/blob/main/evidence/publication-audit/README.md">audit preserves the failing cases</a>.</p>

<p>The tool supports one clock and trusted controller callbacks; its fluid model is uncalibrated, with no hardware validation. A real trace and an independent engineer’s trial are the next useful tests.</p>]]></content><author><name>Walter Teitelbaum</name><email>walter@teitelbaum.us</email></author><summary type="html"><![CDATA[Replay controller events and check whether the recorded response satisfies an explicit timing contract. Part of Walter Teitelbaum's two-day AI engineering experiment.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://walter.teitelbaum.us/assets/files/agentic-engineering/abyss-timing.png" /><media:content medium="image" url="https://walter.teitelbaum.us/assets/files/agentic-engineering/abyss-timing.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">RFQFuzz: Regression Tests for Drawing Reviewers</title><link href="https://walter.teitelbaum.us/2026/10/04/rfqfuzz/" rel="alternate" type="text/html" title="RFQFuzz: Regression Tests for Drawing Reviewers" /><published>2026-10-04T00:00:00-07:00</published><updated>2026-10-04T00:00:00-07:00</updated><id>https://walter.teitelbaum.us/2026/10/04/rfqfuzz</id><content type="html" xml:base="https://walter.teitelbaum.us/2026/10/04/rfqfuzz/"><![CDATA[<p><a href="https://github.com/jewbee2000/rfq-fuzz">RFQFuzz</a> is a local regression toolkit for engineers developing or adopting reviewers of CNC request-for-quotation packages. It checks whether a change to a review prompt, rule engine, or capability profile changes the findings on controlled STEP models and drawings.</p>

<p>I initially considered a drawing-review tool. The <a href="https://github.com/jewbee2000/rfq-fuzz/blob/main/docs/RESEARCH_AND_GO_NO_GO.md">research into existing products</a> led to a narrower question: how can someone test the reviewer itself? RFQFuzz supplies known defects, corrected counterparts, and valid alternatives so that flagging every difference is not a successful strategy.</p>

<h2 id="how-it-is-used">How it is used</h2>

<p>The workflow is to validate a challenge package, pass its public files to a reviewer, import the observations, and compare the results across versions. Reports connect changed findings to the relevant drawing and geometry. Package consistency and conditional CNC advisories are scored separately.</p>

<p>The <a href="https://github.com/jewbee2000/rfq-fuzz/blob/main/docs/DEMO.md">installation and demo guide</a> provides a 15-case offline replay. After setup, run this from the checkout with the environment active:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python -m rfqfuzz.v1 demo examples/v1-demo work/my-demo
</code></pre></div></div>

<p>Open <code class="language-plaintext highlighter-rouge">work/my-demo/report/index.html</code>. The demo compares retained responses with two deliberately injected changes; it requires no live model or API key.</p>

<h2 id="a-small-example">A small example</h2>

<p>One challenge pairs a STEP model containing 6.00 mm bores with a drawing specifying 6.80 ±0.05 mm at the same manufacturing stage. A corrected drawing resolves the contradiction. Another package legitimately differs because it describes a later reaming operation. That context matters as much as the numbers.</p>

<figure class="experiment-figure">
  <a href="/assets/files/agentic-engineering/rfq-plate.png"><img src="/assets/files/agentic-engineering/rfq-plate.png" alt="RFQFuzz plate drawing specifying four 6.80 plus or minus 0.05 millimetre bores, deliberately contradicting its same-stage STEP model." loading="lazy" width="2339" height="1654" /></a>
  <figcaption>A deliberately inconsistent challenge drawing, not a production part.</figcaption>
</figure>

<h2 id="validation-and-limits">Validation and limits</h2>

<p>The publication audit passed <strong>278 tests</strong>, up from 270 after repairs to local-unit interpretation and process output limits. The <a href="https://github.com/jewbee2000/rfq-fuzz/tree/main/evidence/publication-code-audit">audit records</a> preserve that distinction.</p>

<p>Its 145 validated core packets are development cases, with no holdout. The tool supports three finite geometry families, and its geometry checks share the OCCT kernel. It does not establish general drawing-review accuracy or approve manufacture. I see its potential in making regressions explainable; independent engineering use is still needed to assess its value.</p>]]></content><author><name>Walter Teitelbaum</name><email>walter@teitelbaum.us</email></author><summary type="html"><![CDATA[Compare reviewer behavior on controlled CAD and drawing packages, with evidence for each changed finding. Part of Walter Teitelbaum's two-day AI engineering experiment.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://walter.teitelbaum.us/assets/files/agentic-engineering/rfq-plate.png" /><media:content medium="image" url="https://walter.teitelbaum.us/assets/files/agentic-engineering/rfq-plate.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">FixtureForge: Checking Tool Access in CAD</title><link href="https://walter.teitelbaum.us/2026/10/04/fixtureforge/" rel="alternate" type="text/html" title="FixtureForge: Checking Tool Access in CAD" /><published>2026-10-04T00:00:00-07:00</published><updated>2026-10-04T00:00:00-07:00</updated><id>https://walter.teitelbaum.us/2026/10/04/fixtureforge</id><content type="html" xml:base="https://walter.teitelbaum.us/2026/10/04/fixtureforge/"><![CDATA[<p>A part can fit inside a fixture while leaving no route for a screwdriver or connector to reach it. <a href="https://github.com/jewbee2000/fixtureforge">FixtureForge</a> checks that narrower assembly question: can a simplified tool follow a specified straight path without intersecting the parts around it?</p>

<p>I see this as a small, inspectable integration of existing CAD tools. CadQuery supplies the geometric operations; FixtureForge adds an input contract, repeatable checks, and reports identifying the obstructing part. Its <a href="https://github.com/jewbee2000/fixtureforge/blob/main/docs/BASELINE.md">comparison with CadQuery, build123d, and CADCLAW</a> illustrates why checking only the starting and ending positions can miss an obstacle in between.</p>

<h2 id="how-it-is-used">How it is used</h2>

<p>The intended user is an engineer checking access in a fixture or small assembly. After following the <a href="https://github.com/jewbee2000/fixtureforge#reproduce-locally">installation and demo instructions</a>, the workflow is:</p>

<ol>
  <li>Supply each part as a single-solid STEP file in millimetres.</li>
  <li>Define a box or cylinder representing the tool, its starting and ending positions, and the parts present at that assembly stage in the <a href="https://github.com/jewbee2000/fixtureforge/blob/main/docs/PUBLIC_API.md">JSON access contract</a>.</li>
  <li>Run the inspection and open the local HTML report. The check considers the volume occupied along the whole path.</li>
</ol>

<p>The supplied sensor-clamp demonstration deliberately routes a tool through the upper clamp. Its report shows approximately <strong>382.377 mm³</strong> of overlap. The demo also includes a corrected path, making it possible to inspect both outcomes.</p>

<figure class="experiment-figure">
  <a href="/assets/files/agentic-engineering/fixture-access.jpg"><img src="/assets/files/agentic-engineering/fixture-access.jpg" alt="FixtureForge report showing a deliberately obstructed tool path through a sensor clamp, with 382.377 cubic millimetres of overlap." loading="lazy" /></a>
  <figcaption>A deliberately seeded obstruction. Purple shows the swept envelope; this is a geometry replay, not a physical measurement.</figcaption>
</figure>

<h2 id="validation-and-limits">Validation and limits</h2>

<p>The publication audit passed <strong>61 tests</strong>; four inspect retained campaign evidence rather than rerunning those campaigns. The <a href="https://github.com/jewbee2000/fixtureforge/tree/main/evidence/publication-audit">audit evidence</a> records the checks. The software is runnable, with setup verified on Windows and Python 3.12.</p>

<p>I would use it to investigate a declared access path, not approve an assembly. It supports straight translations and conservative envelopes, which can over-report collisions. It does not plan rotating motions or establish clamping force or material strength. The clamp has not been physically validated, and usefulness to an independent practitioner remains untested.</p>]]></content><author><name>Walter Teitelbaum</name><email>walter@teitelbaum.us</email></author><summary type="html"><![CDATA[Inspect whether a simplified tool can follow a declared path through a fixture or small assembly. Part of Walter Teitelbaum's two-day AI engineering experiment.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://walter.teitelbaum.us/assets/files/agentic-engineering/fixture-access.jpg" /><media:content medium="image" url="https://walter.teitelbaum.us/assets/files/agentic-engineering/fixture-access.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">DriverForge: Testing Instrument Drivers Without Hardware</title><link href="https://walter.teitelbaum.us/2026/10/04/driverforge/" rel="alternate" type="text/html" title="DriverForge: Testing Instrument Drivers Without Hardware" /><published>2026-10-04T00:00:00-07:00</published><updated>2026-10-04T00:00:00-07:00</updated><id>https://walter.teitelbaum.us/2026/10/04/driverforge</id><content type="html" xml:base="https://walter.teitelbaum.us/2026/10/04/driverforge/"><![CDATA[<p>An instrument driver translates between software and a physical device. That translation can fail even when a response looks perfectly reasonable. For <a href="https://github.com/jewbee2000/driverforge">DriverForge</a>, I asked Codex to investigate a useful addition to existing instrument libraries, establish acceptance checks, and preserve failed examples.</p>

<p>The result is a small Python tool for engineers maintaining instrument drivers, particularly when the hardware is unavailable in continuous integration. It supplies a simulated communication channel, controlled faults, and reports showing the exact bytes exchanged alongside the expected and observed results.</p>

<h2 id="how-it-is-used">How it is used</h2>

<p>The workflow starts with an explicit protocol contract and expected readings. An engineer connects a driver to the test transport, schedules faults such as fragmented responses or timeouts, then inspects the resulting HTML or JSON report. The <a href="https://github.com/jewbee2000/driverforge/blob/main/docs/PUBLIC_API.md">public API</a> also provides a pytest fixture. One integration uses an unchanged PyMeasure Agilent34410A driver through its existing adapter interface. <a href="https://pymeasure.readthedocs.io/en/stable/dev/adding_instruments/tests.html">PyMeasure already supports protocol testing</a>; DriverForge’s contribution is the reusable fault schedules and detailed diagnostic records.</p>

<p>After following the <a href="https://github.com/jewbee2000/driverforge#install-and-demonstrate">installation instructions</a> and activating the environment, run:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python -m driverforge demo --offline --output artifacts/demo
</code></pre></div></div>

<p>Open <code class="language-plaintext highlighter-rouge">artifacts/demo/report.html</code> to explore the evidence.</p>

<h2 id="a-small-example">A small example</h2>

<p>One example makes the purpose concrete. A deliberately broken reference driver interprets hexadecimal <code class="language-plaintext highlighter-rouge">FB2E</code> as an unsigned temperature value, producing <strong>643.02 °C</strong> instead of <strong>−12.34 °C</strong>. The report preserves the response bytes and the incorrect interpretation, making the mistake traceable.</p>

<figure class="experiment-figure compact">
  <a href="/assets/files/agentic-engineering/driver-signed-failure.png"><img src="/assets/files/agentic-engineering/driver-signed-failure.png" alt="DriverForge report showing expected minus 12.34 degrees Celsius and observed 643.02 after a deliberately incorrect unsigned decode." loading="lazy" width="755" height="1060" /></a>
  <figcaption>A seeded decoding defect under synthetic replay; no hardware measurement is involved.</figcaption>
</figure>

<h2 id="validation-and-limits">Validation and limits</h2>

<p>The publication audit passed <strong>100 tests</strong>. That includes six regressions added during publication review after discovering that report comparison missed changes to completion status and source evidence. Separately, the offline demo passes 39 reference cases and rejects six deliberately introduced defects.</p>

<p>I would treat this as a starting point for driver development. No physical instruments or independent practitioners have validated it. The reference protocols are fictional, Windows/Python 3.12 is the verified environment, and two synthetic fault cases still fail the upstream integration’s stated consumer contract. Those failures remain visible in the <a href="https://github.com/jewbee2000/driverforge/tree/main/evidence/article-audit">audit evidence</a>.</p>]]></content><author><name>Walter Teitelbaum</name><email>walter@teitelbaum.us</email></author><summary type="html"><![CDATA[A small Python tool for replaying protocol faults and inspecting how an instrument driver responds. Part of Walter Teitelbaum's two-day AI engineering experiment.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://walter.teitelbaum.us/assets/files/agentic-engineering/driver-signed-failure.png" /><media:content medium="image" url="https://walter.teitelbaum.us/assets/files/agentic-engineering/driver-signed-failure.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">3D Printed Bicycle Components</title><link href="https://walter.teitelbaum.us/2025/04/01/3D-Printed-Bicycle-Components/" rel="alternate" type="text/html" title="3D Printed Bicycle Components" /><published>2025-04-01T00:00:00-07:00</published><updated>2025-04-01T00:00:00-07:00</updated><id>https://walter.teitelbaum.us/2025/04/01/3D%20Printed%20Bicycle%20Components</id><content type="html" xml:base="https://walter.teitelbaum.us/2025/04/01/3D-Printed-Bicycle-Components/"><![CDATA[<p>My buddy <a href="https://www.youtube.com/@archmdz">Ari Klau</a> is a badass professional triathlete. However, he has not seen much financial success in the sport yet and does not have a bicycle brand as a sponsor. The sport of triathlon is extremely dependent on marginal gains in aerodynamics for competitive success. The fastest athletes in the world spend countless hours in the wind tunnel, testing various components and positions on the bicycle to become as slippery as possible.</p>

<p>Without access to resources like that, I have been using my knowledge of aerodynamics to design and print various components for Ari’s race bike in order to give him an opportunity to compete with the best in the world.</p>

<p><img src="https://walter.teitelbaum.us/assets/files/Sketch.jpg" alt="Sketch" title="Some Sketches" /></p>

<p><img src="https://walter.teitelbaum.us/assets/files/Scott%20Fairing.jpg" alt="Scott Plasma Fairing" title="Fairing for Scott Plasma RC" /></p>

<p><img src="https://walter.teitelbaum.us/assets/files/Scott%20FEA.jpg" alt="Scott FEA" title="FEA on an adapter piece" /></p>

<p><img src="https://walter.teitelbaum.us/assets/files/Speedmax%20Bottle%20Riser.jpg" alt="Speedmax Bottle Riser" title="Bottle Riser for Canyon Speedmax" /></p>]]></content><author><name>Walter Teitelbaum</name><email>walter@teitelbaum.us</email></author><summary type="html"><![CDATA[My buddy Ari Klau is a badass professional triathlete. However, he has not seen much financial success in the sport yet and does not have a bicycle brand as a sponsor. The sport of triathlon is extremely dependent on marginal gains in aerodynamics for competitive success. The fastest athletes in the world spend countless hours in the wind tunnel, testing various components and positions on the bicycle to become as slippery as possible.]]></summary></entry><entry><title type="html">Wooden Couch Riser</title><link href="https://walter.teitelbaum.us/2024/10/11/Theater-Riser/" rel="alternate" type="text/html" title="Wooden Couch Riser" /><published>2024-10-11T00:00:00-07:00</published><updated>2024-10-11T00:00:00-07:00</updated><id>https://walter.teitelbaum.us/2024/10/11/Theater%20Riser</id><content type="html" xml:base="https://walter.teitelbaum.us/2024/10/11/Theater-Riser/"><![CDATA[<p>Being the logician that I am, I generally tend to fabricate concepts for projects based on real problems that need solving. However, in this example, I fabricated a problem for myself, not because it needed solving, but because I was excited to solve it.</p>

<p>I have always had a love for classic cinema; at least ever since the age of 10 when my dad printed out the list of the 100 best movies of all time (<a href="https://www.afi.com/afis-100-years-100-movies-10th-anniversary-edition/">according to the American Film Institute</a>) and stapled it to the TV cabinet in our house, insisting that I watch every film before the age of 18. As a result of this “passion”, I of course now insist on educating all of my friends on all my favorite movies. This is the root cause of the problem I aimed to solve.</p>

<p>A few years back, while still living in Santa Cruz, CA, I purchased a surround sound system, projector, and 150-inch screen on Craigslist. This setup really did the trick, and completely satisfied my constant craving for visual media consumption. Unfortunately, it did not crave my irrepressible desire to educate everyone I know on classical cinema.</p>

<p>Luckily, when I moved to Seattle last January, I had an extra room in my house with plenty of room for my setup, and my mind began to churn on the idea of increasing the seating capacity in the theater.</p>

<p>It was on a chilly weekend in October that I insisted on borrowing my housemate’s truck to drive to Home Depot and pick up some lumber, carpet, and spray adhesive.</p>

<p>Conveniently, plywood comes in 4ft by 8ft sheets, which is the perfect size for a large couch plus some legroom. Lumber also comes in even lengths, which really minimized the quantity of scrap for this project.</p>

<p>I framed the platform by hand using a circular saw and a couple clamps. I wish I has a sawhorse for this job, but it didn’t seem like it was essential. Honestly had very few issues putting the whole thing together. The only real challenge was getting it into my house.</p>

<p><img src="https://walter.teitelbaum.us/assets/files/Theater5.jpg" alt="Picture 5" title="Picture 5" />
<img src="https://walter.teitelbaum.us/assets/files/Theater4.jpg" alt="Picture 4" title="Picture 4" />
<img src="https://walter.teitelbaum.us/assets/files/Theater3.jpg" alt="Picture 3" title="Picture 3" />
<img src="https://walter.teitelbaum.us/assets/files/Theater2.jpg" alt="Picture 2" title="Picture 2" />
<img src="https://walter.teitelbaum.us/assets/files/Theater1.jpg" alt="Picture 1" title="Picture 1" /></p>]]></content><author><name>Walter Teitelbaum</name><email>walter@teitelbaum.us</email></author><summary type="html"><![CDATA[Being the logician that I am, I generally tend to fabricate concepts for projects based on real problems that need solving. However, in this example, I fabricated a problem for myself, not because it needed solving, but because I was excited to solve it.]]></summary></entry><entry><title type="html">Word Chain</title><link href="https://walter.teitelbaum.us/2024/04/02/Word-Chain/" rel="alternate" type="text/html" title="Word Chain" /><published>2024-04-02T00:00:00-07:00</published><updated>2024-04-02T00:00:00-07:00</updated><id>https://walter.teitelbaum.us/2024/04/02/Word%20Chain</id><content type="html" xml:base="https://walter.teitelbaum.us/2024/04/02/Word-Chain/"><![CDATA[<h1 id="compound-noun-chain-game">Compound Noun Chain Game</h1>

<p>This is a web-based daily game (like wordle) where players find a chain of compound nouns from noun-A to noun-B. Each entered noun is validated to form a compound noun with the previous noun. If a prefix chain is invalid, progress cannot be made until the last noun in the chain is cleared and replaced with a valid compound. If noun-B is reached, the user’s solution is registered, something celebratory happens, and the user’s cumulative stats are shown.</p>

<p><img src="https://walter.teitelbaum.us/assets/files/word_chain.png" alt="Screenshot" title="Screenshot" /></p>

<h1 id="-wordchain-game-backend">🧩 Wordchain Game Backend</h1>

<p>My dad invented this game, but I wrote the whole backend and frontend implementation. I coded the app with <strong>Ruby</strong> and the <strong>Sinatra</strong> framework. It utilizes <strong>ActiveRecord</strong> for database management and <strong>Redis</strong> for fast caching and word validation.</p>

<p>The backend handles:</p>
<ul>
  <li>User interaction and session tracking</li>
  <li>Word chain validation logic</li>
  <li>User statistics management and persistence</li>
</ul>

<hr />

<h2 id="-technologies-used">🔧 Technologies Used</h2>

<ul>
  <li><strong><a href="http://sinatrarb.com/">Sinatra</a></strong> – Lightweight Ruby web framework for HTTP routing</li>
  <li><strong><a href="https://guides.rubyonrails.org/active_record_basics.html">ActiveRecord</a></strong> – ORM for interacting with the database</li>
  <li><strong><a href="https://redis.io/">Redis</a></strong> – In-memory data structure store for compound noun validation</li>
  <li><strong><a href="https://github.com/cyu/rack-cors">Rack::Cors</a></strong> – Middleware for Cross-Origin Resource Sharing</li>
  <li><strong><a href="https://www.sqlite.org/index.html">SQLite3</a></strong> – Simple file-based relational database</li>
</ul>

<hr />

<h2 id="-project-structure">📁 Project Structure</h2>

<h3 id="apprb"><code class="language-plaintext highlighter-rouge">app.rb</code></h3>
<p>Main Sinatra app file:</p>
<ul>
  <li>Defines core API routes:
    <ul>
      <li><code class="language-plaintext highlighter-rouge">GET /game</code> – Retrieve game data</li>
      <li><code class="language-plaintext highlighter-rouge">GET /stats</code> – Get user statistics</li>
      <li><code class="language-plaintext highlighter-rouge">POST /chain</code> and <code class="language-plaintext highlighter-rouge">POST /soln</code> – Validate submitted word chains</li>
    </ul>
  </li>
  <li>Initializes Redis</li>
  <li>Includes helper methods for standardized responses and validation</li>
</ul>

<h3 id="modelsuserrb"><code class="language-plaintext highlighter-rouge">models/user.rb</code></h3>
<p>Defines the <code class="language-plaintext highlighter-rouge">User</code> model with the following attributes:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">uuid</code></li>
  <li><code class="language-plaintext highlighter-rouge">won</code></li>
  <li><code class="language-plaintext highlighter-rouge">current_streak</code></li>
  <li><code class="language-plaintext highlighter-rouge">max_streak</code></li>
</ul>

<p>These fields track user-specific performance stats.</p>

<h3 id="modelsinitrb"><code class="language-plaintext highlighter-rouge">models/init.rb</code></h3>
<p>Initializes all models:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">User</code></li>
  <li><code class="language-plaintext highlighter-rouge">Game</code></li>
  <li><code class="language-plaintext highlighter-rouge">Solution</code></li>
</ul>

<h3 id="dbschemarb"><code class="language-plaintext highlighter-rouge">db/schema.rb</code></h3>
<p>Represents the current schema definition for the SQLite3 database:</p>
<ul>
  <li>Tables: <code class="language-plaintext highlighter-rouge">users</code>, <code class="language-plaintext highlighter-rouge">games</code>, <code class="language-plaintext highlighter-rouge">solutions</code></li>
</ul>

<h3 id="dbmigrate"><code class="language-plaintext highlighter-rouge">db/migrate/...</code></h3>
<p>Includes a migration that updates the <code class="language-plaintext highlighter-rouge">shortest_path</code> column in the <code class="language-plaintext highlighter-rouge">games</code> table (from string to integer).</p>

<h3 id="utilscsv2redisrb"><code class="language-plaintext highlighter-rouge">utils/csv2redis.rb</code></h3>
<p>Utility script for populating Redis from a CSV file:</p>
<ul>
  <li>Normalizes compound nouns</li>
  <li>Loads them into Redis for fast lookup during gameplay</li>
</ul>

<h3 id="specapp_specrb"><code class="language-plaintext highlighter-rouge">spec/app_spec.rb</code></h3>
<p>RSpec tests to verify:</p>
<ul>
  <li>Core routes (<code class="language-plaintext highlighter-rouge">/</code>, <code class="language-plaintext highlighter-rouge">/game</code>, <code class="language-plaintext highlighter-rouge">/stats</code>) are working correctly</li>
  <li>Application behavior meets expectations</li>
</ul>

<h3 id="gemfile"><code class="language-plaintext highlighter-rouge">Gemfile</code></h3>
<p>Declares all gem dependencies:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">sinatra</code>, <code class="language-plaintext highlighter-rouge">activerecord</code>, <code class="language-plaintext highlighter-rouge">redis</code>, <code class="language-plaintext highlighter-rouge">rspec</code>, etc.</li>
</ul>

<h3 id="configru"><code class="language-plaintext highlighter-rouge">config.ru</code></h3>
<p>Rack configuration file used to launch the Sinatra server.</p>

<h3 id="rakefile"><code class="language-plaintext highlighter-rouge">Rakefile</code></h3>
<p>Defines database tasks using Rake and ActiveRecord, such as:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">db:migrate</code></li>
  <li><code class="language-plaintext highlighter-rouge">db:seed</code></li>
</ul>

<hr />

<h2 id="-purpose-and-architecture">🚀 Purpose and Architecture</h2>

<p>The backend serves as the core logic engine for a wordchain game. It:</p>

<ul>
  <li>Validates compound nouns using Redis for quick access</li>
  <li>Tracks and persists user streaks and wins</li>
  <li>Provides HTTP endpoints for frontend integration</li>
</ul>

<h3 id="components">Components:</h3>

<table>
  <thead>
    <tr>
      <th>Layer</th>
      <th>Technology</th>
      <th>Role</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Web Server</td>
      <td>Sinatra</td>
      <td>Handles HTTP requests</td>
    </tr>
    <tr>
      <td>Persistence</td>
      <td>SQLite3</td>
      <td>Stores user and game data</td>
    </tr>
    <tr>
      <td>Caching/Logic</td>
      <td>Redis</td>
      <td>Validates compound words and fast lookup</td>
    </tr>
    <tr>
      <td>ORM</td>
      <td>ActiveRecord</td>
      <td>Maps Ruby objects to DB records</td>
    </tr>
  </tbody>
</table>

<hr />

<h2 id="dictionary-api">Dictionary API</h2>

<p>The Dictionary API validates prefix chains of compound nouns:</p>

<p>GET /q?w[]=cow&amp;w[]=bell&amp;w[]=hop&amp;…</p>

<p>It responds with JSON <code class="language-plaintext highlighter-rouge">{“result”:0}</code> or <code class="language-plaintext highlighter-rouge">{“result”:1}</code> indicating whether the given array of words is a valid chain of compound nouns.</p>

<h2 id="backend-api">Backend API</h2>

<p>The API endpoints are as follows:</p>

<h3 id="get-game">GET /game</h3>

<p>Responds with the daily game. E.g.</p>

<p>{“from”:”dog”,”to”:”blade”,”steps”:6,”expires”:ts}</p>

<h3 id="get-stats">GET /stats</h3>

<p>Responds with the user’s stats. E.g.</p>

<p>{“played”:100,”won”:60,”current_streak”:6,”max_streak”:10,”dist”:[60,20,10,2,1,1,7]}</p>

<p>“dist” is a distribution of the user’s solutions: +0 (i.e. shortest valid solution), +1, +2, +3, +4, +5, +more than 5.</p>

<h3 id="put-soln">PUT /soln</h3>

<p>Allows the user to submit a solution to the daily game. Responds with a success Boolean and the updated user stats.</p>

<h2 id="tables">Tables</h2>

<h3 id="games">Games</h3>

<p>Associations: <code class="language-plaintext highlighter-rouge">has_many solutions</code></p>

<p>Fields: Game number, Date, Start word, End word, Shortest path</p>

<h3 id="users">Users</h3>

<p>Associations: <code class="language-plaintext highlighter-rouge">has_many solutions</code></p>

<p>Fields: UUID, Won, Current_streak, Max_streak, Plus_1, Plus_2, Plus_3, Plus_4, Plus_5, Plus_more</p>

<h3 id="solutions">Solutions</h3>

<p>Associations: <code class="language-plaintext highlighter-rouge">belongs_to Game</code>, <code class="language-plaintext highlighter-rouge">belongs_to User</code></p>

<p>Fields: User_id, Game_id, Timestamp, Chain (comma-separated list of words)</p>

<h2 id="authentication">Authentication</h2>

<p>Anonymous identity is provided through a UUID stored in a cookie. Best practices should be adopted for using this cookie to create a secure authenticated session with the user.</p>

<h2 id="game-generation">Game Generation</h2>

<p>Daily games will be pre-generated (e.g. a year in advance) with offline tools that Ben and Louis have written, manually created, and stored in a table on the backend server.</p>]]></content><author><name>Walter Teitelbaum</name><email>walter@teitelbaum.us</email></author><summary type="html"><![CDATA[Compound Noun Chain Game]]></summary></entry><entry><title type="html">Modular Drive-by-Wire System</title><link href="https://walter.teitelbaum.us/2022/05/23/Senior-Design-Project/" rel="alternate" type="text/html" title="Modular Drive-by-Wire System" /><published>2022-05-23T00:00:00-07:00</published><updated>2022-05-23T00:00:00-07:00</updated><id>https://walter.teitelbaum.us/2022/05/23/Senior%20Design%20Project</id><content type="html" xml:base="https://walter.teitelbaum.us/2022/05/23/Senior-Design-Project/"><![CDATA[<p class="message"><strong>Note</strong> This project was graciously funded by Dr. Ricardo Sanfelice and the Hybrid Systems Labratory at the University of California: Santa Cruz</p>

<p>This group project was supervised by Tela Favaloro and Stephen C Petersen as a component of the ECE129 (Formerly EE 129A) Engineering Capstone through the Baskin School of Engineering. The project took place from October 2021 - May 2022.</p>

<p><img src="https://walter.teitelbaum.us/assets/files/Poster%20Presentation_23-05.jpg" alt="Poster Presentation" title="Final Poster" /></p>

<p><a href="https://walter.teitelbaum.us/assets/files/Final Report.pdf">Click Here to download the Final Report</a></p>

<p><a href="https://walter.teitelbaum.us/assets/files/Design Brief v3.pdf">Click Here to download the Design Brief</a></p>]]></content><author><name>Walter Teitelbaum</name><email>walter@teitelbaum.us</email></author><summary type="html"><![CDATA[Note This project was graciously funded by Dr. Ricardo Sanfelice and the Hybrid Systems Labratory at the University of California: Santa Cruz]]></summary></entry><entry><title type="html">Automated Pruning for Polyculture</title><link href="https://walter.teitelbaum.us/2021/07/25/Automated-Pruning-for-Polyculture/" rel="alternate" type="text/html" title="Automated Pruning for Polyculture" /><published>2021-07-25T00:00:00-07:00</published><updated>2021-07-25T00:00:00-07:00</updated><id>https://walter.teitelbaum.us/2021/07/25/Automated%20Pruning%20for%20Polyculture</id><content type="html" xml:base="https://walter.teitelbaum.us/2021/07/25/Automated-Pruning-for-Polyculture/"><![CDATA[<p class="message"><strong>Note</strong> This project was graciously funded by Dr. Ken Goldberg and the UC Berkeley <a href="https://autolab.berkeley.edu/">AUTOLab</a> as part of the <a href="https://github.com/BerkeleyAutomation/AlphaGarden">Alphagarden</a> Project</p>

<p>This summer I did a few weeks of volunteer research at UC Berkeley. I was asked to design a pruning attachment for the <a href="https://farm.bot/?srsltid=AfmBOoqRhzMuiJLiP-o9ItITznpnXR070whCaood9Z0IdypC3U3dJaiO">FarmBot</a> that the AUTOLab had purchased in order to do a real-life demo of their polyculture optimization software.</p>

<p>When I showed up, the FarmBot had already planted a large gardenbox filled with various seeds acording to a deep-learning based maximization algoritm. The garden layout was simulated in a custom OpenAI gym reinforcement learning environment and compared to the physical testbed.</p>

<p>I decided to design a 3-axis servo arm and used a sharp pair of Japanese topiary shears as an end effector. I was able to have the new design working within two weeks! Here is the end result:</p>

<p><img src="https://walter.teitelbaum.us/assets/files/Shears2.png" alt="CAD Model" title="CAD Model" />
<img src="https://walter.teitelbaum.us/assets/files/Shears1.png" alt="Walt's Pruning Attachment" title="Walt's Pruning Attachment" /></p>

<p>I also contributed several paragraphs to <a href="https://ieeexplore.ieee.org/abstract/document/10506760">“Automated Pruning and Irrigation of Polyculture Plants”</a> which was ultimately published in <a href="https://ieeexplore.ieee.org/xpl/RecentIssue.jsp?punumber=8856">IEEE Transactions on Automation Science and Engineering</a> ( Volume: 21, <a href="https://ieeexplore.ieee.org/xpl/tocresult.jsp?isnumber=10631719&amp;punumber=8856">Issue: 3</a>, July 2024)</p>

<p><a href="https://cad.onshape.com/documents/19c47b2204936e0e6afb5d5f/w/8c687fab2e1043ea59059492/e/a7e77233d09cace7d0dfaa54">Link to my CAD files</a></p>]]></content><author><name>Walter Teitelbaum</name><email>walter@teitelbaum.us</email></author><summary type="html"><![CDATA[Note This project was graciously funded by Dr. Ken Goldberg and the UC Berkeley AUTOLab as part of the Alphagarden Project]]></summary></entry></feed>