<?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: Kaung Zin Hein</title>
    <description>The latest articles on DEV Community by Kaung Zin Hein (@zin_kg).</description>
    <link>https://dev.to/zin_kg</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%2F1461616%2F808e72a4-9fcb-4668-95e8-50793b4f42cd.jpg</url>
      <title>DEV Community: Kaung Zin Hein</title>
      <link>https://dev.to/zin_kg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zin_kg"/>
    <language>en</language>
    <item>
      <title>AI Video Needs CI More Than Better Prompts</title>
      <dc:creator>Kaung Zin Hein</dc:creator>
      <pubDate>Mon, 20 Jul 2026 20:49:27 +0000</pubDate>
      <link>https://dev.to/zin_kg/ai-video-needs-ci-more-than-better-prompts-3lb0</link>
      <guid>https://dev.to/zin_kg/ai-video-needs-ci-more-than-better-prompts-3lb0</guid>
      <description>&lt;p&gt;Here I'll share what I built for Track 2 of the Global AI Hackathon Series with Qwen Cloud, and what it taught me about testing things you can't see.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My expensive little problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I generated a five-second video clip. The first frame looked perfect.&lt;/p&gt;

&lt;p&gt;Then I watched the other four seconds.&lt;/p&gt;

&lt;p&gt;The camera drifted left. My brief said hold static.&lt;/p&gt;

&lt;p&gt;Here's the part that &lt;em&gt;irritates&lt;/em&gt; me: I found out &lt;strong&gt;after&lt;/strong&gt; I paid. On Qwen Cloud's Wan models a clip is a fixed five seconds of premium quota whether it's usable or garbage. The bill doesn't care.&lt;/p&gt;

&lt;p&gt;Text models don't work like this. You read the answer, you see it's wrong, you move on. The artifact and the verdict show up together and being wrong costs you a few hundred tokens.&lt;/p&gt;

&lt;p&gt;Video fails &lt;em&gt;in motion&lt;/em&gt;. The failure lives in frames you haven't looked at yet.&lt;/p&gt;

&lt;p&gt;So you pay first, and find out second.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But it gets worse...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The obvious build for this track is a premise-in, episode-out generator. I started there. Within a couple of days I had something that produced a demo reel.&lt;/p&gt;

&lt;p&gt;But demo reels hide the interesting failures.&lt;/p&gt;

&lt;p&gt;Every bad take that reaches your final render is money you already spent. And I kept asking myself a question that had nothing to do with generation:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Can the system tell whether the video obeyed the brief, before it spends premium budget on it?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That question has a name in software. It's CI.&lt;/p&gt;

&lt;p&gt;And almost nobody is running it on generated video.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So why bother? Don't we just prompt better?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That was my first instinct too. Write better prompts, get better clips.&lt;/p&gt;

&lt;p&gt;But a prompt is not a contract. It's too easy to rewrite, stretch, and forget as an artifact moves between models. You can't assert against a prompt. You can't fail a build with one.&lt;/p&gt;

&lt;p&gt;Before I burned a week on this bet, I wanted to know it wasn't just a slogan I liked the sound of. So I counted. Twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test 1 — the simulated field.&lt;/strong&gt; I ran 15 independent LLM brainstorms over this track's public brief. Two model families, 14 personas, none of them seeing my repo or each other. Around 150 ideas.&lt;/p&gt;

&lt;p&gt;All 15 produced a generator.&lt;/p&gt;

&lt;p&gt;Zero produced a way to check whether the generated episode came out right.&lt;/p&gt;

&lt;p&gt;Two of them even emitted the phrase "CI for AI-generated video" &lt;em&gt;verbatim&lt;/em&gt; — and then bolted it onto a generator anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test 2 — the observed field.&lt;/strong&gt; Two days before the deadline I read the eight most substantial shipped entries in this track's public GitHub field. Every one routes its quality checks through a token-billed model call. Six of the eight import no computer-vision library at all. None ships a closed assertion vocabulary. None can gate a video it didn't itself generate.&lt;/p&gt;

&lt;p&gt;Then I found this line in the config of a shipping logline-to-video pipeline:&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;DAILIES_QC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;   &lt;span class="c1"&gt;# off = faster pipeline
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Someone built a review stage. Named it dailies. Shipped it switched &lt;strong&gt;off&lt;/strong&gt;. For speed.&lt;/p&gt;

&lt;p&gt;That's the whole problem in one line.&lt;/p&gt;

&lt;p&gt;When the gate lives &lt;em&gt;inside&lt;/em&gt; the generator's codebase, the gate is the first thing traded away for throughput.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time to build the tests instead&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In film production, &lt;em&gt;dailies&lt;/em&gt; are the screening where the crew watches yesterday's footage before more money is spent shooting on top of it. It's the daily quality gate.&lt;/p&gt;

&lt;p&gt;So that's the name. &lt;strong&gt;Dailies.&lt;/strong&gt; The review stage that can't be quietly switched off, because it doesn't belong to the pipeline it judges.&lt;/p&gt;

&lt;p&gt;It reads frames, not generator internals. Point it at any mp4 from any model.&lt;/p&gt;

&lt;p&gt;Here's how it works.&lt;/p&gt;

&lt;p&gt;You write what a shot has to do. Every take gets measured against it before it ships. A take that misses gets one bounded repair attempt. A take that still misses never reaches your cut.&lt;/p&gt;

&lt;p&gt;A spec is a short program in a &lt;strong&gt;closed assertion DSL — ten sentence types across three tiers&lt;/strong&gt;. The compiler translates each sentence into a call in a shared check library, and rejects anything outside the grammar &lt;em&gt;before a single token is spent&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Send it something it doesn't recognize and &lt;code&gt;parse_assertions&lt;/code&gt; raises. Send &lt;code&gt;{"type": "vibe_check"}&lt;/code&gt; to the MCP server and it comes back &lt;code&gt;isError&lt;/code&gt;, not a guess.&lt;/p&gt;

&lt;p&gt;That rejection is the literal compile error in "CI for generated video."&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Assertion type&lt;/th&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Compiles to&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;duration_between&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A · deterministic&lt;/td&gt;
&lt;td&gt;clip length within bounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;brightness_range&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A · deterministic&lt;/td&gt;
&lt;td&gt;mean-luma within bounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;flicker_below&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A · deterministic&lt;/td&gt;
&lt;td&gt;inter-frame luma std under threshold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scene_cuts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A · deterministic&lt;/td&gt;
&lt;td&gt;HSV-histogram cut count at or under max&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;camera_motion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A · deterministic&lt;/td&gt;
&lt;td&gt;optical-flow pan direction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;palette_deltae&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A · deterministic&lt;/td&gt;
&lt;td&gt;dominant-color ΔE to a brand palette&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;subject_present&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0 · pre-render still&lt;/td&gt;
&lt;td&gt;subject recognizable in the t2i still&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;identity_consistent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;B · advisory&lt;/td&gt;
&lt;td&gt;VLM: same identity across frames&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;action_completed&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;B · advisory&lt;/td&gt;
&lt;td&gt;VLM: the briefed action visibly completes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;title_card_present&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;B · advisory&lt;/td&gt;
&lt;td&gt;VLM: a title / text card is visible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice there's an organizational idea hiding in that table.&lt;/p&gt;

&lt;p&gt;Right now, the person who &lt;em&gt;defines&lt;/em&gt; "correct" — brand, legal, marketing — is coupled to the person who &lt;em&gt;operates&lt;/em&gt; the generator. They're joined by one overworked reviewer eyeballing every clip.&lt;/p&gt;

&lt;p&gt;The stakeholder writes these assertions once, in plain language. Every shot gets tested against them automatically.&lt;/p&gt;

&lt;p&gt;Spec-driven development, for video.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tiers are boring on purpose&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not every check deserves the same budget. So the cascade runs cheapest-and-most-certain first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier-A is deterministic OpenCV.&lt;/strong&gt; Duration, brightness, flicker, scene cuts, optical-flow camera motion, palette ΔE. Zero tokens, so it runs on &lt;em&gt;every take&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It's deliberately unglamorous. OpenCV has no idea whether your story works. But it cheaply catches a huge amount of broken video, and it never has an opinion it can't defend with a number.&lt;/p&gt;

&lt;p&gt;Measured over 25 iterations: all six checks on a 5-second clip cost a &lt;strong&gt;median 317 ms&lt;/strong&gt; of CPU. Nothing else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier-B is Qwen-VL, and it's advisory.&lt;/strong&gt; A VLM is good at "does this appear to match the brief." But a model judgment is softer evidence than a pixel measurement — so Tier-B flags for the human and never blocks promotion.&lt;/p&gt;

&lt;p&gt;Deterministic checks are the foundation. Model-graded judgment sits on top. Never underneath.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier-0 is a still-image pre-screen.&lt;/strong&gt; Before any motion is generated, a &lt;code&gt;wan2.1-t2i-plus&lt;/code&gt; still renders at roughly 1/25th of a video's cost, and &lt;code&gt;qwen-vl-plus&lt;/code&gt; gets asked one question: is the briefed subject even in the frame?&lt;/p&gt;

&lt;p&gt;If a prompt can't render its own subject as a still, paying for motion just buys you the same lesson at 25× the price.&lt;/p&gt;

&lt;p&gt;Only after surviving all that does a shot earn promotion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;premise → script + specs (qwen-plus) → compiled assertion checklist
        → Tier-0 still pre-screen (wan2.1-t2i-plus)
        → [human review gate — the one checkpoint, before any video spend]
        → drafts (wan2.1-t2v-turbo)
        → Tier-A CV (deterministic, zero tokens) + Tier-B VLM (qwen-vl-plus, advisory)
        → bounded prompt-repair + retake (qwen-plus)
        → promote passing shots (wan2.2-i2v-flash, anchored on the approved frame)
        → narration, one voice per character (qwen3-tts-flash)
        → ffmpeg assembly → certified episode, with sound
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A rendered architecture diagram was a required deliverable anyway, so here's the same thing drawn formally. One convention worth knowing: &lt;strong&gt;red is reserved for the two paths that matter most&lt;/strong&gt; — a spec rejected before any spend, and a blocking Tier-A fail.&lt;/p&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%2Fsseyqykv6kqhbkogozi9.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%2Fsseyqykv6kqhbkogozi9.png" alt=" " width="800" height="725"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two human roles that today collapse into one exhausted reviewer. The &lt;strong&gt;stakeholder&lt;/strong&gt; owns "correct" and authors the spec once. The &lt;strong&gt;operator&lt;/strong&gt; is the only human in the loop at runtime, at the single gate before any video is paid for.&lt;/p&gt;

&lt;p&gt;Level 2 answers the question the hackathon actually asked — how Qwen Cloud connects to the frontend, backend, and store:&lt;/p&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%2Fccmqm3c28ge829cywnot.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%2Fccmqm3c28ge829cywnot.png" alt=" " width="800" height="1148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That was the design.&lt;/p&gt;

&lt;p&gt;Then I ran it for real, and reality started correcting me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The rule that kept saving me: let the model choose, never let it spell&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before the war stories, one design decision that turned out to matter more than anything else I did.&lt;/p&gt;

&lt;p&gt;That closed vocabulary started as an assertion-layer detail. It ended up being the rule the whole system runs on.&lt;/p&gt;

&lt;p&gt;There are three places where a Qwen model makes a real decision in Dailies. In all three, it emits a &lt;em&gt;choice from a set the server owns&lt;/em&gt; — never the artifact itself.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;th&gt;The model emits&lt;/th&gt;
&lt;th&gt;The server produces&lt;/th&gt;
&lt;th&gt;The failure it prevents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Assertions&lt;/td&gt;
&lt;td&gt;a &lt;code&gt;type&lt;/code&gt; from a closed set + typed params&lt;/td&gt;
&lt;td&gt;a call into the check library&lt;/td&gt;
&lt;td&gt;a check that means something other than what it says&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipeline topology&lt;/td&gt;
&lt;td&gt;run &lt;strong&gt;parameters&lt;/strong&gt; (&lt;code&gt;premise&lt;/code&gt;, &lt;code&gt;pack&lt;/code&gt;, &lt;code&gt;max_shots&lt;/code&gt;, &lt;code&gt;custom_checks&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;the canonical node/edge graph&lt;/td&gt;
&lt;td&gt;a structurally malformed run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Narration casting&lt;/td&gt;
&lt;td&gt;a &lt;code&gt;speaker&lt;/code&gt; — a character &lt;em&gt;name&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;a voice from a probed roster&lt;/td&gt;
&lt;td&gt;a &lt;strong&gt;silent&lt;/strong&gt; hole in a certified episode&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That middle row became my headline demo.&lt;/p&gt;

&lt;p&gt;You type a request in plain language. &lt;code&gt;qwen-plus&lt;/code&gt; calls a &lt;code&gt;build_pipeline_graph&lt;/code&gt; tool with &lt;code&gt;tool_choice="auto"&lt;/code&gt;. The server deterministically expands those parameters into the graph the run executes, rendered live in React Flow off the same 2.5-second poll the dashboard already uses.&lt;/p&gt;

&lt;p&gt;So "an agent wired the pipeline" is a claim I can make without flinching. The model authored the run. It &lt;em&gt;could not&lt;/em&gt; have emitted a broken graph, because it never emitted topology at all.&lt;/p&gt;

&lt;p&gt;This is the difference between validating the model's output and making invalid output unrepresentable.&lt;/p&gt;

&lt;p&gt;Validation is a check you can forget to run. Or run in only one of two code paths — which I did, and I'll get to that.&lt;/p&gt;

&lt;p&gt;A parameter contract is a shape the bad value cannot fit through.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The day my green tests lied to me&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every end-to-end test I'd written used synthetic clips. A fake Wan client returning generated mp4s so I could exercise the pipeline for free.&lt;/p&gt;

&lt;p&gt;That validates control flow. And nothing about the API's contract.&lt;/p&gt;

&lt;p&gt;A fake client can't reject a request the real service would reject.&lt;/p&gt;

&lt;p&gt;So I built a fixtures mode. Real Wan client, real Tier-A, real Tier-B, real assembly — with only the two non-deterministic text stages pinned to fixed prompts. (Prompts are cache keys, so a pinned run replays identically at zero quota.)&lt;/p&gt;

&lt;p&gt;Then I ran it cold, against the real API, for the first honest time.&lt;/p&gt;

&lt;p&gt;It found four bugs.&lt;/p&gt;

&lt;p&gt;Seventy-nine passing tests had missed every single one.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bug&lt;/th&gt;
&lt;th&gt;Why 79 passing tests missed it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;wan2.2-t2v-plus&lt;/code&gt; &lt;strong&gt;rejects &lt;code&gt;1280*720&lt;/code&gt;&lt;/strong&gt; — so &lt;em&gt;every premium promotion the project had ever made had silently failed&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;_promote&lt;/code&gt; treats a failed promote as "keep the passing draft," so a rejected final and a healthy skip produced identical state. The premium tier — my entire wedge — had never actually run.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The budget governor asked the cache about the wrong resolution key for finals, calling every cached final "fresh"&lt;/td&gt;
&lt;td&gt;Under judge mode that would have &lt;em&gt;refused free replays during judging&lt;/em&gt; — the one thing the live URL depends on.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The ledger wrote an empty note for both a no-op and a hard failure&lt;/td&gt;
&lt;td&gt;Which is precisely how the first two hid. The audit trail didn't audit.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;state.json&lt;/code&gt; was write-only — snapshots atomically written, never read back&lt;/td&gt;
&lt;td&gt;Every redeploy silently discarded every run a viewer had made, while my architecture diagram promised state persists across restarts.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sit with that first row for a second.&lt;/p&gt;

&lt;p&gt;My entire pitch is that generated video ships unverified because nobody runs the claim against the artifact.&lt;/p&gt;

&lt;p&gt;And my own premium tier had been dead for the project's whole life. In a repo whose thesis is a conformance gate.&lt;/p&gt;

&lt;p&gt;The gate caught its own maker.&lt;/p&gt;

&lt;p&gt;I fixed all four in one commit, each with a regression test I verified by reverting the fix and watching the test fail. But this is the line I wrote in the log afterward, and it's the one I keep coming back to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mocks test the code you wrote. Fixtures test the assumption you made. This bug lived in the gap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A mock returns what you told it to. So a suite of mocks can only ever confirm your own mental model. It re-asserts your assumptions back at you, in green.&lt;/p&gt;

&lt;p&gt;The real contract lives at the boundary with the external service. The only test that touches it is one that actually calls the thing.&lt;/p&gt;

&lt;p&gt;If you're integrating any generative API — spend the tokens on one real end-to-end run early. It's the cheapest bug-finder you'll ever build.&lt;/p&gt;

&lt;p&gt;There was a fifth of the same family, and it's the one I'd hand to a test-design skeptic.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;subject_present&lt;/code&gt; — my Tier-0 check — was declared, marked blocking-class, and evaluated by &lt;em&gt;nothing&lt;/em&gt;. All three runtimes wired it to &lt;code&gt;lambda spec, still: []&lt;/code&gt;, while the pipeline dutifully generated &lt;strong&gt;and billed&lt;/strong&gt; a still for every shot, then stored the empty list it got back.&lt;/p&gt;

&lt;p&gt;A green suite couldn't catch that. Because of one line:&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;take&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&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;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;advisory&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FAIL&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A check that returns &lt;strong&gt;no result&lt;/strong&gt; and a check that &lt;strong&gt;passes&lt;/strong&gt; are the same empty list.&lt;/p&gt;

&lt;p&gt;Wiring it to a real &lt;code&gt;qwen-vl-plus&lt;/code&gt; read costs 325 tokens per shot to avoid a 5-second premium clip. I measured it in both directions — present subject and absent — because a check that only ever answers PASS is not a check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The receipt that made me believe in the thing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;3e1f628d4acf&lt;/code&gt;, shot 0, contract &lt;code&gt;camera_motion: static&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The turbo draft passed cleanly at optical-flow magnitude &lt;code&gt;|v|=0.30&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then the premium &lt;code&gt;wan2.2-t2v-plus&lt;/code&gt; render came back drifting left at &lt;code&gt;|v|=0.92&lt;/code&gt;, and failed the same contract the draft had passed.&lt;/p&gt;

&lt;p&gt;The gate did exactly what it exists for. Rejected the premium clip. Certified the cheaper draft.&lt;/p&gt;

&lt;p&gt;Working as designed — but now my episode was stuck with the lesser render.&lt;/p&gt;

&lt;p&gt;So I built targeted repair.&lt;/p&gt;

&lt;p&gt;Tier-A doesn't just say a check failed. It keeps the per-frame series behind each measurement, so a failure carries a &lt;em&gt;time window&lt;/em&gt;. Here it placed the drift at &lt;strong&gt;0.4s–3.6s&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That window gives you an anchor: the last good frame, at 0.2s. A frame-anchored Wan model (&lt;code&gt;wan2.2-i2v-flash&lt;/code&gt;) re-renders from that frame forward, Tier-A re-verifies, and a passing patch re-cuts the episode.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;before (premium, take 1)&lt;/th&gt;
&lt;th&gt;after (patch)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;camera_motion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;FAIL&lt;/strong&gt; — drifting left, `\&lt;/td&gt;
&lt;td&gt;v\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;flicker / brightness / duration / cuts&lt;/td&gt;
&lt;td&gt;pass&lt;/td&gt;
&lt;td&gt;pass&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Cost: &lt;strong&gt;5 video-seconds&lt;/strong&gt; on the i2v free-tier pool, plus one {% raw %}&lt;code&gt;qwen-plus&lt;/code&gt; repair call.&lt;/p&gt;

&lt;p&gt;The premium look, recovered under contract, by the same gate that rejected it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My best idea was only half right&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That receipt made me greedy.&lt;/p&gt;

&lt;p&gt;If anchoring on a good frame rescues a &lt;em&gt;broken&lt;/em&gt; clip, why not anchor everything?&lt;/p&gt;

&lt;p&gt;The reasoning felt airtight. Draft, repair, and final were three independent rolls from the same prompt — three separate lotteries — so a certified episode could look like three different films of the same script.&lt;/p&gt;

&lt;p&gt;Anchor the retake on the last good frame. Anchor the promotion on the frame the human approved. Every take of a shot inherits one continuous look.&lt;/p&gt;

&lt;p&gt;Same primitive, generalized. I shipped it.&lt;/p&gt;

&lt;p&gt;Then I ran it on real Wan output. It was wrong in two specific, measurable places.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. An anchor can't fix a defect that has no "before."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Shot 1 asserts &lt;code&gt;camera_motion: right&lt;/code&gt;. Its first draft came back static — &lt;code&gt;|v| = 0.005&lt;/code&gt; against a &lt;code&gt;0.4&lt;/code&gt; threshold — with Tier-A localizing the failure to &lt;code&gt;fail_window_s [0.0, 5.33]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The entire clip.&lt;/p&gt;

&lt;p&gt;There's exactly one frame before that window. Frame 0. And anchoring the retake there pinned the exact staticness the retake existed to remove.&lt;/p&gt;

&lt;p&gt;The anchored retake measured &lt;code&gt;|v| = 0.112&lt;/code&gt;. Still a FAIL.&lt;/p&gt;

&lt;p&gt;A fresh &lt;code&gt;t2v&lt;/code&gt; roll on the same repaired prompt reached &lt;code&gt;|v| = 0.745 'right'&lt;/code&gt; and passed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. An anchor frame carries composition. It does not carry motion.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This one I did not see coming.&lt;/p&gt;

&lt;p&gt;I took that approved rightward pan — &lt;code&gt;|v| = 0.745 'right'&lt;/code&gt; — and promoted it by anchoring at &lt;code&gt;0.1s&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The premium final came back panning &lt;strong&gt;the other way&lt;/strong&gt;. &lt;code&gt;|v| = 6.15 'left'&lt;/code&gt;. Failed re-verify.&lt;/p&gt;

&lt;p&gt;A single frame encodes framing, lighting, wardrobe, palette. It encodes nothing about which direction the camera was travelling when that frame was taken.&lt;/p&gt;

&lt;p&gt;So the model just invents one.&lt;/p&gt;

&lt;p&gt;The rule those two measurements produced is now code, not prompt advice:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Anchor to preserve. Re-roll to change.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Concretely: &lt;code&gt;_anchor_for_retake&lt;/code&gt; returns &lt;code&gt;None&lt;/code&gt; when the failure window opens at &lt;code&gt;t = 0&lt;/code&gt;, so a whole-clip defect re-rolls from the corrected prompt instead. And a shot whose contract asserts camera motion &lt;strong&gt;skips promotion entirely&lt;/strong&gt; — the clip that satisfied the contract is the clip that ships.&lt;/p&gt;

&lt;p&gt;That second consequence is my favourite number in the whole project. Look at the ledger for a certified three-shot batch:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Calls&lt;/th&gt;
&lt;th&gt;Billed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;drafting&lt;/code&gt; (&lt;code&gt;wan2.1-t2v-turbo&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;20 video-s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;promoting&lt;/code&gt; (&lt;code&gt;wan2.2-i2v-flash&lt;/code&gt;, frame-anchored)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;10 video-s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three shots certified. &lt;strong&gt;Two&lt;/strong&gt; promotions.&lt;/p&gt;

&lt;p&gt;The missing one is the shot with the motion contract.&lt;/p&gt;

&lt;p&gt;So verification here isn't only rejecting bad output. It's &lt;em&gt;deleting a generation the run would otherwise have paid for&lt;/em&gt;, because measurement proved that generation could only make things worse.&lt;/p&gt;

&lt;p&gt;A quality gate that &lt;strong&gt;reduces&lt;/strong&gt; spend is a much easier thing to sell than one that adds to it.&lt;/p&gt;

&lt;p&gt;Both findings cost one clip each to discover. 10 seconds out of a 600-second budget.&lt;/p&gt;

&lt;p&gt;And notice which half of my idea survived. "Anchor for visual continuity" was right. "Anchoring beats re-rolling" was an unexamined extension of it, and it took two real generations to pull them apart.&lt;/p&gt;

&lt;p&gt;When a primitive works beautifully in the case you built it for, the temptation is to extend it by resemblance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every bug I found was the same bug&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's the postscript, and it's the most uncomfortable finding in my log.&lt;/p&gt;

&lt;p&gt;The promotion path and the &lt;em&gt;manual&lt;/em&gt; re-render button computed their anchors in two separate places.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pipeline.py&lt;/code&gt; learned the &lt;code&gt;t=0&lt;/code&gt; rule. &lt;code&gt;patch.py&lt;/code&gt; had its own &lt;code&gt;anchor_second&lt;/code&gt;, which clamped happily to &lt;code&gt;0.0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So for another full day, the button in my UI cheerfully offered — and the endpoint faithfully performed — precisely the move I had just measured as useless.&lt;/p&gt;

&lt;p&gt;No test caught it. And the reason is worth stating plainly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Both surfaces agreed with themselves.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each was internally consistent. Nothing in the suite asserted they agreed with &lt;em&gt;each other&lt;/em&gt;. It only surfaced because someone finally clicked the button.&lt;/p&gt;

&lt;p&gt;There's a third instance lurking in my deploy runbook. The budget governor wraps &lt;code&gt;gen_video_fn&lt;/code&gt; — but promotion now renders through &lt;code&gt;patch_video_fn&lt;/code&gt;, deliberately unwrapped so anchored work draws the separate i2v pool instead of competing with drafts.&lt;/p&gt;

&lt;p&gt;Correct decision. Unintended consequence: &lt;code&gt;fresh_final_cap&lt;/code&gt; no longer bounds a live run.&lt;/p&gt;

&lt;p&gt;The safety rail didn't break. The thing it guarded moved out from under it.&lt;/p&gt;

&lt;p&gt;Now line up every bug this project has found:&lt;/p&gt;

&lt;p&gt;· a fallback that returns the success value on failure&lt;br&gt;
· a missing result indistinguishable from a passing one&lt;br&gt;
· two code paths deriving the same value independently&lt;br&gt;
· a wrapper whose subject moved&lt;/p&gt;

&lt;p&gt;Not one of them failed loudly.&lt;/p&gt;

&lt;p&gt;Every single one presented as success.&lt;/p&gt;

&lt;p&gt;Which is, uncomfortably, the exact thing my product exists to catch. Generated video ships unverified because a bad clip and a good clip both look like &lt;em&gt;output&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Giving it a voice (and the roster the API won't tell you)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Wan's video models return silent clips. So my certified episode was silent.&lt;/p&gt;

&lt;p&gt;Listing the models available to my key turned up 149 of them, including the &lt;code&gt;qwen3-tts-flash&lt;/code&gt; voice family. A 107-character line synthesizes in 2.4 seconds.&lt;/p&gt;

&lt;p&gt;Easy win. Except for two things.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The twelve-hour episode.&lt;/strong&gt; The returned WAV is &lt;em&gt;streamed&lt;/em&gt;, so its header declares an effectively infinite length. A ~7-second clip reports &lt;strong&gt;44,739 seconds&lt;/strong&gt; to both &lt;code&gt;wave&lt;/code&gt; and &lt;code&gt;ffprobe&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Anything that trusts that header to size the output produces a half-day-long file.&lt;/p&gt;

&lt;p&gt;My assembler survives because &lt;code&gt;-shortest&lt;/code&gt; bounds every segment by its &lt;em&gt;video&lt;/em&gt;, and a paired &lt;code&gt;apad&lt;/code&gt; stops a short narration line from truncating the video the other way. Verified: a 5.00s clip muxed with that 44,739s-declaring WAV comes out at exactly 5.00s.&lt;/p&gt;

&lt;p&gt;Never trust a container's self-reported duration for a stream. Bound it by something you &lt;em&gt;do&lt;/em&gt; know.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The roster you can't list.&lt;/strong&gt; Narration shipped with one hardcoded voice, so every character sounded identical.&lt;/p&gt;

&lt;p&gt;Giving a cast distinct voices means knowing which voices this account may actually use. And the API won't say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;400 InvalidParameter: Invalid voice specified, the requested voice does not exist
                      or is not licensed for use—please select a supported voice.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That message enumerates nothing.&lt;/p&gt;

&lt;p&gt;And &lt;em&gt;"not licensed for use"&lt;/em&gt; means availability is an &lt;strong&gt;account&lt;/strong&gt; property, not a model property. So the roster has to be probed, not read.&lt;/p&gt;

&lt;p&gt;I fired 20 candidate names at &lt;code&gt;qwen3-tts-flash&lt;/code&gt;. Got 200-with-audio for all 20:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Cherry&lt;/code&gt; · &lt;code&gt;Ethan&lt;/code&gt; · &lt;code&gt;Nofish&lt;/code&gt; · &lt;code&gt;Jennifer&lt;/code&gt; · &lt;code&gt;Ryan&lt;/code&gt; · &lt;code&gt;Katerina&lt;/code&gt; · &lt;code&gt;Elias&lt;/code&gt; · &lt;code&gt;Jada&lt;/code&gt; · &lt;code&gt;Dylan&lt;/code&gt; · &lt;code&gt;Sunny&lt;/code&gt; · &lt;code&gt;Li&lt;/code&gt; · &lt;code&gt;Marcus&lt;/code&gt; · &lt;code&gt;Roy&lt;/code&gt; · &lt;code&gt;Peter&lt;/code&gt; · &lt;code&gt;Rocky&lt;/code&gt; · &lt;code&gt;Kiki&lt;/code&gt; · &lt;code&gt;Eric&lt;/code&gt; · &lt;code&gt;Serena&lt;/code&gt; · &lt;code&gt;Chelsie&lt;/code&gt; · &lt;code&gt;Aiden&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Which brings back the rule from earlier. My script agent emits a &lt;code&gt;speaker&lt;/code&gt; — a character name. The server casts the voice from that probed roster.&lt;/p&gt;

&lt;p&gt;The model &lt;em&gt;cannot&lt;/em&gt; emit an invalid voice, because it never emits a voice at all.&lt;/p&gt;

&lt;p&gt;That closure earns its keep here more than anywhere. Because this failure is &lt;strong&gt;silent&lt;/strong&gt;: an unlicensed voice degrades that shot to silence rather than failing the run. A certified episode would just have a hole in it, and nothing would say so.&lt;/p&gt;

&lt;p&gt;One more detail that's load-bearing. Casting is by &lt;strong&gt;order of first appearance&lt;/strong&gt;, fixed at scripting time — not by hashing the character's name.&lt;/p&gt;

&lt;p&gt;A hash can collide and hand two characters one voice with nothing to signal it. An ordinal is equally deterministic, so a re-run casts identically and every narration cache key still hits.&lt;/p&gt;

&lt;p&gt;That key is &lt;code&gt;sha1(model|voice|text)&lt;/code&gt;. Unstable casting would silently re-synthesize every line on a replay that was supposed to be free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Making it survive the judges&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A gate is only real if someone can click it. And generated media is slow and quota-sensitive — exactly the wrong properties for a live demo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A content-addressed cache.&lt;/strong&gt; Identical &lt;code&gt;(model, prompt, seed, size)&lt;/code&gt; requests replay from disk for free:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;billed video-seconds&lt;/th&gt;
&lt;th&gt;wall clock&lt;/th&gt;
&lt;th&gt;shots certified&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cold (2 uncached finals)&lt;/td&gt;
&lt;td&gt;10 s (~$3.00 est.)&lt;/td&gt;
&lt;td&gt;207 s&lt;/td&gt;
&lt;td&gt;3/3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warm (everything cached)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 s ($0.00)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6 s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3/3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Re-certifying real 1080p video costs zero video quota. Across the entire life of this project, my honest end-to-end runs have spent &lt;strong&gt;35 video-seconds. Total. Ever.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A real deployment.&lt;/strong&gt; The backend runs on an Alibaba Cloud Simple Application Server in &lt;code&gt;us-west-1&lt;/code&gt; — nginx serving the SPA on &lt;code&gt;:80&lt;/code&gt;, proxying &lt;code&gt;/api&lt;/code&gt; to a uvicorn app, bind-mounted volume so cache and run-state survive restarts. A push to &lt;code&gt;main&lt;/code&gt; triggers a GitHub Actions job that SSHes into the box, rebuilds, and gates on the health check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A catalog deliberately kept off the critical path.&lt;/strong&gt; Finished runs publish into a Postgres 18 sidecar with media in a private Alibaba OSS bucket, addressed by content hash.&lt;/p&gt;

&lt;p&gt;It's additive and flag-gated (&lt;code&gt;CATALOG_ENABLED&lt;/code&gt;, default off). Live runs stay on the in-memory store. A run gets mirrored only once it has &lt;em&gt;finished&lt;/em&gt;. Publishing tolerates a dead database or unreachable bucket and never raises.&lt;/p&gt;

&lt;p&gt;Why? Because a storage outage must not fail a run that already passed its gates. The conformance verdict is the product. Archiving it has a lower right to fail.&lt;/p&gt;

&lt;p&gt;One thing bit me immediately, and it's a direct consequence of my own determinism: &lt;strong&gt;media paths are many-to-one against content.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Deterministic runs produce byte-identical episodes. So ~40 project paths collapsed onto 13 objects.&lt;/p&gt;

&lt;p&gt;That's the cache working as designed. It also means the path→hash mapping needs its own &lt;code&gt;media_paths&lt;/code&gt; table — not a column on the object, where it would keep only the last path written and 404 every other one.&lt;/p&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%2Fn2q8jhxclmu7t936xwyg.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%2Fn2q8jhxclmu7t936xwyg.png" alt=" " width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The deploy had its own small war stories. A plan upgrade that grew the cloud disk but not the partition inside it — grow the partition &lt;em&gt;first&lt;/em&gt;, then the filesystem, because a filesystem can't stretch past its partition. And the discovery that this box is Alibaba Cloud Linux 3, RHEL-family, so it's &lt;code&gt;dnf&lt;/code&gt;, not &lt;code&gt;apt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The kind of thing you only learn by actually putting compute on the cloud, instead of calling its APIs from your laptop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this isn't just a demo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The engine has no coupling to the generator, because its checks take &lt;em&gt;frames&lt;/em&gt;, not generator internals.&lt;/p&gt;

&lt;p&gt;So it lifts out. It's exposed as an MCP server — the same primitive coding agents already speak — runnable as a package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvx &lt;span class="nt"&gt;--from&lt;/span&gt; &lt;span class="s1"&gt;'.[mcp]'&lt;/span&gt; dailies-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ListTools&lt;/code&gt; returns &lt;strong&gt;two&lt;/strong&gt; tools, and the pair is the point:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;run_shot_tests&lt;/code&gt;&lt;/strong&gt; — zero-token, deterministic Tier-A CV, runs on any mp4. The model-agnostic claim, made executable. It &lt;strong&gt;reports&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;patch_clip&lt;/code&gt;&lt;/strong&gt; — localizes the first blocking failure in time, anchors a Wan i2v regeneration just before it, re-verifies, and reports &lt;code&gt;patched&lt;/code&gt; only if the retake passes. It &lt;strong&gt;acts&lt;/strong&gt;, and spends one generation to do it.&lt;/p&gt;

&lt;p&gt;Watching a Qwen agent drive this loop was genuinely satisfying. It calls the free tool. Gets back a real &lt;code&gt;FAIL — camera static, |v|=0.00&lt;/code&gt;. Explains it in plain English. Then &lt;em&gt;offers&lt;/em&gt; the repair — naming it correctly as keyframe-to-video generation, which it only knows because &lt;code&gt;ListTools&lt;/code&gt; handed it &lt;code&gt;patch_clip&lt;/code&gt;'s description.&lt;/p&gt;

&lt;p&gt;It never fires it, because its system message forbids the tool that spends quota.&lt;/p&gt;

&lt;p&gt;A gate an agent can read is a gate an agent can act on.&lt;/p&gt;

&lt;p&gt;Both ends of that loop are mine. Dailies is an MCP &lt;em&gt;producer&lt;/em&gt;, and the client consuming it is a Qwen-Agent &lt;code&gt;Assistant&lt;/code&gt; with my own server in its &lt;code&gt;mcpServers&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;That same engine is reachable three ways — a native function-calling tool, a Qwen-Agent custom skill via &lt;code&gt;@register_tool&lt;/code&gt;, and the MCP server — over one shared core that imports neither &lt;code&gt;openai&lt;/code&gt; nor &lt;code&gt;qwen_agent&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let me be honest about the edges, because the whole ethos here is not claiming what the engine can't do.&lt;/p&gt;

&lt;p&gt;Assertions are per-shot and evaluated whole-clip. There's no audio transcript check, no OCR, no time-windowing (a "logo in the first 3 seconds" check), no episode-level concept yet.&lt;/p&gt;

&lt;p&gt;When a rule needs a modality the vocabulary lacks, the compiler &lt;strong&gt;omits it rather than approximating&lt;/strong&gt; it with a type that means something else. Known gap: that omission is currently silent.&lt;/p&gt;

&lt;p&gt;Those are roadmap, not shipped features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Qwen Cloud actually gave me&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The integration splits along a line the platform draws for you, and picking the right side per capability is most of what "sophisticated use" means here.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;OpenAI-compatible endpoint&lt;/strong&gt; (&lt;code&gt;dashscope-intl.aliyuncs.com/compatible-mode/v1&lt;/code&gt;) fronts everything text- and vision-shaped. &lt;code&gt;qwen-plus&lt;/code&gt; for scripting, repair, and both function-calling loops. &lt;code&gt;qwen-vl-plus&lt;/code&gt; for Tier-0 and Tier-B verdicts.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;native DashScope task API&lt;/strong&gt; handles the media models, because generation is long-running and the OpenAI-compatible shape has no vocabulary for it. &lt;code&gt;wan2.1-t2v-turbo&lt;/code&gt; drafts, &lt;code&gt;wan2.2-i2v-flash&lt;/code&gt; frame-anchored finals and repairs, &lt;code&gt;wan2.1-t2i-plus&lt;/code&gt; Tier-0 stills, &lt;code&gt;qwen3-tts-flash&lt;/code&gt; narration.&lt;/p&gt;

&lt;p&gt;Video generation is &lt;em&gt;mandatorily&lt;/em&gt; asynchronous — create with &lt;code&gt;X-DashScope-Async: enable&lt;/code&gt;, then poll. And it carries a gotcha I'm very glad I found on day one, at zero cost:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP 200 on create does not mean the request was valid.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Validation surfaces asynchronously, on the first poll. So retries must branch on the polled &lt;code&gt;task_status&lt;/code&gt;, never the POST's status code. (The image endpoint, confusingly, validates &lt;em&gt;synchronously&lt;/em&gt; and returns a 400.)&lt;/p&gt;

&lt;p&gt;One more finding I'd reuse anywhere: the video endpoints accept a base64 &lt;code&gt;data:&lt;/code&gt; URI in place of an image URL. That's what my entire repair feature depends on, because a frame extracted on a &lt;code&gt;127.0.0.1&lt;/code&gt; box has no public URL and now needs no upload step.&lt;/p&gt;

&lt;p&gt;And notice what's &lt;em&gt;missing&lt;/em&gt; from that model list. The deterministic tier.&lt;/p&gt;

&lt;p&gt;Tier-A is OpenCV. It calls nothing. The Qwen surface gets spent on generation and judgment — never on measurement.&lt;/p&gt;

&lt;p&gt;Which is the whole reason measurement can run on every take.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test the artifact, not the prompt.&lt;/strong&gt; Orchestrating models is only half the problem, and it's the easy half. The hard half — the one almost nobody demos — is deciding &lt;em&gt;when not to call the expensive model&lt;/em&gt;, and being able to prove with a number that the thing you didn't render was one you were right to reject.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A mock can only confirm your own mental model.&lt;/strong&gt; It returns what you told it to, so a suite of mocks re-asserts your assumptions back at you in green. The real contract lives at the boundary with the external service. If you're integrating any generative API, spend the tokens on one real end-to-end run &lt;em&gt;early&lt;/em&gt;. Cheapest bug-finder you'll ever build.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Let the model choose, never let it spell.&lt;/strong&gt; Don't validate the model's output — make invalid output unrepresentable. Ask what the model actually needs to &lt;em&gt;decide&lt;/em&gt;, which is almost always far less than what you're asking it to &lt;em&gt;emit&lt;/em&gt;. A closed vocabulary, a parameter contract, a probed roster: three shapes a bad value can't fit through.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generalize by measurement, not by resemblance.&lt;/strong&gt; My best idea worked beautifully in the case I built it for, so I extended it everywhere by analogy. Two real generations proved half of it wrong. The failure mode isn't that the primitive is bad — it's that you've silently changed what you're asking it to preserve.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Watch for the bugs that present as success.&lt;/strong&gt; A fallback returning the success value. A missing result that reads as a passing one. Two code paths deriving the same value independently. A wrapper whose subject moved. None of these fail loudly, and green tests love them.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, here's the recap:&lt;/p&gt;

&lt;p&gt;· AI video fails in motion, after you've already paid for it&lt;br&gt;
· The fix isn't better prompts — it's a spec you can assert against&lt;br&gt;
· Deterministic checks first, model judgment on top, never underneath&lt;br&gt;
· Verification doesn't just reject bad output; sometimes it deletes spend&lt;br&gt;
· Every bug worth finding looked like success first&lt;/p&gt;

&lt;p&gt;Dailies is open source (MIT), built for Track 2 of the Global AI Hackathon Series with Qwen Cloud, and deployed on Alibaba Cloud.&lt;/p&gt;

&lt;p&gt;Go test your generated video like you test your code.&lt;/p&gt;

&lt;p&gt;Happy shipping!&lt;/p&gt;

</description>
      <category>qwen</category>
      <category>alibaba</category>
      <category>cloud</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to contribute to a large codebase?</title>
      <dc:creator>Kaung Zin Hein</dc:creator>
      <pubDate>Thu, 03 Oct 2024 03:19:56 +0000</pubDate>
      <link>https://dev.to/zin_kg/how-to-contribute-to-a-large-codebase-2ho0</link>
      <guid>https://dev.to/zin_kg/how-to-contribute-to-a-large-codebase-2ho0</guid>
      <description>&lt;p&gt;&lt;em&gt;A step-by-step guide on contributing to open-source projects with thousands of lines of code&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;As a budding open-source contributor, I was at a loss when I found a lack of resources on how to get started. Other than a few good guides, most of the advice is general and, often, shallow. &lt;strong&gt;I felt like the concrete steps were brushed off and left to the readers to figure out for themselves.&lt;/strong&gt; Which, in a sense, makes for a great learning experience. At the same time, I felt overwhelmed by the number of projects on GitHub, by the number of issues in major projects. &lt;/p&gt;

&lt;p&gt;Even for a developer with years of experience, approaching a new codebase takes domain-specific knowledge and patience. On top of that, errors thrown when navigating through the code maze may not even be due to a lack of skills - &lt;strong&gt;poorly documented build guides, platform incompatibility&lt;/strong&gt;, etc., may explain why the repository you just cloned doesn’t work.&lt;/p&gt;

&lt;p&gt;With that said, a pre-requisite before diving into a large codebase is to get familiar with contributing to small-to-medium-sized repositories. The best projects to contribute to are ones you’re most knowledgeable about, ones that you’re most familiar with. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But here’s the catch.&lt;/strong&gt; A lot of what we use daily may not be a simple library that solves one thing. It may well be a full-blown framework or a full-stack application. That’s why it’s important to have honed in on the foundational concepts and the semantics of your language. I don’t mean mastery - which is a continuous pursuit, rather than an accomplishment - I’m referring to an &lt;strong&gt;attempt&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your attempt at trying to master something.&lt;/strong&gt; For example, I wrote a few &lt;a href="https://www.npmjs.com/settings/zin_kg/packages" rel="noopener noreferrer"&gt;npm modules&lt;/a&gt; to better familiarize myself with the native Node.js APIs. Why Node.js? Because my goal was/is contribute and learn from other web technologies built on the Javascript ecosystem. I’ll talk more about writing utilities in another guide. &lt;/p&gt;

&lt;p&gt;For now, here’s my approach when dealing with a large open-source repository:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Use the tool so you understand, what some call, the business problem.&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;How is it helping customers or developers?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The ideal project to contribute to is one whose API you’ve been using regularly. Whose functions and classes you know well enough to integrate it into your applications and other projects. Familiarity with the public implementations lend itself to understanding the internal code better. If it’s a project you’re completely new to but are willing to dig into, the “Getting Started” guide from the official docs is a great starting point. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Start with the &lt;em&gt;what&lt;/em&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Reading a codebase in general terms (the main functions, the entry point, the layers, etc.) is a good practice. But what’s even more effective? A targeted approach. &lt;/p&gt;

&lt;p&gt;Trying to solve an issue and following the code trail that the problem leads to, may not cover as many lines of code as passively reading, but it puts to test your understanding of a small subset of the repository. Here's a task for you: open an issue you’ve run into (ideal) or pick up a manageable issue. This approach, &lt;strong&gt;compounded over time, issues, and PRs&lt;/strong&gt;, can lead to deeper understanding. &lt;/p&gt;

&lt;p&gt;It’s tricky to define ‘manageable’ because not every project owner assigns ‘good-first-issue’ or ‘up-for-grabs’ labels. And depending on the project, even issues with those beginner-friendly tags may still seem daunting. Which brings us to the next step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Analyze how existing modules and tests are set up.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Take those as reference in laying out the structure of your code and tests. For example, when adding a new plugin, study how other integrations are written and copy the outline of the corresponding tests.&lt;/p&gt;

&lt;p&gt;Doing so ensures that you’re following best practices that are &lt;strong&gt;specific&lt;/strong&gt; to the repository at hand and staying in sync with other contributors’ code style.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Write down the build and test process.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Note-taking doesn’t get the credit it deserves especially in the software development circle. That’s because note-taking is a skill many haven’t mastered yet, or not willing to try at all. &lt;/p&gt;

&lt;p&gt;Instead of looking for &lt;strong&gt;patterns&lt;/strong&gt;, some mark everything down, quickly leading to burnout. Building and testing are processes at the core of most projects. They are the steps you take after making any sort of change. If you’re dealing with a repository more than once (not a &lt;a href="https://opensauced.pizza/blog/yolo-coder" rel="noopener noreferrer"&gt;YOLO contribution&lt;/a&gt;), it’s worth the time to jot down exactly how a change in the code is tested. &lt;/p&gt;

&lt;p&gt;Likewise, in a mono-repo, you don’t want to waste time trying to build and test every package when the changes you’ve made only affect one or a few. But wait, can’t the compiling and testing for one package be done via a script each? Probably yes. But when you’re fiddling with more than a single package and their workspace dependencies, the processes tend to involve a couple of steps. &lt;/p&gt;

&lt;p&gt;The practice is beneficial in 2 main ways: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A)&lt;/strong&gt; When you return to an issue after taking a break, all the steps you’d taken last time are right before you. So, &lt;strong&gt;you can focus on the problem-solving part immediately&lt;/strong&gt;, instead of trying to recall what you did the last time for building/testing/modifying configs. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B)&lt;/strong&gt; When tackling a similar issue, you can follow the same process, instead of figuring out the steps from scratch. This saves time! Which matters a lot when your goal is to ship quality features/fixes as quick as possible. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Apply forensics on the commit history of a particular block of code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When figuring out why a piece of code is implemented, reviewing not only the related PRs, but also the surrounding discussion (comments, reviews, linked issues/PRs) leaves clues - &lt;strong&gt;often outright solutions&lt;/strong&gt;. This step helps you learn about the thought process and the decisions that were formed by other contributors before you arrived. For example, you can check why the author introduced a new utility function or how a bug was fixed. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Take feedback from maintainers/major contributors to heart.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No one’s more familiar with the codebase than those who’ve spent months and years working on it. Try to fix the pain points that they’ve brought up, especially in a code review. &lt;/p&gt;

&lt;p&gt;On the other hand, don’t be too sorry to point out their misunderstanding of the intent of your code or to state your doubt on their arguments. Open-minded senior devs are willing to elaborate and are, well, open to feedback themselves. &lt;/p&gt;




&lt;h2&gt;
  
  
  Summary with Actions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Use the product/library/framework.&lt;/strong&gt;&lt;br&gt;
Action: If it’s not a tool you’re already familiar with, try it out to get the hang of it. Start from the official docs. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Follow a bottom-up approach.&lt;/strong&gt;&lt;br&gt;
Action: Open or pick up an issue. Analyze the necessary code files and functions as you try to solve the issue. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Look at the structure of existing modules and tests.&lt;/strong&gt;&lt;br&gt;
Action: Analyze and apply a similar (or sometimes the same) structure to your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Write down the build and test process.&lt;/strong&gt;&lt;br&gt;
Action: Record how exactly you compile and test the code involved in your PR. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Learn from the past.&lt;/strong&gt;&lt;br&gt;
Action: Review the commit history and the related conversations, code reviews, and comments. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Accept constructive feedback.&lt;/strong&gt;&lt;br&gt;
Action: Review and try to resolve the code reviews from senior contributors. Don’t hesitate to explain any misunderstanding.  &lt;/p&gt;

&lt;p&gt;Happy contributing!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>community</category>
      <category>github</category>
    </item>
    <item>
      <title>Filtering in ExpressJS</title>
      <dc:creator>Kaung Zin Hein</dc:creator>
      <pubDate>Fri, 16 Aug 2024 23:29:16 +0000</pubDate>
      <link>https://dev.to/zin_kg/filtering-in-expressjs-8ng</link>
      <guid>https://dev.to/zin_kg/filtering-in-expressjs-8ng</guid>
      <description>&lt;p&gt;How I implemented the filter feature in my volunteer management application&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is part of the series explaining the principles and algorithms implemented in my capstone web application project. You can check out the app &lt;a href="https://volunteer-mern.vercel.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Or view the &lt;a href="https://github.com/Zen-cronic/volun-mern" rel="noopener noreferrer"&gt;source code&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A major ingredient for modern management applications (be it content, e-commerce, customer, or financial) is the filter feature, alongside sorting and searching. Here’s how I’ve implemented it in my web app. It filters volunteer events in the backend, according to the filter category sent by the client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzoce1yf6ipaet4xitzig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzoce1yf6ipaet4xitzig.png" alt="Filtering for events located externally (outside the organization) and with open shift positions&lt;br&gt;
" width="800" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The goal here is to build a custom filter feature using what Express can offer, without depending on any third-party library. So, I decided to make use of the request-response lifecycle and the “locals” property of the response.&lt;/p&gt;

&lt;p&gt;Following the modern MCV architecture for ExpressJS applications, I’ve refactored the previous code by separating business logic from the controller. This logic is contained in service functions. Let’s take a look at the filter controller first.&lt;/p&gt;
&lt;h2&gt;
  
  
  Filter events controller
&lt;/h2&gt;

&lt;p&gt;This controller is an array of request handlers, each wrapped in an express-async-handler function to manage asynchronous errors. Its length depends on the number of filter categories that are stored as constants. As of now, these are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Event date (date)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Event venue (venue)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Events with open positions (isOpen)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Events that are happening in the future (isUpcoming)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Plus, the service function of the last handler is responsible for curating the filtered results (event IDs) from the above 4 filters and sorting each result based on how many filter categories it falls under. So, I’ve got an array of 5 request handlers.&lt;/p&gt;

&lt;p&gt;Let’s examine the request handler for the event venue category (venue).&lt;/p&gt;
&lt;h2&gt;
  
  
  Filter Events by Venue
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filterEventsHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="c1"&gt;//venue filter&lt;/span&gt;
  &lt;span class="nf"&gt;asyncHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;objKeysIncludes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FILTER_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VENUE&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="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;venue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filteredVenue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;filterEventsByVenue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;venue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;

&lt;span class="c1"&gt;//...more handlers &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Inside the handler, there’s a helper function that checks whether or not req.body (sent from the client) includes the category “venue”. This function serves as a form of data validation for the user input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;objKeysIncludes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;if&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="nx"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Obj param must be an object&lt;/span&gt;&lt;span class="dl"&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;checked&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;If it’s included, the value of the venue is extracted (e.g., {venue: “External”}), after which it’s processed by the service that filters events by venue. The result is an array of event IDs, which are then stored in res.locals property. The data/variable stored() in res.locals is not shared between requests as they belong only to the current request-response cycle. If the client didn’t include the “venue” filter, this request handler is skipped by returning the next function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;objKeysIncludes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FILTER_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VENUE&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="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;venue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filteredVenue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;filterEventsByVenue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;venue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even after storing the filtered result in res.locals, next has to be called, moving on to the following handler that checks for another filter category.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Handler
&lt;/h2&gt;

&lt;p&gt;After repeating this process for all categories, we arrive at the last handler. Its service function (filterEvents) sorts all the filtered event IDs from res.locals, attaches the filter tags that each event belongs to, and returns a sorted array of events based on the number of tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="c1"&gt;//sorted filter&lt;/span&gt;
  &lt;span class="nf"&gt;asyncHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;filteredAllIds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;idsWithTags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;sortedIdsWithTags&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="nf"&gt;filterEvents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;locals&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;filteredAllIds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;idsWithTags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;sortedIdsWithTags&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;p&gt;Let’s see how it works.&lt;/p&gt;

&lt;p&gt;The values of the properties in &lt;code&gt;res.locals&lt;/code&gt; stored by the preceding filter handlers are assigned to respective variables. Object destructing is not used because the client may not have selected all filter categories, making these variables undefined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filterEvents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filterObj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;resLocals&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredVenue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resLocals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filteredVenue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resLocals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filteredDate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredIsOpen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resLocals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filteredIsOpen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredIsUpcoming&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resLocals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filteredIsUpcoming&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;span class="nx"&gt;Then&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;declared&lt;/span&gt; &lt;span class="nx"&gt;which&lt;/span&gt; &lt;span class="nx"&gt;will&lt;/span&gt; &lt;span class="nx"&gt;house&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="nf"&gt;category &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.,&lt;/span&gt; &lt;span class="nx"&gt;venue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;corresponding&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;property&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;See&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;example&lt;/span&gt; &lt;span class="nx"&gt;below&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;where&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="nx"&gt;ID&lt;/span&gt; &lt;span class="nx"&gt;qualifies&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;selected&lt;/span&gt; &lt;span class="nx"&gt;venue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="c1"&gt;// {"venue": [id1, id2, id3]}&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filterObj&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;filterKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filterKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;FILTER_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;filterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;filteredDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;FILTER_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IS_OPEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;filterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;filteredIsOpen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;FILTER_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VENUE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;// filteredResultsByKey[filterKey] = filteredVenue&lt;/span&gt;

        &lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;filterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;filteredVenue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nx"&gt;FILTER_OPTIONS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IS_UPCOMING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;filterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;filteredIsUpcoming&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

      &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&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;p&gt;Next, the property values of filteredResultsByKey are turned into a 1-D array (from a 2-D array). This service function returns an array of event IDs, each with only one occurrence, which is stored in the filteredAllIds variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredAllIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;filterArrSortLoose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;Object&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="nx"&gt;filteredResultsByKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;//filterArrSortLoose helper&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filterArrSortLoose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;twoDArr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;twoDArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;arr&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;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;each elem must be an arr - an arr of arr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oneDArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;twoDArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;matchIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="nx"&gt;oneDArr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;matchIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;matchIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matchIds from loose filter: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;matchIds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;matchIds&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;
  
  
  Filter Tags
&lt;/h2&gt;

&lt;p&gt;Finally, it’s time for the most challenging task yet. Assign filter tags to each event ID. To do so, we need to relate the filteredResultsByKey object and filteredAllIds array, resulting in an idsWithTags array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//filteredResultsByKey&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nl"&gt;filterKey1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="nx"&gt;filterKey2&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//filteredAllIds&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;//filteredResultsByKey + filteredAllIds -&amp;gt; idsWithTags&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;id1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;filterKey1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;filterValue&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;filterKey2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;filterValue&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;id2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;filterKey2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;filterValue&lt;/span&gt;&lt;span class="p"&gt;}]},&lt;/span&gt;
 &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;id3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="na"&gt;filterKey1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;filterValue&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="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that an event ID can appear under more than one filter category. In this case, we assign all the associated filter tags to the event ID object.&lt;/p&gt;

&lt;p&gt;In the following nested loop, the outer loop iterates over all filtered IDs, and the inner loop runs through each entry of the filteredResultsByKey object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;filteredAllIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;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="p"&gt;{&lt;/span&gt;

    &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filteredResultsByKey&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;filterKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filterKeyVal&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filterObj&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&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="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;filterKey&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each event ID, we must find the corresponding filter category it belongs to by iterating through each entry in the filteredResultsByKey and cross-checking with req.body (filterObj).&lt;/p&gt;

&lt;p&gt;If the key from the &lt;code&gt;req.body&lt;/code&gt; equals the current key of &lt;code&gt;filteredResultsByKey&lt;/code&gt;, we access the value of the key (e.g., in &lt;code&gt;{date: “2023–12–31”&lt;/code&gt;, 2023–12–31 is the value). This filter category value (filterKeyVal object) and the filter key are appended as a filter tag for each qualifying event ID.&lt;/p&gt;

&lt;p&gt;If the current event id (outer loop) is included in a property array of filteredResultsByKey (inner), there are two possible scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The event ID object is already included in the idsWithTags array, which means the event qualifies for more than one filter category.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The event ID object is not included yet.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both scenarios are determined by finding in the idsWithTags array an object whose eventId property has the same value as the current event id. The responsible helper function returns an index number if found, and -1 if not found.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isEventIdAlrExists&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;elemObjPropValIncludes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nx"&gt;idsWithTags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eventId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;id&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;//...&lt;/span&gt;

&lt;span class="c1"&gt;//helper to determine if current event ID is already in idsWithTags&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elemObjPropValIncludes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;propKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;checkedPropVal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


    &lt;span class="c1"&gt;//propKey must exists in all objs in the array&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hasOwn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;propKey&lt;/span&gt;&lt;span class="p"&gt;)))){&lt;/span&gt;

        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`all elem obj in the arr must contain propKey: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;propKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; : as a property key`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;included&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findIndex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;propKey&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;checkedPropVal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;included&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;Dealing&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;second&lt;/span&gt; &lt;span class="nx"&gt;scenario&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;simple&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;We&lt;/span&gt; &lt;span class="nx"&gt;just&lt;/span&gt; &lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;eventId&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;filterTags&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt; &lt;span class="nx"&gt;entries&lt;/span&gt; &lt;span class="nx"&gt;into&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

 &lt;span class="nx"&gt;idsWithTags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;eventId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;filterTags&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="nx"&gt;filterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;filterKeyVal&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;For the first case, however, there’s an extra step involved. We must map through the idsWithTags array until we arrive at the current event. Then, reassign that event ID object with the additional filter category entry it belongs to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bufferArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;idsWithTags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eventId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

              &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;filterTags&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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filterTags&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="nx"&gt;filterKey&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;filterKeyVal&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="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;

          &lt;span class="nx"&gt;idsWithTags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bufferArr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After assigning tags to each event, we must sort them in descending order based on the number of tags. At the end of the request-response cycle, this final handler returns &lt;code&gt;sortedIdsWithTags&lt;/code&gt; to the client. It’s now the front-end’s job to manage how the events with filtered tags will be displayed.&lt;/p&gt;

&lt;p&gt;That’s it! That’s how I’ve implemented filtering in my Express API using the nature of the request-response cycle and &lt;code&gt;res.locals&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;The key takeaways I got from coming up with this feature are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request-response cycle&lt;/li&gt;
&lt;li&gt;Modular middleware and the role of &lt;code&gt;next()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Data Validation&lt;/li&gt;
&lt;li&gt;Higher Order functions&lt;/li&gt;
&lt;li&gt;Filtering logic!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Further improvements in the future:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Map and Set for a simpler data structure&lt;/li&gt;
&lt;li&gt;Implementing Bloom’s filter algorithm&lt;/li&gt;
&lt;li&gt;You can interact with the app live &lt;a href="https://volunteer-mern.vercel.app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;. Or view the code on my &lt;a href="https://github.com/Zen-cronic/volun-mern" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Why write a library?</title>
      <dc:creator>Kaung Zin Hein</dc:creator>
      <pubDate>Fri, 03 May 2024 04:01:54 +0000</pubDate>
      <link>https://dev.to/zin_kg/why-write-a-library-4ceb</link>
      <guid>https://dev.to/zin_kg/why-write-a-library-4ceb</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a blog version of the talk I gave at &lt;a href="https://www.linkedin.com/company/torontojs/"&gt;TorontoJS&lt;/a&gt; Lightning Talks event on Apr 30, 2024.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzicy4szz0l9gmsx08xpb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzicy4szz0l9gmsx08xpb.jpg" alt="Me at talk event, intro slide" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My technical pet peeve
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7vmgyh5dpuvx9gzhiwd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7vmgyh5dpuvx9gzhiwd.png" alt="console-log" width="800" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This &lt;em&gt;irritates&lt;/em&gt; me - typing a variable’s name beside the variable in the log statement. It isn’t that big of a problem for just a few variables here and there. But many variables multiplied by many files in your app? You do the math. &lt;/p&gt;

&lt;p&gt;That's when I realized writing my own &lt;a href="https://github.com/Zen-cronic/scope-logger"&gt;logging library&lt;/a&gt; could save me some headaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rant continues...
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsyppqe2w415nu35x5vig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsyppqe2w415nu35x5vig.png" alt="Many logs to comment and delete" width="678" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, who enjoys commenting out or deleting log statements before pushing their code to production? I &lt;em&gt;really&lt;/em&gt; don't. &lt;/p&gt;

&lt;p&gt;Fortunately, there are tools available to solve this such as the  &lt;a href="https://github.com/debug-js/debug"&gt;&lt;code&gt;debug&lt;/code&gt; library&lt;/a&gt; which is based on the core NodeJS logging utility. &lt;/p&gt;

&lt;p&gt;We already have a solution. So why bother? Let’s take a look at my personal use case: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qodu2hfka2dcik4wb73.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5qodu2hfka2dcik4wb73.png" alt="A variable logged inside nested functions" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More often than not, a variable is logged from within nested function calls, and across multiple files. When I wanted to quickly check from where a variable is being logged (that happens after you’re debugging and have called it a day and you return to it later), I would write the metadata (the function name) &lt;strong&gt;next&lt;/strong&gt; to the log variable. &lt;/p&gt;

&lt;p&gt;Instead of a quick check, this process became quickly &lt;em&gt;tedious&lt;/em&gt;. Here was a use case that i hadn't found any JS library addressing (as far as I know).&lt;/p&gt;

&lt;h2&gt;
  
  
  Time to &lt;em&gt;modify&lt;/em&gt; the wheel!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftxq3zycdcgs1t5i4y1s1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftxq3zycdcgs1t5i4y1s1.png" alt="My library in action" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, I decided to write a &lt;a href="https://github.com/Zen-cronic/scope-logger"&gt;module&lt;/a&gt; that logs the value of the variable alongside its name without having to type the name manually. And I'll share with you how I did it from scratch. &lt;/p&gt;

&lt;p&gt;Of course, this can be done using &lt;code&gt;console.log()&lt;/code&gt; with the object destructing &lt;code&gt;{ }&lt;/code&gt; property. &lt;/p&gt;

&lt;p&gt;But what &lt;code&gt;console.log()&lt;/code&gt; lacks is the ability to print the &lt;strong&gt;function scopes&lt;/strong&gt; of the logged variable in a developer-friendly way. Here's the output: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvk655or0g8s1bnq4nwy9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvk655or0g8s1bnq4nwy9.png" alt="My library's output" width="789" height="170"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By &lt;strong&gt;developer-friendly&lt;/strong&gt;, I mean anyone seeing this log message in their terminal can immediately tell the function scope of the variable being logged. The order of function scopes is parsed from the call stack provided by the NodeJS stack trace API. Hence the name, &lt;a href="https://github.com/Zen-cronic/scope-logger"&gt;&lt;em&gt;scope-logger&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: “Object.” just means the outermost function is invoked from the global object/topmost level of the file.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's the recipe on how to write a library by studying others (in pseudo-code!): &lt;/p&gt;

&lt;h2&gt;
  
  
  Steps.length = 4
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf1i1izih6hiwlu6w745.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgf1i1izih6hiwlu6w745.png" alt="Library making steps in pseudo-code" width="772" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0: Just build it!
&lt;/h2&gt;

&lt;p&gt;“Zero” not only because we are programmers, also because it’s one fundamental step before taking any further. You must be building the Minimum Viable Product (&lt;strong&gt;MVP&lt;/strong&gt;) as soon as possible, or at the very least, a small chunk of it. &lt;/p&gt;

&lt;p&gt;You’re &lt;strong&gt;not&lt;/strong&gt; striving for perfection. You just need a working version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Start small
&lt;/h2&gt;

&lt;p&gt;As a reference, pick a small library with similar use cases to your idea. &lt;br&gt;
Here’s my criteria for selecting one: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Popular&lt;/strong&gt;: not because it’s the new kid on the block, but because it’s been well-maintained for a long while with a large, active user-base.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Well-tested&lt;/strong&gt;: because quality is important - look for integration/e2e tests and unit tests.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Challenging enough for analysis&lt;/strong&gt;: you don’t wanna be tackling the Express framework or React on your first go. Pick a library that is considerably smaller, which you can determine by the following factor.   &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number of dependencies&lt;/strong&gt;: one way to tell if a library is &lt;strong&gt;not&lt;/strong&gt; too challenging to be used as study source is based on the production dependencies count. The fewer the better. For example, I chose &lt;a href="https://github.com/debug-js/debug"&gt;&lt;code&gt;debug&lt;/code&gt;&lt;/a&gt; because it only has 1 dependency (&lt;a href="https://github.com/vercel/ms"&gt;ms&lt;/a&gt;), while the rest of the code relies on core NodeJS modules - which is exactly what I was looking for - to learn how to build a library from scratch, not off the shelf libraries with many external deps, which in turn are based on more deps. There you go, dependency hell.  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Break it down smaller
&lt;/h2&gt;

&lt;p&gt;After you’ve picked a library, break it down even smaller. Study how the main functions work by replicating their behaviors: &lt;strong&gt;isolate&lt;/strong&gt; those functions, provide input, and see the output.&lt;/p&gt;

&lt;p&gt;This is one of the few times that you should allow yourself to fall into &lt;strong&gt;rabbit holes&lt;/strong&gt;, and really understand the in’s and out’s of each line of code in a function.&lt;/p&gt;

&lt;p&gt;For example: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhty7tjo2kzdtm4q7apt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhty7tjo2kzdtm4q7apt.png" alt="debugjs formatArgs function" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the &lt;code&gt;formatArgs()&lt;/code&gt; function of the &lt;a href="https://github.com/debug-js/debug"&gt;&lt;code&gt;debug&lt;/code&gt;&lt;/a&gt; library. By isolating it, I learned about ANSI colour escape codes, and where and how the properties of one debug instance is used (&lt;code&gt;namespace&lt;/code&gt;, &lt;code&gt;useColours&lt;/code&gt;, and &lt;code&gt;this.colour&lt;/code&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Publish
&lt;/h2&gt;

&lt;p&gt;After you’ve studied other approaches and built your own module, all there's left to do is hit publish, right? Well, not before you complete these three things. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Semantic Versioning&lt;/strong&gt;: for every update (major, minor, or patch) made, increment the version number according to &lt;a href="https://semver.org/"&gt;semantic versioning&lt;/a&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Changelog/history&lt;/strong&gt;: track and display the updates you’ve made so far - the version number, the date you published it, and a brief description of those changes.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnhdpfn4h4ee7askboud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnhdpfn4h4ee7askboud.png" alt="scope-logger changelog/history" width="550" height="778"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: You cannot expect other developers to magically figure out how to use your library without detailed descriptions of the features. It also serves as a roadmap of what you’ve built. You can either dedicate a whole website for it or simply fill in the &lt;a href="https://github.com/Zen-cronic/scope-logger/#readme"&gt;README.md&lt;/a&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: I left out &lt;strong&gt;tests&lt;/strong&gt; because we should be writing them as the library is being built, not just before hitting publish.&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Recipe Recap
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zero&lt;/strong&gt;: you build a working version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One&lt;/strong&gt;: start small by picking a small but challenging enough library to learn from&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two&lt;/strong&gt;: analyze that library by breaking it down into even smaller pieces&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three&lt;/strong&gt;: after attaching semantic versioning, changelog, and documentation, hit publish. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Breaks are Great!
&lt;/h2&gt;

&lt;p&gt;These steps are in a loop, repeated until it’s time for a &lt;strong&gt;break&lt;/strong&gt;, which is just as important as the preceding steps. &lt;/p&gt;

&lt;p&gt;As a rule of thumb, after publishing your major or minor version, or several patch updates in a row, take your &lt;em&gt;well-deserved&lt;/em&gt; break!&lt;/p&gt;

&lt;p&gt;Taking a break is great for discovering more use cases as you use the library/module you just made in other projects. &lt;/p&gt;

&lt;p&gt;As you might’ve guessed, I did use &lt;a href="https://github.com/Zen-cronic/scope-logger"&gt;&lt;code&gt;scope-logger&lt;/code&gt;&lt;/a&gt; to develop other modules. By doing so, I found features that I &lt;em&gt;really&lt;/em&gt; needed, not just stuff that I thought would be cool to have.&lt;/p&gt;

&lt;p&gt;When a particular use case keeps popping up, that’s my &lt;strong&gt;cue&lt;/strong&gt; to update the library with a new feature to address it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Solve your own problems first&lt;/strong&gt;: As a budding developer, how do you go about determining what projects to pursue? The idea for this library occurred to me as I was building projects for my portfolio. With limited industry connections and programming know-how to cater to a target audience, I felt stuck. But there lurked a hidden opportunity. If you're in the same boat, try this: &lt;em&gt;ditch the latest trends, and double down on understanding the nuts and bolts of one technology, to tackle a problem that's currently bogging &lt;strong&gt;you&lt;/strong&gt; down&lt;/em&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reinvent the wheel, sometimes&lt;/strong&gt;: And to solve your developer problem, contrary to conventional advice, you must reinvent the wheel to understand in-depth how the wheel is built. In the long haul, the &lt;strong&gt;time&lt;/strong&gt; and &lt;strong&gt;effort&lt;/strong&gt; put into studying a great library, and building one using core modules and fundamental programming principles, is what’s gonna make you &lt;em&gt;stand out&lt;/em&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Depth &amp;amp;&amp;amp; Breadth (not versus)&lt;/strong&gt;: With that said, depth is &lt;strong&gt;not&lt;/strong&gt; the superior path. Tread both. The &lt;em&gt;breadth&lt;/em&gt; part involves exploring other libraries, studying their differences, and observing patterns that show up repeatedly. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;So, I invite you to try this project idea - create a library by studying great examples. As slow as it may seem, your programming craft will grow exponentially. &lt;/p&gt;

</description>
      <category>library</category>
      <category>node</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
