<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: E F</title>
    <description>The latest articles on DEV Community by E F (@efa).</description>
    <link>https://dev.to/efa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4035818%2F5f3adf1a-c519-4f4b-b67d-6a0e58016c84.jpg</url>
      <title>DEV Community: E F</title>
      <link>https://dev.to/efa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/efa"/>
    <language>en</language>
    <item>
      <title>Multi-stage interview process to fintech</title>
      <dc:creator>E F</dc:creator>
      <pubDate>Wed, 26 Aug 2026 17:40:41 +0000</pubDate>
      <link>https://dev.to/efa/multi-stage-interview-process-to-fintech-3j9f</link>
      <guid>https://dev.to/efa/multi-stage-interview-process-to-fintech-3j9f</guid>
      <description>&lt;h1&gt;
  
  
  ᯅ Multi-Stage Interview Process to Fintech
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;⚡ &lt;strong&gt;Did I get an offer?&lt;/strong&gt; I will leave the answer for the end.&lt;br&gt;&lt;br&gt;
✉ If you want to know the real name of fintech company R, message me on LinkedIn and like any post: &lt;a href="https://www.linkedin.com/in/egor-f-a214b2411/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/egor-f-a214b2411/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;𝙿𝚢𝚝𝚑𝚘𝚗 · 𝐌𝐋 · 𝙰𝙸 𝐚𝐠𝐞𝐧𝐭𝐬 · 𝚁𝙰𝙶 · 𝐬𝐲𝐬𝐭𝐞𝐦 𝐝𝐞𝐬𝐢𝐠𝐧&lt;br&gt;&lt;br&gt;
⏱ Eight stages, several teams, live coding, RAG, agents, and a final round.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They actually reached out to me first, even though I had tried several times to get into this fintech company myself.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙ 1-stage: Demo Day
&lt;/h2&gt;

&lt;p&gt;My way into the company started with what they called a &lt;strong&gt;Demo Day&lt;/strong&gt;, where it was possible to get an offer in a single day.&lt;/p&gt;

&lt;p&gt;It started with Python.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; Why would you use &lt;code&gt;TypeVar&lt;/code&gt; and &lt;code&gt;Protocol&lt;/code&gt;?&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Answer:&lt;/strong&gt; &lt;code&gt;TypeVar&lt;/code&gt; connects an input type with an output type, while &lt;code&gt;Protocol&lt;/code&gt; defines an interface through duck typing. Inheritance is not the important part: having the required methods is. They also asked about mutable default arguments. &lt;code&gt;def f(x, l=[])&lt;/code&gt; creates that list once, when the function is defined, so a dataclass needs &lt;code&gt;default_factory=list&lt;/code&gt; for a list field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; What does the GIL actually limit, and where does &lt;code&gt;asyncio&lt;/code&gt; fit?&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Answer:&lt;/strong&gt; In CPython, only one thread executes Python bytecode inside a process at a time. Threads are mainly useful for I/O, while processes are better for CPU-bound work. &lt;code&gt;asyncio&lt;/code&gt; is concurrent execution of coroutines inside an event loop. It works well for HTTP, databases, and files, but not for heavy CPU workloads. &lt;code&gt;ContextVar&lt;/code&gt; stores a separate context value for every async task, so values do not get mixed together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; What is the difference between &lt;code&gt;__new__&lt;/code&gt; and &lt;code&gt;__init__&lt;/code&gt;, and where can recursion appear?&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Answer:&lt;/strong&gt; &lt;code&gt;__new__&lt;/code&gt; creates an object; &lt;code&gt;__init__&lt;/code&gt; initializes it. &lt;code&gt;__getattribute__&lt;/code&gt; runs on every attribute access, while &lt;code&gt;__getattr__&lt;/code&gt; runs only when an attribute is not found. Calling &lt;code&gt;self.name&lt;/code&gt; from inside &lt;code&gt;__getattribute__&lt;/code&gt; can create infinite recursion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; How does Python execute code?&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Answer:&lt;/strong&gt; Tokenization, AST, bytecode, then execution by the virtual machine. That is why Python both compiles to bytecode and is interpreted.&lt;/p&gt;

&lt;p&gt;⌚ Two hours after I learned that I had passed the first filter, I went to the second part, where I got window-based tasks.&lt;/p&gt;

&lt;p&gt;The first task was a rate limiter using a sliding window. The naive approach filters the whole request list in &lt;code&gt;O(n)&lt;/code&gt;. The better approach uses a &lt;code&gt;deque&lt;/code&gt;: remove expired timestamps from the left and get close to &lt;code&gt;O(1)&lt;/code&gt; work per request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;

&lt;span class="n"&gt;window_to_see&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;limit_to_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="c1"&gt;# requests[user_id] = []
&lt;/span&gt;
    &lt;span class="c1"&gt;# Naive O(n) approach:
&lt;/span&gt;    &lt;span class="c1"&gt;# new_requests = []
&lt;/span&gt;    &lt;span class="c1"&gt;# for ts in requests[user_id]:
&lt;/span&gt;    &lt;span class="c1"&gt;#     if ts &amp;gt; now - window_to_see:
&lt;/span&gt;    &lt;span class="c1"&gt;#         new_requests.append(ts)
&lt;/span&gt;    &lt;span class="c1"&gt;# requests[user_id] = new_requests
&lt;/span&gt;
    &lt;span class="c1"&gt;# Move from O(n) to O(1)
&lt;/span&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;window_to_see&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;popleft&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;limit_to_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They also asked how &lt;strong&gt;ML CI/CD&lt;/strong&gt; differs from regular CI/CD. In a regular pipeline, you build an artifact such as a Docker image and deploy it. The main criterion is whether tests passed.&lt;/p&gt;

&lt;p&gt;ML CI/CD has extra moving parts: &lt;strong&gt;versioned data&lt;/strong&gt;, &lt;strong&gt;models as artifacts&lt;/strong&gt;, and &lt;strong&gt;quality metrics&lt;/strong&gt; such as accuracy, F1 score, and latency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Data validation:
--drift-threshold 0.1

If the distribution moves by more than 10%, fail the pipeline.

Nightly retraining:
schedule:
  - cron: "0 2 * * *"

Evaluation gate:
--min-improvement 0.02

Deploy only if F1 improves by at least 2%.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;F1 is the balance between precision and recall.&lt;/p&gt;

&lt;p&gt;Then came an &lt;code&gt;ErrorCounter&lt;/code&gt; task: &lt;code&gt;ingest&lt;/code&gt; accepts error codes and timestamps, &lt;code&gt;get_top_3&lt;/code&gt; returns the three most frequent codes over the last &lt;code&gt;n&lt;/code&gt; minutes, and &lt;code&gt;get_total_errors&lt;/code&gt; returns the total error count. Calls arrive in chronological order, and multiple errors can happen in the same second.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;

&lt;span class="n"&gt;ErrorCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ErrorCounter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ErrorCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ingest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ErrorCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_top_3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;n_mins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ErrorCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
        &lt;span class="n"&gt;start_timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;n_mins&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error_timestamp&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start_timestamp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;error_timestamp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_total_errors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ErrorCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ingest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;E1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ingest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;E2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ingest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;E1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ingest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_top_3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# [('E1', 2), ('E2', 1), (500, 1)]
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_total_errors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# 4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✦ I solved the tasks and my tests passed. One of the interviewer’s tests for the second task did not pass, though. He even said he did not know why it was failing, then said: “Well, never mind. The important part is that yours passed.” Then we went back to theory.&lt;/p&gt;

&lt;p&gt;After &lt;code&gt;ErrorCounter&lt;/code&gt;, they asked what meaningful work I had done in my latest project. I said that I had improved &lt;strong&gt;recall&lt;/strong&gt; in a RAG system.&lt;/p&gt;

&lt;p&gt;Then came regression, classification, and regularization. One question was whether regression could be used to solve a classification problem. My answer was: technically yes, but it would not make much sense. We also discussed the sigmoid function.&lt;/p&gt;

&lt;p&gt;After that, we moved through the NLP timeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bag of Words&lt;/strong&gt; treats words as indices. &lt;strong&gt;TF-IDF&lt;/strong&gt; stands for Term Frequency and Inverse Document Frequency. Term Frequency is how often a word occurs in a text. Inverse Document Frequency lowers the weight of words that appear everywhere.&lt;/p&gt;

&lt;p&gt;TF-IDF is a cheap way to turn words into numbers for search and classification. BoW counts frequency; TF-IDF adds importance. Its limitations are clear: it does not understand context, and sparse vectors contain a lot of zeros. A practical trick is using n-grams, where you consider neighboring words rather than one word in isolation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.feature_extraction.text&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TfidfVectorizer&lt;/span&gt;

&lt;span class="n"&gt;texts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python python python django&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python python python fastapi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python python python sklearn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;django&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fastapi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sklearn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;tfidf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TfidfVectorizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vocabulary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tfidf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;texts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toarray&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;#    python  django  fastapi  sklearn
# 0   0.872   0.490    0.000    0.000
# 1   0.872   0.000    0.490    0.000
# 2   0.872   0.000    0.000    0.490
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;python&lt;/code&gt; appears in all three texts, so its IDF is low. &lt;code&gt;django&lt;/code&gt;, &lt;code&gt;fastapi&lt;/code&gt;, and &lt;code&gt;sklearn&lt;/code&gt; occur in only one document each, so their IDF is higher.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BM25&lt;/strong&gt; improves on TF-IDF by taking document length into account, giving more flexible tuning and usually better ranking.&lt;/p&gt;

&lt;p&gt;Then came &lt;strong&gt;Word2Vec&lt;/strong&gt;. These are dense but non-contextual embeddings. The classic example is &lt;code&gt;king - man + woman = queen&lt;/code&gt;. CBOW predicts one word from several context words and is usually faster. Skip-gram predicts several context words from one target word and works well with rare words and smaller corpora. Negative Sampling updates positive and randomly sampled negative pairs instead of the entire vocabulary.&lt;/p&gt;

&lt;p&gt;After Word2Vec came &lt;strong&gt;GloVe&lt;/strong&gt; and &lt;strong&gt;FastText&lt;/strong&gt;. GloVe relies on a large word co-occurrence matrix; adding a new word changes the matrix and requires recalculation. FastText extends Word2Vec with character n-grams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RNNs&lt;/strong&gt; process sequences step by step, passing hidden state forward. They cannot parallelize sequence processing and suffer from vanishing gradients. &lt;strong&gt;CNNs&lt;/strong&gt; reuse the same filter across positions but only see local neighborhoods. &lt;strong&gt;LSTMs&lt;/strong&gt; use a memory cell with input, forget, and output gates, so they preserve context better than a simple RNN, although they are slow.&lt;/p&gt;

&lt;p&gt;Then came the GPT history: GPT-1 was a decoder-only Transformer trained for next-token prediction, then adapted for downstream tasks. GPT-2 became a larger zero-shot model. GPT-3 showed few-shot in-context learning without changing weights. InstructGPT added SFT on instruction-answer pairs and RLHF. ChatGPT became a dialogue system with alignment, tools, feedback, web search, vector search, code execution, human-in-the-loop flows, guardrails, multimodality, and memory.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⏲ I did not reach the final through the first Demo Day, but I did get into the hiring funnel.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⛓ 2-stage: AI Agents
&lt;/h2&gt;

&lt;p&gt;The next stage was about agent architecture and coding in Google Colab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://colab.research.google.com/" rel="noopener noreferrer"&gt;https://colab.research.google.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They asked what an agent consists of, how to design its architecture, what to keep in memory, how it calls tools, and where checks should live.&lt;/p&gt;

&lt;p&gt;My agent runtime looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;External events / cron / user messages
                |
                v
        Event router / FSM start
                |
                v
      Context and tool router
                |
      +---------+----------+-----------------+
      |         |          |                 |
      v         v          v                 v
Vector search  Web search  Community RAG   User data
      |         |          |                 |
      +---------+----------+-----------------+
                |
                v
      Context aggregator + cache
                |
                v
         Planner -&amp;gt; Reviewer
                |
                v
  Chain classifier -&amp;gt; block constructor
                |
                v
      Local tests -&amp;gt; global validation
                |
                v
        Escalation guard / HITL
                |
                v
             Finalizer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Google Colab, there was Pandas and live code review rather than a separate algorithmic challenge. They checked &lt;code&gt;__call__&lt;/code&gt;, the Singleton pattern, an object behaving like a function, and similar Python mechanics. It was mostly about how I write and explain code in real time.&lt;/p&gt;

&lt;p&gt;The agent runtime itself was a visual finite-state machine with more than twenty sub-agents, hooks, tools, and webhooks for inbound and outbound conversations. There was debounce, PII removal, and omnichannel communication through a chatbot and a mini landing page.&lt;/p&gt;

&lt;p&gt;For memory, I described &lt;strong&gt;short-term memory&lt;/strong&gt; as context-window management, compactization, invalidation, extension, caching, and message history. &lt;strong&gt;Long-term memory&lt;/strong&gt; was a vector database with episodic and semantic memory.&lt;/p&gt;

&lt;p&gt;Localization was not just translation. It meant preserving meaning, terminology, tone, channel-specific style, cultural context, sensitive fragments, ambiguity, and confidence level.&lt;/p&gt;

&lt;p&gt;The architecture choices were a single agent for linear workflows, a router that sends money questions to an accounting agent and bug questions to a technical agent, or multi-agent collaboration, such as one agent writing SQL and another reviewing it.&lt;/p&gt;

&lt;p&gt;Testing was especially important. An agent should never promise a refund before checking an order in the database. It should not confirm discounts that do not exist in CRM. It must ignore instructions to forget or change its system prompt. If a customer asks for an individual price, it should say: “I am not authorized to change the price. I will forward this request to a manager.”&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠ Adversarial checks: will the agent give a 99% discount, leak its system prompt, become rude, run a dangerous command, promise a refund without verification, or ignore the policy after “forget your previous instructions”?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The metrics were &lt;strong&gt;accuracy&lt;/strong&gt;, &lt;strong&gt;deflection rate&lt;/strong&gt;, and &lt;strong&gt;CSAT&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⌖ 3-stage: Algorithmic Interview
&lt;/h2&gt;

&lt;p&gt;I was redirected to another team, and the process almost restarted: repeated theory plus another algorithmic interview.&lt;/p&gt;

&lt;p&gt;This became a real multi-stage process. Teams could redirect candidates between each other, and by the time you are moving through the pipeline, the original opening may no longer be the exact role you started with.&lt;/p&gt;

&lt;p&gt;The coding platform for this stage was LeetCode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/" rel="noopener noreferrer"&gt;https://leetcode.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first task was &lt;code&gt;PALINDROME&lt;/code&gt;. The first version creates a cleaned string. The second version uses two pointers and does not allocate a new string. Its complexity is &lt;code&gt;O(n)&lt;/code&gt; time and &lt;code&gt;O(1)&lt;/code&gt; additional memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;cleaned&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isalnum&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;cleaned&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cleaned&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;cleaned&lt;/span&gt;&lt;span class="p"&gt;[::&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;is_palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A man, a plan, a canal: Panama&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# True
&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;is_palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;race a car&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# False
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;isalnum&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;isalnum&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

        &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second task was sorting ages with counting sort. Since valid ages are in the &lt;code&gt;0..120&lt;/code&gt; range, we count each age first and then write them back in order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;f1.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;f2.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;MAX_AGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;
    &lt;span class="n"&gt;WRITE_BATCH_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000&lt;/span&gt;
    &lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_AGE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# First pass: count people of each age.
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;f1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="c1"&gt;# Second pass: write ages in order.
&lt;/span&gt;    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_AGE&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;how_many_people&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;one_person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;how_many_people&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;how_many_people&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WRITE_BATCH_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;f2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;one_person&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;how_many_people&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;∑ Time complexity: &lt;code&gt;O(n + k)&lt;/code&gt;&lt;br&gt;&lt;br&gt;
⌘ Memory complexity: &lt;code&gt;O(k)&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⚡ 4-stage: ML
&lt;/h2&gt;

&lt;p&gt;This was the ML section and an &lt;code&gt;ndcg_at_k&lt;/code&gt; task.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⌖ The live-coding room for this exact nDCG task was:&lt;br&gt;&lt;br&gt;
&lt;a href="https://interview.cups.online/live-coding/?room=7fdf45e7-fe28-4ee0-9df7-e049952f1ad0" rel="noopener noreferrer"&gt;https://interview.cups.online/live-coding/?room=7fdf45e7-fe28-4ee0-9df7-e049952f1ad0&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We calculate the metric for one query: search output is a list of document IDs sorted by descending score, labels are &lt;code&gt;{id: relevance}&lt;/code&gt;, relevance is an integer from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;3&lt;/code&gt;, gain is linear, and the discount is &lt;code&gt;log2(i + 1)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ndcg_at_k&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranked_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;relevance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;dcg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;idcg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ranked_ids&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;relevance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;dcg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ideal_dcg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relevance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ideal_dcg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;idcg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;idcg&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dcg&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;idcg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;rel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ndcg_at_k&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;1e-9&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ndcg_at_k&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.6458&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;1e-4&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ndcg_at_k&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.9152&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;1e-4&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ndcg_at_k&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;1e-9&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ndcg_at_k&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.2044&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;1e-4&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ndcg_at_k&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;0.9319&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;1e-4&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;ndcg_at_k&lt;/span&gt;&lt;span class="p"&gt;([],&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;ndcg_at_k&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;ndcg_at_k&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;All good!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;They also asked for definitions of retrieval and RAG metrics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recall@K&lt;/strong&gt; answers: what proportion of all relevant documents appears in top-K?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Recall@K = relevant documents in top-K / all relevant documents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It mostly ignores the order inside top-K. In RAG, this is critical. If the required document never reaches top-K, the LLM cannot use it in the answer. A concrete example: before improvements, the right document appeared in top-10 for 72 out of 100 queries; after improvements, it appeared for 88 out of 100.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MRR&lt;/strong&gt;, Mean Reciprocal Rank, measures how high the first relevant result appears. A relevant result in first position gives &lt;code&gt;1.0&lt;/code&gt;, in second position &lt;code&gt;0.5&lt;/code&gt;, in third position roughly &lt;code&gt;0.33&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MRR = 1/N * Σ(1/rank)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;MAP&lt;/strong&gt;, Mean Average Precision, is stricter. It cares about all relevant documents and their order, not just the first correct one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DCG&lt;/strong&gt; accounts for ranking order and graded relevance. &lt;strong&gt;NDCG&lt;/strong&gt; compares the real ranking with the ideal ranking, so it normally lies between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IDCG@3 = 3/log2(2) + 1/log2(3) = 3.631
NDCG = DCG / IDCG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HitRate@K&lt;/strong&gt; answers whether there is at least one relevant result in top-K. &lt;strong&gt;Precision@K&lt;/strong&gt; is relevant documents in top-K divided by K, which matters when you want clean context for the LLM. &lt;strong&gt;PFound&lt;/strong&gt; estimates whether a user is likely to find an answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MMR&lt;/strong&gt;, Maximal Marginal Relevance, is not a metric. It is a retrieval strategy that avoids selecting highly similar chunks. For example, retrieve &lt;code&gt;fetch_k = 10&lt;/code&gt; chunks and select a diverse &lt;code&gt;k = 3&lt;/code&gt;. A &lt;code&gt;lambda_mult&lt;/code&gt; close to &lt;code&gt;1.0&lt;/code&gt; favors relevance; closer to &lt;code&gt;0.0&lt;/code&gt; favors diversity.&lt;/p&gt;

&lt;p&gt;To choose &lt;code&gt;K&lt;/code&gt; for a retriever, I would test values such as &lt;code&gt;20&lt;/code&gt;, &lt;code&gt;50&lt;/code&gt;, &lt;code&gt;100&lt;/code&gt;, and &lt;code&gt;1000&lt;/code&gt;, and compare recall, &lt;code&gt;ndcg@K&lt;/code&gt;, MRR, p95/p99 latency, and API cost. I would choose the smallest K after which quality almost stops improving while latency and cost still fit the SLA.&lt;/p&gt;

&lt;p&gt;After generation, &lt;strong&gt;faithfulness&lt;/strong&gt; measures whether an answer is supported by context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Faithfulness = supported_claims / all_claims
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Answer relevance checks whether the answer actually answers the question. Context precision or relevance checks how much retrieved context is useful. Answer correctness asks whether the answer is correct. Context recall asks whether all necessary facts made it into the context.&lt;/p&gt;

&lt;p&gt;For generated text, they asked about &lt;strong&gt;G-Eval&lt;/strong&gt;, &lt;strong&gt;BLEU&lt;/strong&gt;, &lt;strong&gt;ROUGE&lt;/strong&gt;, and newer alternatives. G-Eval is LLM-as-a-judge with a numeric score for correctness, coherence, completeness, and relevance. BLEU compares n-grams with a reference and penalizes very short answers, but it does not understand meaning well. ROUGE-1/2/L is a recall-oriented family for summarization; ROUGE-L uses the longest common subsequence.&lt;/p&gt;

&lt;p&gt;FineSurE evaluates faithfulness, conciseness, and completeness. BLEURT and COMET are trained metrics. SEAHORSE evaluates clarity, repetition, grammar, factuality, key ideas, and conciseness. BERTScore compares semantic similarity through embeddings. For RAG, none of these is enough on its own, so much of modern validation uses LLM-as-a-judge.&lt;/p&gt;

&lt;p&gt;For the &lt;strong&gt;retriever pipeline&lt;/strong&gt;, they asked about Multiple Negatives Ranking Loss, InfoNCE or contrastive loss with in-batch negatives, and triplet margin loss. A bi-encoder or dual-encoder retriever is optimized for &lt;code&gt;Recall@K&lt;/code&gt;: the query should be closer to the relevant document and farther from negatives.&lt;/p&gt;

&lt;p&gt;For the &lt;strong&gt;reranker pipeline&lt;/strong&gt;, they asked about pointwise Binary Cross-Entropy or MSE on graded relevance; pairwise RankNet, BPR, and margin ranking loss; and listwise ListNet, ListMLE, and LambdaRank. A cross-encoder reranker puts top-K results in order, so the relevant metrics are &lt;code&gt;nDCG@K&lt;/code&gt;, MRR, and MAP.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚒ 5-stage: AI Agents
&lt;/h2&gt;

&lt;p&gt;This was another agent interview, but this time with Docker, model weights, MCP, and Transformers.&lt;/p&gt;

&lt;p&gt;One question was how to mount model weights. My answer: use a &lt;strong&gt;volume&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The harness runs the agent loop, connects tools and MCP servers, logs tool calls and token usage, runs evaluations, checks permissions, requires approval for dangerous actions, and stores the audit trail.&lt;/p&gt;

&lt;p&gt;For agent security, I split the answer into three layers: &lt;strong&gt;sandboxing&lt;/strong&gt;, &lt;strong&gt;permission model&lt;/strong&gt;, and &lt;strong&gt;audit trail&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sandboxing means isolated execution: a separate container or pod with CPU, memory, network, filesystem, and timeout restrictions. No access to secrets by default.&lt;/p&gt;

&lt;p&gt;The permission model defines allowed actions. Read-only tools can be available immediately. Deploy, delete, payment, database migration, email sending, and PII access require explicit approval. Permissions should be task-specific and scoped by user or admin role.&lt;/p&gt;

&lt;p&gt;The audit trail records who started the task, which prompt was used, which tools and arguments were called, which files changed, token usage, approvals, and the result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function calling&lt;/strong&gt; is a mechanism where the application exposes a function to the model. &lt;strong&gt;Tool calling&lt;/strong&gt; means calling external actions from a conversation, for example internal APIs, CRM, databases, or external sources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP&lt;/strong&gt;, Model Context Protocol, standardizes how an AI application connects to external systems. MCP consists of an MCP client, such as an IDE, agent, or chat application; an MCP server; tools as allowed actions; resources such as files and tables; and prompts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MCP flow:

Handshake
  -&amp;gt; tool discovery with parameters
  -&amp;gt; client request
  -&amp;gt; routing
  -&amp;gt; a specific tool response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tool is a function. MCP is a standardized client-server architecture around tools, resources, and prompts.&lt;/p&gt;

&lt;p&gt;To protect MCP, I mentioned OAuth, RBAC, scopes for every tool, allowlists, rate limits, audit logs, HITL, and prompt-injection defenses. External documents should be treated as untrusted data. System instructions should stay separate from retrieved content. Tool arguments must be validated, secrets should not be passed to the model, and critical operations should require human approval.&lt;/p&gt;

&lt;p&gt;For Transformers, I covered embeddings, positional information, and self-attention. Query, Key, and Value connect tokens in context. Multi-head attention captures different dependencies. Residual connections and normalization stabilize training. A decoder-only Transformer predicts the next token.&lt;/p&gt;

&lt;p&gt;There were also Kubernetes questions: deployments, services, ingress, environment variables and secrets, resource requests and limits, health checks, and autoscaling. Helm charts parameterize dev, stage, and production environments. GitLab CI/CD builds Docker images, runs tests and linters, pushes to a registry, and deploys through &lt;code&gt;helm upgrade&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Agent testing included routing tests, golden datasets, adversarial tests, replaying production traces, and shadow mode. Multi-agent workflows included thinking traces, streaming, vision with image bytes or base64, structured output through Pydantic or JSON, parallel tool calling, multi-turn tool calling through an agent loop, context-window management, heartbeats, and permission limits.&lt;/p&gt;

&lt;p&gt;Context compactization included summaries, key-fact extraction or NER, removing old tool results, deduplicating goals, constraints, tool results, file links, chunks, errors, and next actions. Older information can be retrieved when needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚲ Zero trust matters: agents should be isolated.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⚖ 6-stage: Principal Tech Lead, RAG
&lt;/h2&gt;

&lt;p&gt;This was a separate day and a separate stage: a short interview, around 30 minutes, with a Principal Tech Lead. It was heavy on RAG questions, not a continuation of the agent-architecture discussion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question:&lt;/strong&gt; What would you do if faithfulness dropped by 5% after the system was already in production?&lt;/p&gt;

&lt;p&gt;That led to follow-up questions: how to distinguish a retrieval problem from a generation problem; which offline and production metrics to inspect; how to build a golden dataset and replay production traces; how to compare old and new versions of the retriever, embeddings, chunking, reranker, and prompt; how to detect data drift and document freshness issues; and what to do when there is no source, insufficient context, or a hallucination.&lt;/p&gt;

&lt;p&gt;More RAG questions covered Recall@K, Precision@K, HitRate, MRR, MAP, DCG, and NDCG; which metrics belong to the retriever and which to the reranker; how to evaluate citations, answer relevance, context relevance, and faithfulness; why chunk size, overlap, metadata filters, query rewriting, hybrid search, BM25, vector search, RRF, and reranking matter; when to abstain or call a human; and how to use A/B testing, shadow mode, rollback, and versioning for data, indexes, embeddings, and models.&lt;/p&gt;

&lt;p&gt;On my previous project, I had improved RAG recall. The important part here was not one number. It was explaining where the loss came from: document indexing, chunking, retrieval, ranking, context construction, or the final answer, and proving it with data rather than intuition.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚙ 7-stage: System Design
&lt;/h2&gt;

&lt;p&gt;In system design, I did not list infrastructure components in isolation. I designed one system: RAG with hybrid search over corporate documents, returning an LLM answer with citations.&lt;/p&gt;

&lt;p&gt;I started with requirements: is it B2B, B2C, or internal? What are the document volume and freshness requirements? What is the SLA, peak QPS, read/write ratio, PII policy, and acceptable latency?&lt;/p&gt;

&lt;p&gt;The goal is not simply to produce text. It is to retrieve the required sources, send a controlled amount of context to the LLM, and return verifiable citations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⟁ Core metrics: &lt;strong&gt;faithfulness&lt;/strong&gt;, &lt;strong&gt;retrieval recall&lt;/strong&gt;, &lt;strong&gt;context size&lt;/strong&gt;, &lt;strong&gt;p50/p95/p99 latency&lt;/strong&gt;, &lt;strong&gt;RPS/QPS/tokens&lt;/strong&gt;, concurrency, CPU/GPU/database/network/storage usage.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Documents
  -&amp;gt; S3 / blob storage
  -&amp;gt; extraction and chunking
  -&amp;gt; PII filtering
  -&amp;gt; embeddings + metadata
  -&amp;gt; OpenSearch: BM25 + vector index

Query
  -&amp;gt; API Gateway
  -&amp;gt; hybrid retrieval: BM25 + kNN
  -&amp;gt; RRF / weighted score
  -&amp;gt; cross-encoder reranker
  -&amp;gt; top-K context
  -&amp;gt; LLM answer + citations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the query path, the API Gateway provides authentication, rate limiting, routing, observability, versioning, and X-API-Key validation. The query service sends the request to OpenSearch. BM25 provides lexical search, vector kNN provides semantic search, RRF or a weighted score combines results, and a cross-encoder reranker orders them. Then top-K chunks go into the LLM together with citations.&lt;/p&gt;

&lt;p&gt;Every component has a role in answer quality: the retriever owns recall, the reranker owns ranking order, and the LLM owns the final answer and faithfulness.&lt;/p&gt;

&lt;p&gt;The document path goes in the other direction. Raw files live in S3 or blob storage. Private files use pre-signed URLs with a signature and expiration time. An ingestion worker runs extraction, PII filtering, chunking, embedding, and indexing with metadata and ACL.&lt;/p&gt;

&lt;p&gt;I would not keep long-running ingestion inside an HTTP request. I would put it into Kafka, RabbitMQ, or SQS. I would not create a Kafka topic per user. Instead, there is a &lt;code&gt;user_events&lt;/code&gt; topic, and Kafka distributes users across partitions using &lt;code&gt;hash(user_id)&lt;/code&gt;. Consumer groups can read independently. Transactional outbox and idempotency prevent duplicate indexing or repeated operations. A DLQ collects documents that could not be processed.&lt;/p&gt;

&lt;p&gt;Storage is chosen by role. PostgreSQL or YandexDB stores tenants, users, ACL, job status, and relationships. PgBouncer limits physical connections from services and workers to the database; read replicas serve read traffic. OpenSearch or Elasticsearch handles ranking, aggregations, and hybrid retrieval. The vector index handles embedding search. ClickHouse or Snowflake can store query and quality analytics.&lt;/p&gt;

&lt;p&gt;MongoDB makes sense when the whole object is primarily JSON. ScyllaDB or Cassandra, with LSM storage, fit very high write throughput but do not replace PostgreSQL where joins and relationships matter. Neo4j is relevant only if the system adds graph permissions, social relationships, or fraud detection.&lt;/p&gt;

&lt;p&gt;Caching also belongs to this RAG task, not to a random infrastructure checklist. Browser cache, CDN, Nginx reverse proxy, external Redis, and internal cache reduce p95 for frequent queries and repeated retrieval. CDN pull works for ordinary static attachments; CDN push works when edge locations are prefilled.&lt;/p&gt;

&lt;p&gt;The DNS path is browser, DNS resolver, root DNS, &lt;code&gt;.com&lt;/code&gt; DNS, authoritative DNS, then IP, although in practice much of it is hidden behind TTL caching. Redis can hold query cache, sessions, rate-limit counters, and distributed locks. After a deployment, cold cache can be handled with cache warming. Redis Sentinel can switch the master after a failure. Invalidation is mandatory: otherwise the LLM may cite a document that was updated or closed.&lt;/p&gt;

&lt;p&gt;For this RAG endpoint, I would use Fixed Window, Sliding Window, or Token Bucket rate limiting at both Nginx and the endpoint level. Rate limiting only by IP is not enough because of proxies.&lt;/p&gt;

&lt;p&gt;Nginx can balance through Round Robin, Weighted Round Robin, Least Connections, Least Response Time, Random, or IP Hash. If services use gRPC with a long-lived HTTP/2 connection, an L7 load balancer is needed; otherwise one connection can break normal balancing.&lt;/p&gt;

&lt;p&gt;For resilience, I would use retries with exponential backoff and jitter, a Circuit Breaker with Closed/Open/Half-Open states for external embedding or LLM providers, and Bulkheads so one failed provider cannot consume all available resources.&lt;/p&gt;

&lt;p&gt;On the production side, that means metrics, logs, tracing, alerts, Sentry, documentation, and unit/integration/end-to-end tests. Security means roles, 2FA, HTTPS, access checks at the chunk and tenant level, guardrails, and HITL moderation for risky actions. Deployment should be zero-downtime, with several stateless workers, rate limits, and rollback.&lt;/p&gt;

&lt;p&gt;Strong consistency is needed for ACL updates and document deletion. Eventual consistency is acceptable when a new embedding appears in search a few seconds later.&lt;/p&gt;

&lt;p&gt;Sharding also belongs to this exact system when tenant and document counts grow. Options are range-based, hash-based with &lt;code&gt;hash(tenant_id) % N&lt;/code&gt;, directory-based with a separate mapping table, geographic, and time-span sharding. For vector or index nodes, consistent hashing minimizes data movement: if you move from nine servers to ten, roughly 10% of data moves instead of almost all data.&lt;/p&gt;

&lt;p&gt;For deep search results, I would use cursor or &lt;code&gt;search_after&lt;/code&gt; pagination because &lt;code&gt;offset&lt;/code&gt; becomes expensive. Metadata and ACL in the database are the source of truth; the search index is a rebuildable read model.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚖ The core trade-off: latency, consistency, cost, and retrieval freshness.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It was at system design that I finally reached the final, unlike the Demo Day, where I got into the funnel but did not reach the end.&lt;/p&gt;




&lt;h2&gt;
  
  
  ★ 8-stage: Final
&lt;/h2&gt;

&lt;p&gt;By the final, this was already the eighth stage.&lt;/p&gt;

&lt;p&gt;For some reason, the final questions were almost entirely about databases, message brokers, Kafka, Redis, RabbitMQ, replication, sharding, partitioning, microservices, and monoliths.&lt;/p&gt;

&lt;p&gt;Redis came up as cache, session storage, rate limiting, distributed locks, counters, and leaderboards. Kafka came up as a log with topics, partitions, consumer groups, DLQ, retries, idempotency, and transactional outbox. RabbitMQ came up as queues, routing, and acknowledgements.&lt;/p&gt;

&lt;p&gt;We discussed asynchronous and synchronous replication with read replicas. Partitioning means splitting a large table, for example by time. Sharding means distributing data across independent nodes by range, hash, directory, geography, or time span.&lt;/p&gt;

&lt;p&gt;A monolith makes sense for a local or early-stage product: it is easier to develop, deploy, and keep transactions consistent. Microservices make more sense for multiple geographies, independent business domains, and separate teams: auth, users, vehicles, rentals, payments, and notifications.&lt;/p&gt;

&lt;p&gt;Services should be stateless, so new instances can be started horizontally; databases are replicated. The trade-off is that microservices add network complexity, observability, schema evolution, distributed transactions, Saga patterns, retries, and idempotency.&lt;/p&gt;

&lt;p&gt;The system-design questions I now ask at the start are simple: What is the business goal? What are the functional and non-functional requirements? What are the constraints and success metrics? Is this B2C, B2B, or internal? What are DAU/MAU, peak QPS, growth, and read/write ratio? Does p95 need to be under 200 ms, or are 2-3 seconds acceptable? Do we need strong consistency or eventual consistency? Are real-time updates required? How many entities already exist, how many are created per day, and which fields are used for search and filtering?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;★ The whole process, from the Demo Day and getting into the funnel, took from &lt;strong&gt;July 4 to August 25, 2026&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fintech company R: I will reveal the real name on LinkedIn. Find me here, send me a DM, and like any post. I will reply:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/egor-f-a214b2411/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/egor-f-a214b2411/&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;∞ My main takeaway: in this company, teams choose candidates for themselves and, crucially, they do not see your results from previous interviews. That gives you a real chance to try again.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;blockquote&gt;
&lt;p&gt;✦ One last aside: here is another piece of code from one of my interviews:&lt;br&gt;&lt;br&gt;
&lt;a href="https://codeinterview.io/QJQIDBHIMS" rel="noopener noreferrer"&gt;https://codeinterview.io/QJQIDBHIMS&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Yes, that was also fintech, but another fintech, another story.. ♥&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>career</category>
      <category>interview</category>
      <category>python</category>
    </item>
    <item>
      <title>Technical Interview for an Agentic Technical Lead Role</title>
      <dc:creator>E F</dc:creator>
      <pubDate>Fri, 31 Jul 2026 16:36:34 +0000</pubDate>
      <link>https://dev.to/efa/technical-interview-for-an-agentic-technical-lead-role-5fee</link>
      <guid>https://dev.to/efa/technical-interview-for-an-agentic-technical-lead-role-5fee</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The company name has been slightly modified.&lt;br&gt;&lt;br&gt;
&lt;em&gt;(I will share the original company name after you subscribe to my DEV.to and &lt;a href="https://www.linkedin.com/in/egor-f-a214b2411" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/egor-f-a214b2411&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Today I had a real technical interview for an &lt;strong&gt;Agentic Technical Lead&lt;/strong&gt; position at &lt;strong&gt;4nd-ever&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The interview focused on LangGraph, MCP, LangFuse, evaluation, observability, routing, tool calling, and the architecture of production-ready agentic systems.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Role Overview
&lt;/h1&gt;

&lt;h2&gt;
  
  
  2.1. Main Goal
&lt;/h2&gt;

&lt;p&gt;The role was focused on building an internal platform that allows engineering teams to create, configure, evaluate, observe, and deploy agentic systems.&lt;/p&gt;

&lt;p&gt;The goal was not to build one AI agent. The goal was to build reusable infrastructure for many teams and use cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  2.2. Main Responsibilities
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Design an agentic systems framework.&lt;/li&gt;
&lt;li&gt;Build LangGraph-based orchestration.&lt;/li&gt;
&lt;li&gt;Create reusable MCP Server and MCP Client templates.&lt;/li&gt;
&lt;li&gt;Implement evaluation pipelines with LangFuse.&lt;/li&gt;
&lt;li&gt;Support datasets, experiments, and LLM-as-a-Judge.&lt;/li&gt;
&lt;li&gt;Add tracing, cost monitoring, latency metrics, and drift detection.&lt;/li&gt;
&lt;li&gt;Support RAG, tool calling, structured outputs, and prompt chaining.&lt;/li&gt;
&lt;li&gt;Provide reusable components through Backstage.&lt;/li&gt;
&lt;li&gt;Own production reliability, retries, fallbacks, releases, and rollbacks.&lt;/li&gt;
&lt;li&gt;Mentor engineers and define the platform roadmap.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2.3. Main Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;LangGraph&lt;/li&gt;
&lt;li&gt;LangFuse&lt;/li&gt;
&lt;li&gt;MCP Servers and Clients&lt;/li&gt;
&lt;li&gt;PostgreSQL&lt;/li&gt;
&lt;li&gt;Backstage&lt;/li&gt;
&lt;li&gt;AWS&lt;/li&gt;
&lt;li&gt;Kubernetes&lt;/li&gt;
&lt;li&gt;GitLab&lt;/li&gt;
&lt;li&gt;Vector databases&lt;/li&gt;
&lt;li&gt;RAG&lt;/li&gt;
&lt;li&gt;Tool calling&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  3. Theoretical Interview Questions
&lt;/h1&gt;

&lt;h2&gt;
  
  
  3.1. How did you use LangGraph, and how was the agent structured?
&lt;/h2&gt;

&lt;p&gt;I used LangGraph as an explicit state graph.&lt;/p&gt;

&lt;p&gt;Nodes perform individual steps, while edges define transitions and branches. The agent stores its current state, calls tools, supports retry and fallback paths, and terminates when a defined terminal condition is reached.&lt;/p&gt;

&lt;h2&gt;
  
  
  3.2. What were the inputs and outputs of the planner layer?
&lt;/h2&gt;

&lt;p&gt;The planner received:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the user goal;&lt;/li&gt;
&lt;li&gt;the current state;&lt;/li&gt;
&lt;li&gt;available tools;&lt;/li&gt;
&lt;li&gt;system constraints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It returned a structured plan containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;execution steps;&lt;/li&gt;
&lt;li&gt;selected tools;&lt;/li&gt;
&lt;li&gt;tool arguments;&lt;/li&gt;
&lt;li&gt;completion criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3.3. What does a typical LangGraph flow look like?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User request
-&amp;gt; classification and routing
-&amp;gt; retrieval or tool execution
-&amp;gt; result validation
-&amp;gt; final response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Failure branches may include:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;retry
fallback
clarification
human escalation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  3.4. Where should deterministic logic be implemented: in the MCP client or MCP server?
&lt;/h2&gt;

&lt;p&gt;Both components require deterministic logic.&lt;/p&gt;

&lt;p&gt;The MCP client manages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;timeout;&lt;/li&gt;
&lt;li&gt;retry;&lt;/li&gt;
&lt;li&gt;routing;&lt;/li&gt;
&lt;li&gt;request format;&lt;/li&gt;
&lt;li&gt;response parsing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The MCP server manages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;schema validation;&lt;/li&gt;
&lt;li&gt;authorization;&lt;/li&gt;
&lt;li&gt;idempotency;&lt;/li&gt;
&lt;li&gt;safe tool execution.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3.5. How did you build observability and evaluation?
&lt;/h2&gt;

&lt;p&gt;Observability answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What happened inside the workflow?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;traces;&lt;/li&gt;
&lt;li&gt;prompts;&lt;/li&gt;
&lt;li&gt;tool calls;&lt;/li&gt;
&lt;li&gt;latency;&lt;/li&gt;
&lt;li&gt;cost;&lt;/li&gt;
&lt;li&gt;errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Evaluation answers:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How well did the agent complete the task?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;offline datasets;&lt;/li&gt;
&lt;li&gt;metrics;&lt;/li&gt;
&lt;li&gt;regression testing;&lt;/li&gt;
&lt;li&gt;experiments;&lt;/li&gt;
&lt;li&gt;human review.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3.6. Did you use LangFuse or another tool?
&lt;/h2&gt;

&lt;p&gt;LangFuse is a strong primary layer for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LLM tracing;&lt;/li&gt;
&lt;li&gt;datasets;&lt;/li&gt;
&lt;li&gt;experiments;&lt;/li&gt;
&lt;li&gt;evaluation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Infrastructure monitoring still requires additional tools such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudWatch;&lt;/li&gt;
&lt;li&gt;Grafana;&lt;/li&gt;
&lt;li&gt;Prometheus;&lt;/li&gt;
&lt;li&gt;structured application logs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3.7. How do you create evaluation datasets when agents can follow different paths?
&lt;/h2&gt;

&lt;p&gt;An agentic dataset should contain more than input and output.&lt;/p&gt;

&lt;p&gt;It should include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;user goal;&lt;/li&gt;
&lt;li&gt;initial state;&lt;/li&gt;
&lt;li&gt;available tools;&lt;/li&gt;
&lt;li&gt;allowed trajectories;&lt;/li&gt;
&lt;li&gt;forbidden actions;&lt;/li&gt;
&lt;li&gt;expected final state;&lt;/li&gt;
&lt;li&gt;edge cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would begin with real production cases and then add synthetic edge cases.&lt;/p&gt;
&lt;h2&gt;
  
  
  3.8. Is evaluation context created automatically or manually?
&lt;/h2&gt;

&lt;p&gt;The best approach is hybrid.&lt;/p&gt;

&lt;p&gt;Humans define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;taxonomy;&lt;/li&gt;
&lt;li&gt;rubric;&lt;/li&gt;
&lt;li&gt;quality criteria;&lt;/li&gt;
&lt;li&gt;safety boundaries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automation extracts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;traces;&lt;/li&gt;
&lt;li&gt;tool calls;&lt;/li&gt;
&lt;li&gt;outputs;&lt;/li&gt;
&lt;li&gt;latency;&lt;/li&gt;
&lt;li&gt;errors;&lt;/li&gt;
&lt;li&gt;cost.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important or ambiguous cases should pass human review.&lt;/p&gt;
&lt;h2&gt;
  
  
  3.9. What context should be provided to an LLM-as-a-Judge?
&lt;/h2&gt;

&lt;p&gt;The judge should receive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the original task;&lt;/li&gt;
&lt;li&gt;the rubric;&lt;/li&gt;
&lt;li&gt;the expected result;&lt;/li&gt;
&lt;li&gt;constraints;&lt;/li&gt;
&lt;li&gt;the actual execution trace;&lt;/li&gt;
&lt;li&gt;tool calls;&lt;/li&gt;
&lt;li&gt;the final answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It should score specific criteria such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;correctness;&lt;/li&gt;
&lt;li&gt;safety;&lt;/li&gt;
&lt;li&gt;completeness;&lt;/li&gt;
&lt;li&gt;trajectory quality.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3.10. What should be included in an evaluation dataset?
&lt;/h2&gt;

&lt;p&gt;For a simple LLM feature:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;input + golden answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;For an agentic workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;initial state;&lt;/li&gt;
&lt;li&gt;available tools;&lt;/li&gt;
&lt;li&gt;allowed tool calls;&lt;/li&gt;
&lt;li&gt;key intermediate steps;&lt;/li&gt;
&lt;li&gt;negative cases;&lt;/li&gt;
&lt;li&gt;success conditions;&lt;/li&gt;
&lt;li&gt;failure conditions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3.11. Which metrics matter for agentic systems and tool calling?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;task-completion rate;&lt;/li&gt;
&lt;li&gt;tool-selection accuracy;&lt;/li&gt;
&lt;li&gt;argument accuracy;&lt;/li&gt;
&lt;li&gt;tool success rate;&lt;/li&gt;
&lt;li&gt;trajectory accuracy;&lt;/li&gt;
&lt;li&gt;latency per step;&lt;/li&gt;
&lt;li&gt;retries and fallbacks;&lt;/li&gt;
&lt;li&gt;cost;&lt;/li&gt;
&lt;li&gt;schema validity;&lt;/li&gt;
&lt;li&gt;safety violations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3.12. What should the classifier predict?
&lt;/h2&gt;

&lt;p&gt;The classifier should classify the user request and select an intent or route.&lt;/p&gt;

&lt;p&gt;Example classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RAG;&lt;/li&gt;
&lt;li&gt;action or tool use;&lt;/li&gt;
&lt;li&gt;support;&lt;/li&gt;
&lt;li&gt;billing;&lt;/li&gt;
&lt;li&gt;research;&lt;/li&gt;
&lt;li&gt;validation;&lt;/li&gt;
&lt;li&gt;unknown.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It may also estimate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;risk;&lt;/li&gt;
&lt;li&gt;domain;&lt;/li&gt;
&lt;li&gt;confidence;&lt;/li&gt;
&lt;li&gt;escalation requirements.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3.13. What data does the classifier use?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;the current user request;&lt;/li&gt;
&lt;li&gt;recent conversation history;&lt;/li&gt;
&lt;li&gt;user and tenant metadata;&lt;/li&gt;
&lt;li&gt;current workflow state;&lt;/li&gt;
&lt;li&gt;previous tool results.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Training data may include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;labeled real requests;&lt;/li&gt;
&lt;li&gt;production traces;&lt;/li&gt;
&lt;li&gt;synthetic rare cases.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  3.14. How do you route arbitrary user requests?
&lt;/h2&gt;

&lt;p&gt;I would use a router with a confidence threshold.&lt;/p&gt;

&lt;p&gt;First, the system determines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;intent;&lt;/li&gt;
&lt;li&gt;risk;&lt;/li&gt;
&lt;li&gt;confidence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then it routes the request to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RAG;&lt;/li&gt;
&lt;li&gt;action workflow;&lt;/li&gt;
&lt;li&gt;research;&lt;/li&gt;
&lt;li&gt;specialist agent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Low-confidence or high-risk requests should trigger clarification or human review.&lt;/p&gt;


&lt;h1&gt;
  
  
  4. Practical Architecture Task
&lt;/h1&gt;
&lt;h2&gt;
  
  
  4.1. The Main Requirement
&lt;/h2&gt;

&lt;p&gt;After the theoretical questions, I was asked to design a production-ready agentic architecture using LangGraph.&lt;/p&gt;

&lt;p&gt;The key condition was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The system does not know in advance what request the user will send or what context will be required.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This was the most important part of the task.&lt;/p&gt;

&lt;p&gt;The interviewer clearly expected the architecture to introduce a &lt;strong&gt;classifier before full context collection and tool execution&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The expected insight was not simply:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User -&amp;gt; RAG -&amp;gt; LLM -&amp;gt; Answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The expected insight was:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User -&amp;gt; Classifier -&amp;gt; Required Context -&amp;gt; Route -&amp;gt; Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The classifier is essential because the system must first determine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the user wants;&lt;/li&gt;
&lt;li&gt;which domain the request belongs to;&lt;/li&gt;
&lt;li&gt;what context is required;&lt;/li&gt;
&lt;li&gt;which tools are allowed;&lt;/li&gt;
&lt;li&gt;whether the request is risky;&lt;/li&gt;
&lt;li&gt;whether human review is needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  4.2. Architecture Diagram
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://excalidraw.com/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexcalidraw.com%2Fog-image-3.png" height="450" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://excalidraw.com/" rel="noopener noreferrer" class="c-link"&gt;
            Excalidraw Whiteboard
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Excalidraw is a virtual collaborative whiteboard tool that lets you easily sketch diagrams that have a hand-drawn feel to them.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fexcalidraw.com%2Ffavicon-32x32.png" width="32" height="32"&gt;
          excalidraw.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;suggested &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Futlpvnj5cetwvkfs6ir6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Futlpvnj5cetwvkfs6ir6.png" alt=" " width="800" height="565"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[FIGURE 1 - LangGraph Agentic Architecture]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Figure 1&lt;/strong&gt; shows the proposed architecture with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trigger or Cron;&lt;/li&gt;
&lt;li&gt;Pre-check node;&lt;/li&gt;
&lt;li&gt;Intent classifier;&lt;/li&gt;
&lt;li&gt;Context builder;&lt;/li&gt;
&lt;li&gt;Router;&lt;/li&gt;
&lt;li&gt;Execution node;&lt;/li&gt;
&lt;li&gt;Validation node;&lt;/li&gt;
&lt;li&gt;Checkpointer;&lt;/li&gt;
&lt;li&gt;HITL User;&lt;/li&gt;
&lt;li&gt;HITL Admin;&lt;/li&gt;
&lt;li&gt;Circuit Breaker;&lt;/li&gt;
&lt;li&gt;Redis, relational database, and vector database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A critical detail in Figure 1 is that several nodes contain &lt;strong&gt;internal iterations&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;These iterations are not decorative. They represent repeated processing inside the workflow.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;build_context&lt;/code&gt; iterates over context sources;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;router&lt;/code&gt; iterates over candidate tools;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;execution_node&lt;/code&gt; iterates over planned tasks;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;validate_node&lt;/code&gt; iterates over evaluation metrics;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;checkpointer_node&lt;/code&gt; controls retry loops.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4.3. Main Flow
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Trigger
-&amp;gt; Pre-check
-&amp;gt; Intent Classifier
-&amp;gt; Context Builder
-&amp;gt; Router
-&amp;gt; Execution
-&amp;gt; Validation
-&amp;gt; Final Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additional branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Retry
Fallback
HITL User
HITL Admin
Circuit Breaker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4.4. Pre-check Node
&lt;/h2&gt;

&lt;p&gt;The pre-check node performs deterministic operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authentication;&lt;/li&gt;
&lt;li&gt;input validation;&lt;/li&gt;
&lt;li&gt;data cleaning;&lt;/li&gt;
&lt;li&gt;language detection;&lt;/li&gt;
&lt;li&gt;metadata loading;&lt;/li&gt;
&lt;li&gt;rate limiting.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pre_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;validated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4.5. Intent Classifier
&lt;/h2&gt;

&lt;p&gt;The classifier is the central component of the architecture.&lt;/p&gt;

&lt;p&gt;It receives minimal context and returns a structured routing decision.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Literal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rag&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;support&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;billing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;risk&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;required_context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;allowed_tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;classify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_structured_output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:],&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;model_dump&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This directly solves the unknown-context problem.&lt;/p&gt;

&lt;p&gt;The system does not load everything first. It classifies the request and then retrieves only the required context.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.6. Context Builder
&lt;/h2&gt;

&lt;p&gt;The context builder may use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redis;&lt;/li&gt;
&lt;li&gt;PostgreSQL;&lt;/li&gt;
&lt;li&gt;vector databases;&lt;/li&gt;
&lt;li&gt;conversation history;&lt;/li&gt;
&lt;li&gt;summaries;&lt;/li&gt;
&lt;li&gt;RAG;&lt;/li&gt;
&lt;li&gt;user metadata.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The internal iteration from Figure 1 can be implemented as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required_context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LOADERS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4.7. Router
&lt;/h2&gt;

&lt;p&gt;The router selects a tool, specialist agent, or subgraph.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;risk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hitl_admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hitl_user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;route&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The router may internally evaluate several tools before selecting one.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.8. Execution Node
&lt;/h2&gt;

&lt;p&gt;The execution node processes the structured plan.&lt;/p&gt;

&lt;p&gt;Figure 1 explicitly shows iteration over tasks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tasks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TOOLS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;args&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For production workflows, one task per graph transition is often safer because the state can be checkpointed after each external call.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.9. Validation Node
&lt;/h2&gt;

&lt;p&gt;The validation node checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;schema validity;&lt;/li&gt;
&lt;li&gt;correctness;&lt;/li&gt;
&lt;li&gt;safety;&lt;/li&gt;
&lt;li&gt;tool results;&lt;/li&gt;
&lt;li&gt;terminal conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Figure 1 shows an internal loop over metrics.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;metric&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;METRICS&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scores&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;passed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;passed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4.10. Retry, Fallback, and Circuit Breaker
&lt;/h2&gt;

&lt;p&gt;A failed validation may trigger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retry;&lt;/li&gt;
&lt;li&gt;replanning;&lt;/li&gt;
&lt;li&gt;fallback;&lt;/li&gt;
&lt;li&gt;human review;&lt;/li&gt;
&lt;li&gt;circuit breaker.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;after_validation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;passed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;final&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retry_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;circuit_breaker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4.11. Minimal LangGraph Assembly
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AgentState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pre_check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pre_check&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;classify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classify&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;build_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;execute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;validate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pre_check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pre_check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;classify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;classify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;execute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;execute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;validate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;validate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;after_validation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;final&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;execute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;circuit_breaker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  5. Main Takeaway
&lt;/h1&gt;

&lt;p&gt;The most important question was not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do we connect an LLM to a tool?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The real question was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How do we design an agent when the required context is unknown in advance?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The interviewer wanted to hear that a classifier should appear before full context retrieval and tool execution.&lt;/p&gt;

&lt;p&gt;The classifier determines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;intent;&lt;/li&gt;
&lt;li&gt;risk;&lt;/li&gt;
&lt;li&gt;confidence;&lt;/li&gt;
&lt;li&gt;required context;&lt;/li&gt;
&lt;li&gt;allowed tools;&lt;/li&gt;
&lt;li&gt;execution route.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only after that should the system retrieve data, build a plan, call tools, validate the result, and terminate the workflow.&lt;/p&gt;

&lt;p&gt;The internal iterations shown in Figure 1 are also important because real agentic systems repeatedly process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;context sources;&lt;/li&gt;
&lt;li&gt;candidate tools;&lt;/li&gt;
&lt;li&gt;execution tasks;&lt;/li&gt;
&lt;li&gt;evaluation metrics;&lt;/li&gt;
&lt;li&gt;retry attempts.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  6. Interview Results
&lt;/h1&gt;

&lt;p&gt;If you want to learn the final result of this interview, subscribe to my DEV.to and LinkedIn:&lt;/p&gt;

&lt;p&gt;DEV.to: &lt;a href="https://dev.to/efa"&gt;https://dev.to/efa&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;LinkedIn: &lt;a href="https://www.linkedin.com/in/egor-f-a214b2411/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/egor-f-a214b2411/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also message me directly, and I will reply privately.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Solved Reef Technologies’ Recruitment Game — and Learned to Evaluate the Hiring Process Too</title>
      <dc:creator>E F</dc:creator>
      <pubDate>Sun, 19 Jul 2026 13:38:53 +0000</pubDate>
      <link>https://dev.to/efa/i-solved-reef-technologies-recruitment-game-and-learned-to-evaluate-the-hiring-process-too-3f0g</link>
      <guid>https://dev.to/efa/i-solved-reef-technologies-recruitment-game-and-learned-to-evaluate-the-hiring-process-too-3f0g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;⚖ &lt;strong&gt;Context note.&lt;/strong&gt; This is my personal account of a recruitment process with &lt;strong&gt;Reef Technologies&lt;/strong&gt; in June–July 2026. It combines facts from my correspondence, my own interpretation of the experience, and a technical walkthrough of code I wrote. It is &lt;strong&gt;not&lt;/strong&gt; an allegation that the company or its employees committed fraud. The recruitment flow simply raised serious privacy, communication, and process questions for me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;ᯅ I solved a difficult recruitment game. The harder lesson was outside the code.&lt;/p&gt;

&lt;p&gt;Most take-home assignments are framed as a one-way evaluation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⌕ Can the candidate understand requirements?&lt;br&gt;&lt;br&gt;
⚒ Can they design a solution?&lt;br&gt;&lt;br&gt;
⚙ Can they write and test reliable code?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are fair questions. But after this experience I would add another:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;⌘ Can the candidate evaluate the hiring process, its tools, and the access they are asked to give before they are hired?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I completed a gamified recruitment assignment for a Senior Python Backend Engineer role at Reef Technologies. The assignment itself was genuinely challenging and technically rewarding: three stages, sub-stages, gradually unlocked mechanics, a limited number of turns, resource logistics, production chains, and a remote API.&lt;/p&gt;

&lt;p&gt;I finished all three stages, submitted the code, and built a reusable solver rather than a one-off script. Yet I did not progress further because I had not logged the work through Hubstaff, a desktop time-tracking tool that the company required candidates to use.&lt;/p&gt;

&lt;p&gt;This article has two threads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⛓ the &lt;strong&gt;engineering story&lt;/strong&gt;: how I built a capability-driven Python solver that could reason about unknown game mechanics;&lt;/li&gt;
&lt;li&gt;⚡ the &lt;strong&gt;candidate story&lt;/strong&gt;: why I became cautious about an installation request that included desktop monitoring and screenshots, and what I would verify before taking a similar assignment again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both lessons matter.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✉ The onboarding request that made me pause
&lt;/h2&gt;

&lt;p&gt;After completing an initial test, I received a congratulatory email and an invitation to the next stage. The message said that the task had to be tracked through the desktop version of &lt;strong&gt;Hubstaff&lt;/strong&gt;. It also explained that the application could periodically take screenshots while I worked.&lt;/p&gt;

&lt;p&gt;The request did not feel sufficiently clear and connected in my inbox at the moment I saw it. From my perspective, it looked like a request to install software on my personal computer that could collect work metrics and capture the screen. I treated that as a possible security issue, deleted the message, and later emptied the trash.&lt;/p&gt;

&lt;p&gt;Only afterward, while dealing with the task and follow-up correspondence, did I connect the tracking requirement with the recruitment game itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  ⚖ The important nuance
&lt;/h3&gt;

&lt;p&gt;The complete instruction email did contain the Hubstaff requirement. Not following it was my responsibility, and I do not want to rewrite the facts to make that disappear. The company later explained that Hubstaff tracking was an integral requirement because it reflects how their team tracks work time day-to-day. They chose not to move my application forward because no time was recorded there.&lt;/p&gt;

&lt;p&gt;At the same time, I believe an installation requirement with screen monitoring deserves a more explicit, security-conscious onboarding flow.&lt;/p&gt;

&lt;h3&gt;
  
  
  ◈ What I would expect before installing monitoring software
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✉ A separate, clearly titled message: &lt;strong&gt;“Required software for the recruitment task.”&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;⌕ A direct explanation of why it is needed &lt;em&gt;before&lt;/em&gt; employment.&lt;/li&gt;
&lt;li&gt;⚲ A description of what data is collected: activity, screenshots, application names, URLs, or anything else.&lt;/li&gt;
&lt;li&gt;♥ A retention and access policy: who can see the data, and for how long.&lt;/li&gt;
&lt;li&gt;⛓ A verified source for the installer and a way to confirm that the request is authentic.&lt;/li&gt;
&lt;li&gt;⏱ A prominent statement that missing this step blocks the next stage.&lt;/li&gt;
&lt;li&gt;⚖ A safe alternative, if one exists: a separate device, a virtual machine, or an agreed evidence-based workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am not saying that Hubstaff is inherently unsafe, nor that the process was a scam. My point is narrower and practical: &lt;strong&gt;installing any screen-monitoring application on a personal machine is a meaningful privacy and security decision.&lt;/strong&gt; A candidate is allowed to pause, verify, ask questions, and decline to execute an unclear installation request blindly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚡ &lt;code&gt;TRUST != CLICK_FIRST_ASK_LATER&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⏱ The apparent contradiction: the platform knew my progress
&lt;/h2&gt;

&lt;p&gt;The task itself ran on the company’s web platform. It showed my progression through three stages and their sub-stages; after each completed task, the corresponding status indicators changed. After I submitted my solution, I was told that an engineer had checked the time I spent in their system — but that this was not the same as Hubstaff tracking.&lt;/p&gt;

&lt;p&gt;This is where the process felt counterintuitive to me.&lt;/p&gt;

&lt;p&gt;The platform could already establish several useful facts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⌚ I had started the tasks;&lt;/li&gt;
&lt;li&gt;✦ I had completed the required game stages;&lt;/li&gt;
&lt;li&gt;⟁ tasks were completed in a visible sequence;&lt;/li&gt;
&lt;li&gt;⌖ the final solution was submitted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, this is also where I can see the company’s side. Platform activity is not a reliable work-time log. It does not include reading specifications, setting up a Python environment, designing architecture, debugging algorithms, writing tests, or stepping away from the keyboard. It cannot accurately prove how long someone worked.&lt;/p&gt;

&lt;p&gt;So the core issue was not whether their game platform had &lt;em&gt;any&lt;/em&gt; evidence of progress. It did. The issue was that it did not satisfy their separate, explicit requirement for a time tracker.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⏲ &lt;strong&gt;My takeaway:&lt;/strong&gt; a system can prove that you reached an outcome without proving how you spent every minute getting there.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Still, that distinction should be visible from the first line of the task brief — especially when the candidate is asked to run monitoring software during unpaid evaluation work.&lt;/p&gt;




&lt;h1&gt;
  
  
  ⚒ The assignment: a logistics game, not a scripted puzzle
&lt;/h1&gt;

&lt;p&gt;The technical task was much stronger than the administrative experience around it.&lt;/p&gt;

&lt;p&gt;At a high level, the game was a turn-based logistics and production problem. A level contained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a map and terrain;&lt;/li&gt;
&lt;li&gt;a base with an inventory;&lt;/li&gt;
&lt;li&gt;resource nodes;&lt;/li&gt;
&lt;li&gt;structures already on the map;&lt;/li&gt;
&lt;li&gt;a goal inventory that had to be delivered to a target structure;&lt;/li&gt;
&lt;li&gt;a maximum number of turns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The available mechanics evolved between stages. Early on, a simple solution might build a road, build a quarry, mine stone, transfer it to the base, and claim the win. That approach collapses as soon as the server introduces new resources, transport types, construction costs, recipes, or production structures.&lt;/p&gt;

&lt;p&gt;So I chose a different target:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;★ &lt;strong&gt;Do not solve one map. Build a solver that can interpret each stage.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The project became a small planning system with four independent layers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  ✉ Remote game API
                         │
                         ▼
              ◈ CapabilityRegistry
          actions · resources · structures
                         │
                         ▼
                  ⚙ GameState
       board · structures · storage · turns · goal
                    │                 │
                    ▼                 ▼
             ⚖ Local validator    ⚒ Strategy
          replay + invariants    plan + search
                    │                 │
                    └───────⌘─────────┘
                            │
                            ▼
                 valid JSON plan → server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key idea is simple: the strategy must not depend directly on HTTP response shapes, and the server must not be the first place where an invalid plan is discovered.&lt;/p&gt;




&lt;h2&gt;
  
  
  ❖ 1. Actions are real objects, not loose dictionaries
&lt;/h2&gt;

&lt;p&gt;Every game action is a Python object. That gives it behaviour, type identity, string representation for debugging, and a clear mapping to the remote API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BuildAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseAction&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;structure_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;StructureType&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;structure_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;structure_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;action_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BUILD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_api_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BUILD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;game_state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GameState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;structure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;game_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;make_structure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;game_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subtract_in_place&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;structure&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build_cost&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;game_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_structure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;structure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same pattern is used for building, mining, transfers, production, and the final win claim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nc"&gt;BuildAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;structure_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nc"&gt;ExtractAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nc"&gt;TransferAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nc"&gt;ProduceAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nc"&gt;ClaimWinAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why not just create JSON dictionaries in the strategy?&lt;/p&gt;

&lt;p&gt;Because the solver has to answer a more important question before serialisation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚖ &lt;strong&gt;What does this action do to the world state?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the action can be applied locally, the strategy can observe the consequences of its own choices immediately. A new road changes connectivity. A mine fills a local inventory. A transfer makes material available for construction at the base. Production consumes inputs and creates outputs.&lt;/p&gt;

&lt;p&gt;That is the difference between printing a plausible request body and actually planning.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⛓ 2. Model resources as a first-class value object
&lt;/h2&gt;

&lt;p&gt;Resources appear everywhere: construction costs, mine output, transfer amounts, recipes, and win conditions. I used a small &lt;code&gt;Inventory&lt;/code&gt; abstraction rather than scattering &lt;code&gt;dict.get(..., 0)&lt;/code&gt; across the codebase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Inventory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__getitem__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ResourceKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;resource_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ResourceKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;subtract_in_place&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Inventory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;at_least&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Inventory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That made core intent readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at_least&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goal_resources&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nc"&gt;ClaimWinAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No repeated loops. No silent &lt;code&gt;KeyError&lt;/code&gt;. No accidental mutation of the goal. Just a domain-level statement: &lt;em&gt;the base has enough resources to satisfy the goal.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✦ &lt;code&gt;INVENTORY&lt;/code&gt; is small code with a large effect on clarity.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⚙ 3. Interpret the stage instead of hardcoding its names
&lt;/h2&gt;

&lt;p&gt;The game exposes stage capabilities: resources, actions, structures, their interfaces, their costs, and eventually their recipes. I converted that server-defined data into a &lt;code&gt;CapabilityRegistry&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StructureSpec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;build_cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Inventory&lt;/span&gt;
    &lt;span class="n"&gt;interfaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;frozenset&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;resource_allow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;recipe_inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Inventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Inventory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;recipe_outputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Inventory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Inventory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_extraction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has_interface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StructureInterface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extraction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_production&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has_interface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StructureInterface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Production&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the solver can select structures by their role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extractor_specs_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;StructureSpec&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;structure_specs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_buildable&lt;/span&gt;
        &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_storage&lt;/span&gt;
        &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_extraction&lt;/span&gt;
        &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource_allow&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resource_allow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means the strategy does not say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# fragile, level-specific thinking
&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;STONE_QUARRY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⌕ Find a buildable, storage-capable extractor
  that can mine the resource this node contains.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matters because a game that evolves by stage is a deliberately moving target. A hardcoded first-level script is not an algorithm; it is a screenshot of an algorithm.&lt;/p&gt;

&lt;h3&gt;
  
  
  𝚒𝚗 𝚘𝚝𝚑𝚎𝚛 𝚠𝚘𝚛𝚍𝚜
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;𝚃𝚑𝚎 𝚜𝚎𝚛𝚟𝚎𝚛 𝚍𝚎𝚜𝚌𝚛𝚒𝚋𝚎𝚜 𝚠𝚑𝚊𝚝 𝚎𝚡𝚒𝚜𝚝𝚜; 𝚝𝚑𝚎 𝚜𝚘𝚕𝚟𝚎𝚛 𝚍𝚎𝚌𝚒𝚍𝚎𝚜 𝚠𝚑𝚊𝚝 𝚝𝚘 𝚍𝚘 𝚠𝚒𝚝𝚑 𝚒𝚝.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I also added an early compatibility check. If the server advertises an action that the local solver does not implement, the program stops instead of improvising an invalid plan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;solver_actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;supported_action_types&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;missing_actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;solver_actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;missing_actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;CapabilityMismatchError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Stage &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; exposes unsupported actions: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;missing_actions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a small defensive feature, but it prevents a misleading failure mode: “the strategy is bad” when the actual problem is “the game changed and the solver does not know a new action yet.”&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚖ 4. Build a local validator before trusting the network
&lt;/h2&gt;

&lt;p&gt;The server should not be your debugger.&lt;/p&gt;

&lt;p&gt;Sending a plan to a remote service is slower than replaying it locally. It also gives weaker feedback, may consume a limited attempt, and forces you to learn game rules through trial and error. I built a validator that replays the entire plan on a copy of the initial state before the client submits anything.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_plan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;GameState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;BaseAction&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GameState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initial_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_turns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;PlanValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plan uses &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; turns, limit is &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max_turns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;claimed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;turn_index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;turn&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;executed_turns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;turn_index&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;turn_start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;action_index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nf"&gt;_validate_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;turn_index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;action_index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ClaimWinAction&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;claimed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;claimed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;PlanValidationError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plan never claims victory&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ⟁ Invariants I validated
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;⌖ A build is inside the board and does not overwrite an existing structure.&lt;/li&gt;
&lt;li&gt;⚒ The structure exists in the current capability registry and is buildable.&lt;/li&gt;
&lt;li&gt;◈ The base can afford the construction cost.&lt;/li&gt;
&lt;li&gt;⛓ A newly built structure is adjacent to the existing network.&lt;/li&gt;
&lt;li&gt;⚡ An extractor stands on a compatible resource node.&lt;/li&gt;
&lt;li&gt;⌕ Every transfer step is orthogonally adjacent.&lt;/li&gt;
&lt;li&gt;⏱ Transfer endpoints are storage structures; intermediate cells are transport-only structures.&lt;/li&gt;
&lt;li&gt;♥ The source owns the requested positive amount.&lt;/li&gt;
&lt;li&gt;⚙ A mine or producer is activated no more than once per turn.&lt;/li&gt;
&lt;li&gt;★ Production has all recipe inputs.&lt;/li&gt;
&lt;li&gt;⚖ The win claim targets the correct structure and the goal inventory is actually present.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, transfer validation is intentionally strict:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transfer amount must be positive&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;_as_coord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coord&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;coord&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transfer path must contain at least source, transport, and destination&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;_adjacent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transfer path has non-adjacent step &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;❖ &lt;strong&gt;A validator is not an attempt to clone the entire server.&lt;/strong&gt; It is a local contract for the mistakes that would otherwise be expensive to discover remotely.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ⌖ 5. Search for a build route, then use it as a transfer route
&lt;/h2&gt;

&lt;p&gt;Every expansion starts with a geography problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“How can I connect this target cell to the network without crossing forbidden terrain, structures, or incompatible nodes?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I used breadth-first search for pathfinding. A candidate expansion stores the resource, its extractor type, full route, construction cost, the number of roads needed, terrain penalty, and expected rate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExpansionCandidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;extractor_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Coord&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...]&lt;/span&gt;
    &lt;span class="n"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Inventory&lt;/span&gt;
    &lt;span class="n"&gt;road_count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;terrain_penalty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extraction&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The route has two meanings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BASE ── road ── road ── EXTRACTOR
 ▲                           │
 └──── transfer path ────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First it tells the solver which transport cells need to be built. After construction, it is a valid path for taking materials back to the base.&lt;/p&gt;

&lt;p&gt;The strategy builds missing transport cells in order, then builds the extractor at the final coordinate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;coord&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_structure_at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;coord&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nc"&gt;BuildAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;coord&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;coord&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_transport_spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nc"&gt;BuildAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extractor_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the network is complete by that point, the solver mines and transfers in the same turn. This is a small but useful optimisation when the number of turns is tight.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚡ 6. Start with a greedy strategy; keep a bounded search for when it fails
&lt;/h2&gt;

&lt;p&gt;My normal turn-generation loop is deliberately easy to explain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;① ⛏ Mine from every connected extractor.
② ⛓ Transfer those resources back to the base.
③ ⚙ Feed and activate connected production structures.
④ ⌕ Find the best affordable expansion.
⑤ ⚒ Build its transport path and target structure.
⑥ ★ Claim victory as soon as the goal is satisfied.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the essence of the greedy part of the strategy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;at_least&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;goal_resources&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_claim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;extractor&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_connected_extractors&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_transfer_path&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nc"&gt;ExtractAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extracted_resource&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nc"&gt;TransferAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extracted_resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_best_affordable_expansion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Greedy planning is fast, debuggable, and usually good enough. But it has a predictable weakness: a locally cheap expansion can be globally wrong when the game has only a few turns remaining.&lt;/p&gt;

&lt;p&gt;So I added a fallback: &lt;strong&gt;beam search&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;initial state
   │
   ├─ mine / transfer resources available this turn
   ├─ generate several affordable expansions
   ├─ simulate each possible next state
   ├─ score the states
   └─ keep the best K branches  ◈ beam width
                              │
                              ▼
                         next turn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The solver does not enumerate every possible future — that would grow too quickly. Instead, it retains a limited beam of promising states. The score considers progress toward the goal, connected income, production output, remaining turns, recipe-input shortages, construction costs, and terrain penalties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GeneralStrategy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseStrategy&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ACTION_LOOP_LIMIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;
    &lt;span class="n"&gt;BEAM_WIDTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
    &lt;span class="n"&gt;BEAM_BUILD_DEPTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;BEAM_CANDIDATE_LIMIT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the algorithm pragmatic rather than academically exhaustive:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;∞ &lt;strong&gt;Simple cases stay simple. Hard cases get more search only when needed.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For production chains, I also estimate capacity. If the existing factories and connected input sources cannot produce the missing output in the remaining turns, the solver prioritises a new input source or another producer before it is too late.&lt;/p&gt;




&lt;h2&gt;
  
  
  ♻ 7. Tests were part of the solution, not decoration
&lt;/h2&gt;

&lt;p&gt;I used compact synthetic levels to test the planning logic without needing a live server. The tests cover both positive plans and the rule boundaries that should fail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_validator_rejects_invalid_transfer_and_double_mine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;initial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GameState&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlanValidationError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;insufficient STONE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;validate_plan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nc"&gt;TransferAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;STONE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)]],&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlanValidationError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;already mined&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;validate_plan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nc"&gt;ExtractAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;ExtractAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)]])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ✦ The suite checked
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;a single road and a quarry are built in the correct order;&lt;/li&gt;
&lt;li&gt;a multi-road corridor remains connected throughout construction;&lt;/li&gt;
&lt;li&gt;the strategy mines before expanding when the base lacks resources;&lt;/li&gt;
&lt;li&gt;the cheaper resource node is selected first;&lt;/li&gt;
&lt;li&gt;a road cannot be built on a resource node;&lt;/li&gt;
&lt;li&gt;a transfer cannot send more material than the source holds;&lt;/li&gt;
&lt;li&gt;an extractor cannot mine twice in one turn;&lt;/li&gt;
&lt;li&gt;a premature win claim is rejected;&lt;/li&gt;
&lt;li&gt;an invalid plan is never submitted through the CLI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the time of writing, the suite passes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;........                                                                 [100%]
8 passed in 0.91s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;★ Tests do not prove that a solver handles every future game mechanic. They do prove that the rules I had already learned do not silently regress while I add the next mechanic.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  ♥ What I learned
&lt;/h1&gt;

&lt;p&gt;Technically, I am proud of this solution. The task pushed me to build a domain model, separate server capabilities from decisions, replay plans locally, validate hard constraints, and combine a transparent greedy heuristic with a bounded fallback search.&lt;/p&gt;

&lt;p&gt;It reinforced a principle I value in backend work:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚙ &lt;strong&gt;When an external system has rules, create a local model of those rules before you automate decisions against it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The recruitment experience added a second lesson.&lt;/p&gt;

&lt;p&gt;Before I install tracking software, give a service screen access, or commit dozens of hours to a technical task, I will now ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⚖ Is this tool mandatory, and is that requirement explicitly called out?&lt;/li&gt;
&lt;li&gt;⌕ What data does it collect and who can access it?&lt;/li&gt;
&lt;li&gt;⌚ How long is the assignment expected to take?&lt;/li&gt;
&lt;li&gt;₿ Is the work paid, and if so, under what written conditions?&lt;/li&gt;
&lt;li&gt;⚲ Is there a way to use an isolated device, account, or virtual machine?&lt;/li&gt;
&lt;li&gt;✉ What part of the evaluation is blocking: the output, the process, the tracker, or all of the above?&lt;/li&gt;
&lt;li&gt;⟁ Can the employer provide a verified installation source and privacy documentation?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those questions are not hostility. They are ordinary digital hygiene.&lt;/p&gt;

&lt;h2&gt;
  
  
  𝚏𝚒𝚗𝚊𝚕 𝚗𝚘𝚝𝚎
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;𝚃𝚎𝚌𝚑𝚗𝚒𝚌𝚊𝚕 𝚜𝚔𝚒𝚕𝚕 𝚒𝚜 𝚗𝚘𝚝 𝚓𝚞𝚜𝚝 𝚠𝚛𝚒𝚝𝚒𝚗𝚐 𝚌𝚘𝚍𝚎.&lt;br&gt;&lt;br&gt;
𝙸𝚝 𝚒𝚜 𝚞𝚗𝚍𝚎𝚛𝚜𝚝𝚊𝚗𝚍𝚒𝚗𝚐 𝚛𝚎𝚚𝚞𝚒𝚛𝚎𝚖𝚎𝚗𝚝𝚜, 𝚖𝚘𝚍𝚎𝚕𝚕𝚒𝚗𝚐 𝚌𝚘𝚗𝚜𝚝𝚛𝚊𝚒𝚗𝚝𝚜, 𝚟𝚎𝚛𝚒𝚏𝚢𝚒𝚗𝚐 𝚊𝚜𝚜𝚞𝚖𝚙𝚝𝚒𝚘𝚗𝚜, 𝚊𝚗𝚍 𝚔𝚗𝚘𝚠𝚒𝚗𝚐 𝚠𝚑𝚎𝚗 𝚝𝚘 𝚙𝚊𝚞𝚜 𝚊𝚗𝚍 𝚟𝚎𝚛𝚒𝚏𝚢.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The game was difficult. Solving it was worth the effort. And the experience made me a more careful engineer — not only when I design systems, but also when I decide which systems deserve my trust.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
