<?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: Hiroshi TK</title>
    <description>The latest articles on DEV Community by Hiroshi TK (@hiroshi_takamura_c851fe71).</description>
    <link>https://dev.to/hiroshi_takamura_c851fe71</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%2F3844767%2Ffaccdba7-ad99-4d0a-a1d0-70c04234a705.jpg</url>
      <title>DEV Community: Hiroshi TK</title>
      <link>https://dev.to/hiroshi_takamura_c851fe71</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hiroshi_takamura_c851fe71"/>
    <language>en</language>
    <item>
      <title>Footstep dust in Three.js with a pool of four effects</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Wed, 14 Oct 2026 12:53:44 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/footstep-dust-in-threejs-with-a-pool-of-four-effects-3d21</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/footstep-dust-in-threejs-with-a-pool-of-four-effects-3d21</guid>
      <description>&lt;p&gt;A footstep effect has two separate rates: how often the character asks for a puff, and how many particles each puff emits. Keeping those separate makes it possible to budget a repeated effect without tying it to the display refresh rate.&lt;/p&gt;

&lt;p&gt;This NixieFX tutorial uses an intentionally simple character proxy, a moving box, with a dust request every 15 simulation frames. At a fixed step of 1/60 second, that is four requests per simulated second. Each request restarts one available effect containing a 12-particle burst.&lt;/p&gt;

&lt;h2&gt;
  
  
  The effect contract
&lt;/h2&gt;

&lt;p&gt;The tested scene uses nixie-fx 0.1.20 and Three.js. The emitter uses procedural unlit billboards, world-space simulation, no continuous emission, a burst at time zero, and a particle lifetime of 0.7 seconds. The effect timeline lasts 0.8 seconds; the emitter's emission duration is 0.05 seconds. There are no texture or mesh downloads.&lt;/p&gt;

&lt;p&gt;That short emission duration matters. A pool member is available only after its effect is inactive. Leaving a long emitter duration on a short visual puff can keep the pool occupied after the visible particles have gone away.&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;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;},&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;i&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;vfx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dustDefinition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;autoStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;requests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dropped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onFootstep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="o"&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;puff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pool&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="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isActive&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;puff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dropped&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;puff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTransform&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;puff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;reused&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="c1"&gt;// In this test harness, frame advances at a fixed simulation step.&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;frame&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;onFootstep&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;characterX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;vfx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fragment assumes a constructed renderer and the dust definition described above. In an actual game, trigger on the animation's foot-contact event instead of a frame counter. Update the owning renderer once per simulation step; do not also update its instances individually.&lt;/p&gt;

&lt;p&gt;The position belongs to the contact at emission time. Moving an active puff to follow the character would create a different effect. The test moves only an available member immediately before restarting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the run measured
&lt;/h2&gt;

&lt;p&gt;In one Chrome run on macOS, 180 simulation frames produced 12 requests, 12 pool reuses, zero dropped requests, and four retained effect instances. The final frame contained 24 active particles. The recorded p95 CPU duration around the runtime update was 2.0 ms, while the p95 animation-frame interval was 17.2 ms.&lt;/p&gt;

&lt;p&gt;These are observations from a three-second demonstration with other browser tabs open. They include startup samples and debug-transform capture. They are not GPU measurements, a mobile-device budget, or evidence that pooling is faster than allocating a fresh instance. The useful functional result is narrower: the four-member pool served the requested cadence without allocating another effect instance after setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Saturation is a behavior to choose
&lt;/h2&gt;

&lt;p&gt;This implementation drops a cosmetic puff when the pool is full. That avoids stealing an active instance and visibly cutting off its particles. A different game may choose a larger pool or allow a controlled fallback allocation. Measure the number of dropped requests so the decision is visible.&lt;/p&gt;

&lt;p&gt;Four members are a test parameter, not a universal recommendation. A faster character, multiple characters, longer particle lifetimes, or a slower completion condition can change occupancy. Test those cases separately before selecting the production capacity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits and cleanup
&lt;/h2&gt;

&lt;p&gt;The runtime reported the tested Three.js effect as supported with no warnings or blockers. This example does not implement ground collision, terrain normals, animated character feet, lighting, or mesh particles. Those settings were not validated by this run and should not be inferred from the result. The &lt;a href="https://nixiefx.com/threejs-runtime/" rel="noopener noreferrer"&gt;Three.js runtime documentation&lt;/a&gt; covers integration and backend support checks.&lt;/p&gt;

&lt;p&gt;Remove every retained instance when the owning scene is released, or destroy the renderer if that scene owns it. An inactive effect is still a retained instance. The pool has to be bounded and its lifetime explicit even when nothing is visible.&lt;/p&gt;

</description>
      <category>threejs</category>
      <category>javascript</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Rank the work you can verify, not the tokens you can spend</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Wed, 14 Oct 2026 11:53:31 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/rank-the-work-you-can-verify-not-the-tokens-you-can-spend-1815</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/rank-the-work-you-can-verify-not-the-tokens-you-can-spend-1815</guid>
      <description>&lt;p&gt;The example below is hypothetical and does not report a production result.&lt;/p&gt;

&lt;p&gt;An AI task handoff for teams needs a queue that rewards useful outcomes. Token use measures an input. It cannot tell you whether a migration was necessary, a bug was fixed, or a reviewer can reproduce the result.&lt;/p&gt;

&lt;p&gt;Use four fields before assigning work: impact, risk, readiness, and verification. Keep the last three visible instead of hiding every judgment inside a single priority score.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with gates
&lt;/h2&gt;

&lt;p&gt;Readiness means the runner has the necessary repository access, environment instructions, and a bounded request. Verification means someone can describe the evidence required for acceptance. If either is missing, put the task in preparation. A high-impact request does not become executable because it earned a large number.&lt;/p&gt;

&lt;p&gt;Risk describes the potential cost of a mistake. A public typo correction and a billing migration should not share an approval route. High-risk work needs its specialist and release controls before it enters the ready queue.&lt;/p&gt;

&lt;p&gt;Among ready tasks, rank impact first and use expected review effort as a tie-breaker. This is a starting rubric, not a universal scoring formula:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Low&lt;/th&gt;
&lt;th&gt;Medium&lt;/th&gt;
&lt;th&gt;High&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Impact&lt;/td&gt;
&lt;td&gt;Local convenience&lt;/td&gt;
&lt;td&gt;Repeated team friction&lt;/td&gt;
&lt;td&gt;User-facing failure or blocker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk&lt;/td&gt;
&lt;td&gt;Reversible text change&lt;/td&gt;
&lt;td&gt;Bounded behavior change&lt;/td&gt;
&lt;td&gt;Data, access, or release consequences&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Readiness&lt;/td&gt;
&lt;td&gt;Missing owner or access&lt;/td&gt;
&lt;td&gt;One unresolved dependency&lt;/td&gt;
&lt;td&gt;Scope, access, and environment ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verification&lt;/td&gt;
&lt;td&gt;Subjective request&lt;/td&gt;
&lt;td&gt;Evidence partly specified&lt;/td&gt;
&lt;td&gt;Named checks and reviewer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Copy a task card
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;outcome&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export button stays disabled while an export is running&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export panel and its existing interaction tests&lt;/span&gt;
&lt;span class="na"&gt;excluded&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export API, file format, unrelated styling&lt;/span&gt;
&lt;span class="na"&gt;impact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Repeated duplicate export requests&lt;/span&gt;
&lt;span class="na"&gt;risk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Medium; changes a user interaction&lt;/span&gt;
&lt;span class="na"&gt;prepared_by&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Product engineer&lt;/span&gt;
&lt;span class="na"&gt;runner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Teammate with authorized repository and agent access&lt;/span&gt;
&lt;span class="na"&gt;reviewer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export-panel maintainer&lt;/span&gt;
&lt;span class="na"&gt;acceptance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Second click during an export starts no additional request&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Button becomes available after success or failure&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Keyboard activation follows the same rule&lt;/span&gt;
&lt;span class="na"&gt;evidence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Focused diff&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Reproduction steps and observed outcomes&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Test commands, results, and any skipped checks&lt;/span&gt;
&lt;span class="na"&gt;stop_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Fix requires changing the export API contract&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The author prepares the card and checks that the requested behavior is actually desired. The runner executes it with their own authorized tools and access. The maintainer judges the evidence. A deployment owner decides whether and when the accepted change ships. These can be overlapping people on a small team, but the decisions should still be explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Work one handoff
&lt;/h2&gt;

&lt;p&gt;Imagine three requests: polish a tooltip, prevent duplicate exports, and redesign the export API. The tooltip is ready and low risk but has limited impact. The duplicate-request fix has a clear failure and a bounded test. The API redesign has an important goal but no compatibility decision.&lt;/p&gt;

&lt;p&gt;Prepare the redesign before assigning it. Put the bounded fix first among ready work. Keep the tooltip available for a smaller work window. Nothing in that ordering depends on which request consumes the most tokens.&lt;/p&gt;

&lt;p&gt;If the runner discovers that the duplicate originates in the server rather than the panel, they should stop and return the evidence. That is useful progress even without a patch. Rewarding only merged changes would push them toward a superficial client-side fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review the outcome and the rubric
&lt;/h2&gt;

&lt;p&gt;A reviewer should be able to repeat the relevant checks without reconstructing a long agent conversation. Record a verdict, the evidence used, and any remaining limits. Do not turn a passing test into a claim that every export path is safe.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://wagglet.com/blog/gamification-ai-work-bounties-rewards" rel="noopener noreferrer"&gt;Wagglet discussion of bounties and rewards&lt;/a&gt; is a useful context for designing incentives around accepted work. This template is an independent example, not a description of an automatic scoring feature.&lt;/p&gt;

&lt;p&gt;Try the rubric on a small queue. If apparently ready tasks repeatedly need clarification, improve preparation. If review dominates the work, tighten scope. Treat those observations as workflow feedback, not a ranking of people's value.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>A localization handoff that design, QA, and engineering can all use</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Tue, 13 Oct 2026 07:49:24 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/a-localization-handoff-that-design-qa-and-engineering-can-all-use-5fj5</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/a-localization-handoff-that-design-qa-and-engineering-can-all-use-5fj5</guid>
      <description>&lt;p&gt;AI disclosure: This tutorial was generated with AI. The reward dialog is a hypothetical example; no production screenshot or test result is claimed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Describe the failure at the string level
&lt;/h2&gt;

&lt;p&gt;A localization issue often arrives as “German breaks the popup.” That report mixes several decisions: whether the translation is correct, whether the layout can accommodate it, and whether the right resource reaches the UI. Give each decision an owner before requesting a fix.&lt;/p&gt;

&lt;p&gt;Use a small example: a reward dialog has a button with the English source string “Claim reward.” In the German locale, the approved translation is longer than the available space at the smallest supported viewport. The designer owns the layout rule, a locale reviewer owns the language, and engineering owns how the component applies both.&lt;/p&gt;

&lt;p&gt;Do not shorten the translation solely to fit an arbitrary character count. Characters have different widths, and a short phrase can still be semantically wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a task from this template
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fix reward-dialog action-label clipping&lt;/span&gt;
&lt;span class="na"&gt;string_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rewards.claim_cta&lt;/span&gt;
&lt;span class="na"&gt;source_locale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;en&lt;/span&gt;
&lt;span class="na"&gt;source_string&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Claim reward&lt;/span&gt;
&lt;span class="na"&gt;target_locale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;de&lt;/span&gt;
&lt;span class="na"&gt;target_string&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;use the locale reviewer's approved resource value&lt;/span&gt;
&lt;span class="na"&gt;screen&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;daily reward confirmation dialog&lt;/span&gt;
&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reward available; no network request in progress&lt;/span&gt;
&lt;span class="na"&gt;viewport&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;smallest supported mobile viewport, exact dimensions required&lt;/span&gt;
&lt;span class="na"&gt;font&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;record actual family, weight, size and fallback behavior&lt;/span&gt;
&lt;span class="na"&gt;context_screenshot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;before&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;attach a real capture showing the whole dialog and clipped label&lt;/span&gt;
  &lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;capture the same viewport, locale, state and build configuration&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;this dialog's action-label layout&lt;/span&gt;
&lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;translation rewrites, reward logic, global typography changes&lt;/span&gt;
&lt;span class="na"&gt;preparer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;QA with design&lt;/span&gt;
&lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UI engineer using their own authorized development tools&lt;/span&gt;
&lt;span class="na"&gt;reviewers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;locale reviewer&lt;/span&gt;
  &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;designer&lt;/span&gt;
  &lt;span class="na"&gt;acceptance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;QA lead&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The screenshot entries are evidence requirements, not links to nonexistent images. Before using this as a real ticket, attach a capture from the affected build and record its revision. Crop out private account information, but retain enough surrounding UI to explain what the button does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Work the handoff in three decisions
&lt;/h2&gt;

&lt;p&gt;First, QA reproduces the clipping and records the locale, device scale, viewport, and loaded font. A fallback font can change the result, so a screenshot without font context is insufficient. QA also checks whether the defect appears before or after the translation resources finish loading.&lt;/p&gt;

&lt;p&gt;Second, design specifies an acceptable layout behavior. For example, permit the action region to grow vertically while preserving the existing minimum touch target and the approved gap to the secondary action. This is an example decision, not a universal prescription. If the product requires a single-line button, design must instead define an approved width strategy or language-review escalation.&lt;/p&gt;

&lt;p&gt;Third, the engineer changes only the relevant component and returns the diff with comparable before/after captures. If the implementation discovers a shared component issue, expand the scope explicitly before changing every dialog in the game.&lt;/p&gt;

&lt;p&gt;An assistant can help find uses of the string key, draft a test matrix, or propose a constrained component change. That is expert supervised AI execution when the human owners provide the context and review the evidence. &lt;a href="https://wagglet.com/blog/ai-native-mobile-game-studio-stack" rel="noopener noreferrer"&gt;Wagglet's studio-stack discussion&lt;/a&gt; provides a related framework for coordinating those roles. It does not make an AI-generated translation an approved resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify content and layout separately
&lt;/h2&gt;

&lt;p&gt;Use this acceptance checklist for the example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The exact approved target string renders without clipping or ellipsis.&lt;/li&gt;
&lt;li&gt;The label remains inside the action area at each supported narrow viewport.&lt;/li&gt;
&lt;li&gt;The button still performs the same reward action exactly once.&lt;/li&gt;
&lt;li&gt;English remains readable and the secondary action remains reachable.&lt;/li&gt;
&lt;li&gt;The locale reviewer approves meaning and tone independently of layout.&lt;/li&gt;
&lt;li&gt;QA captures the final state using the same setup as the original report.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add an automated layout assertion if the application exposes suitable bounds. Check the rendered text against its actual containing region after fonts and translations are ready. A character-count check cannot establish that the text fits. For a canvas UI, use the engine's text and container bounds and retain a visual capture; DOM text measurements may not represent the canvas renderer.&lt;/p&gt;

&lt;p&gt;The engineer should record what ran, what failed, and what was not checked. “All locales fixed” is too broad if only English and German were exercised.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the limits visible
&lt;/h2&gt;

&lt;p&gt;Pseudo-localization helps expose constrained layouts, but it does not certify grammar, right-to-left behavior, or cultural suitability. This example does not supply a real failing build or screenshot. Treat it as a reusable handoff recipe and replace the evidence fields when applying it to your game.&lt;/p&gt;

&lt;p&gt;The final acceptance decision belongs to the named reviewers. A clean diff and a plausible screenshot are inputs to that decision, not substitutes for it.&lt;/p&gt;

</description>
      <category>design</category>
      <category>frontend</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Budget waterfall mist with particle lifetime before adding density</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Tue, 13 Oct 2026 06:52:00 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/budget-waterfall-mist-with-particle-lifetime-before-adding-density-43n</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/budget-waterfall-mist-with-particle-lifetime-before-adding-density-43n</guid>
      <description>&lt;p&gt;Waterfall mist can consume a surprising amount of a scene's visual budget because it is usually continuous. A burst ends; an ambient emitter remains active while the player explores. The useful first question is how many particles the effect keeps alive, not how dense it looks in the editor.&lt;/p&gt;

&lt;p&gt;This NixieFX tutorial uses a small Three.js fixture: a rectangular waterfall prop, a soft emitter at its base, and a visible runtime readout. The prop is ordinary host geometry. The mist is a NixieFX 0.1.20 billboard effect rendered with Three.js r185.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set the population before tuning the appearance
&lt;/h2&gt;

&lt;p&gt;The emitter creates 24 particles per second, with a lifetime of three seconds and a capacity of 96. Ignoring boundary timing, the expected steady population is approximately 24 × 3 = 72 particles. Capacity is a hard ceiling, not a promise that all 96 particles are always present.&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;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxParticles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;96&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rateValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeParticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lifetime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;box&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;box&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;1.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code uses &lt;code&gt;createConstantParticleScalar&lt;/code&gt; as &lt;code&gt;constant&lt;/code&gt;. The complete source initializes the remaining fields from &lt;code&gt;createDefaultParticleEffect&lt;/code&gt;, enables a fade over lifetime, and gives each particle a small upward velocity. Depth testing stays enabled and depth writing stays disabled for the translucent billboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Place the effect relative to a readable prop
&lt;/h2&gt;

&lt;p&gt;Place the effect at &lt;code&gt;[0, 0.2, 0]&lt;/code&gt;. The demonstration waterfall sits behind it and supplies a stable scale reference. The scene is deliberately plain: mist density should be readable without a complex material, lighting rig, or postprocessing chain.&lt;/p&gt;

&lt;p&gt;A dark background makes soft particle overlap visible. It can also make an additive effect seem more impressive than it will appear in a bright level, so this fixture uses alpha blending. Test against the actual level colors before treating its appearance as final.&lt;/p&gt;

&lt;p&gt;The emitter does not collide with the waterfall or surrounding terrain. It does not simulate water volume, spray breakup, or moisture. It is a visual layer placed near a prop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep simulation accounting separate from rendering accounting
&lt;/h2&gt;

&lt;p&gt;Advance the runtime once per fixed simulation step, then render the scene. Do not advance an instance separately when its renderer already owns the update.&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;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accumulator&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vfx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;accumulator&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fixture caps the elapsed time added after a long frame. That prevents a large catch-up burst when a tab resumes, but it also means the demo is not a wall-clock simulation under stalls. Its fixed-step sequence is useful for comparisons.&lt;/p&gt;

&lt;p&gt;The readout reports active particles, visible particles, capacity, instanced draw calls, and legacy particle draw calls. These are different quantities. A particle whose alpha is zero at birth may exist in the simulation while contributing nothing visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the observed result carefully
&lt;/h2&gt;

&lt;p&gt;At a recorded simulation time of 60 seconds, the fixture showed 73 active particles, 72 visible particles, capacity 96, and one instanced draw call. The peak active count was 73. The extra particle around the simple 72-particle estimate reflects spawn and lifetime boundaries in the stepped simulation; it is not evidence that the capacity limit failed.&lt;/p&gt;

&lt;p&gt;The runtime's support report was &lt;code&gt;supported&lt;/code&gt;, and its unsupported-feature list was empty for this definition. A separate repeatability check compared two 90-step runs with seed 2444 and found identical particle debug transforms.&lt;/p&gt;

&lt;p&gt;This is not a performance benchmark. A single emitter does not reproduce a full level's overdraw, resolution, effects, or device limits. The particle counter is a useful diagnostic, but it cannot replace a frame capture on the target hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Change one budget variable at a time
&lt;/h2&gt;

&lt;p&gt;First hold lifetime at three seconds and adjust the emission rate. Then restore the rate and adjust lifetime. Finally, test billboard size, because larger translucent quads can increase overdraw even when the particle count stays constant.&lt;/p&gt;

&lt;p&gt;Keep the same camera and seed during each comparison. If you add a flipbook, material graph, or other feature, inspect the rendering path again instead of assuming the original draw-call result still applies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nixiefx.com/threejs-runtime/" rel="noopener noreferrer"&gt;The NixieFX Three.js runtime guide&lt;/a&gt; documents the counters and integration controls used here. A useful ambient effect is one whose visual contribution and resource cost can both be explained.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>javascript</category>
      <category>performance</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A task record is not an execution contract: a handoff template for coding agents</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Mon, 12 Oct 2026 07:57:20 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/a-task-record-is-not-an-execution-contract-a-handoff-template-for-coding-agents-4bp8</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/a-task-record-is-not-an-execution-contract-a-handoff-template-for-coding-agents-4bp8</guid>
      <description>&lt;p&gt;Disclosure: This draft was generated with AI assistance. The worked example is illustrative and has not been run against a production repository.&lt;/p&gt;

&lt;p&gt;A ticket can accurately describe a bug while leaving the executor unable to start. “CSV export loses filters” tells us what hurts. It does not identify the repository revision, the supported command, the intended output, or the person who can accept the change.&lt;/p&gt;

&lt;p&gt;When comparing task tracking with managed agent execution, compare responsibilities rather than labels. A task tracker can be part of a well-managed execution system. An agent runner can also be poorly managed. The difference is whether the handoff specifies the following four things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compare context, runner, evidence, and acceptance
&lt;/h2&gt;

&lt;p&gt;Context: Can the executor find the exact starting revision, relevant behavior, constraints, and allowed files? A long conversation is not a substitute for a small, current specification.&lt;/p&gt;

&lt;p&gt;Runner: Is there an authorized operator and a known environment? Naming an agent is insufficient if nobody has installed the dependencies or can grant the necessary repository access.&lt;/p&gt;

&lt;p&gt;Evidence: Does delivery identify the patch, actual commands run, results, and untested cases? “Done” is a state label, not a verification record.&lt;/p&gt;

&lt;p&gt;Acceptance: Is a person responsible for deciding whether the result satisfies the requirement? The executor should not silently replace the requested behavior with an easier interpretation.&lt;/p&gt;

&lt;p&gt;These criteria are useful when evaluating project management for coding agents because they apply before a particular tool enters the picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the execution contract
&lt;/h2&gt;

&lt;p&gt;Here is an original template for an illustrative CSV repair. Values in angle brackets must come from the actual project. Command names are deliberately not invented.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Preserve the selected filters in CSV export&lt;/span&gt;
&lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;authorized repository&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;base_revision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;verified commit&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;reproduction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Select status=open, then export CSV&lt;/span&gt;
  &lt;span class="na"&gt;expected&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export contains exactly the rows matching the filter&lt;/span&gt;
  &lt;span class="na"&gt;fixtures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;sanitized fixture path&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allowed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export query and focused regression coverage&lt;/span&gt;
  &lt;span class="na"&gt;excluded&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Authentication, schema migrations, unrelated UI changes&lt;/span&gt;
&lt;span class="na"&gt;execution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;developer or authorized agent operator&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;setup_command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;verified command from this repository&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;test_command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;verified command from this repository&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Existing authorized development access only&lt;/span&gt;
&lt;span class="na"&gt;delivery&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;patch_revision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
  &lt;span class="na"&gt;commands_and_results&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
  &lt;span class="na"&gt;sample_output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sanitized CSV from the fixture&lt;/span&gt;
  &lt;span class="na"&gt;untested_cases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required, even when empty&lt;/span&gt;
&lt;span class="na"&gt;acceptance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;product_owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Confirms filtering semantics&lt;/span&gt;
  &lt;span class="na"&gt;engineer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Reviews implementation and regression evidence&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not paste credentials into that contract. The person executing the task uses their own authorized tools and access. If the environment is unavailable, that is an execution blocker to resolve, not an invitation to share an account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walk one handoff through the template
&lt;/h2&gt;

&lt;p&gt;The product owner prepares a fixture containing three records: two open and one closed. The expected filtered export contains the two open records. An engineer confirms the expected behavior and identifies the relevant export path.&lt;/p&gt;

&lt;p&gt;The executor first reproduces the failure at the recorded revision. If it does not reproduce, the next useful delivery is the attempted command, environment details, and observed output. Editing code before resolving that mismatch risks fixing a different problem.&lt;/p&gt;

&lt;p&gt;After reproducing the issue, the executor implements a scoped change and adds coverage for the filtered export. The normal unfiltered export is also checked, because repairing one path can narrow the other accidentally. Those are proposed checks; no passing results are claimed here.&lt;/p&gt;

&lt;p&gt;The delivery attaches the patch revision and actual output from the verified test command. The engineer reviews the change. The product owner inspects the sanitized sample and confirms that the selected filters mean what users expect. If either review fails, the same task records the reason and the next attempt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the tool comparison honest
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://wagglet.com/for/engineering-teams" rel="noopener noreferrer"&gt;Wagglet's engineering-team page&lt;/a&gt; is the assigned product reference for this workflow. The template above is a proposed operating practice, not evidence that any particular platform supplies every field, runner, or verification step automatically.&lt;/p&gt;

&lt;p&gt;A task tracker may already be sufficient if the team supplies the missing execution contract through its development process. A managed execution tool may reduce coordination work, but it still cannot decide an ambiguous product requirement without an acceptance owner.&lt;/p&gt;

&lt;p&gt;The useful comparison is therefore concrete: take one real repair and ask where its context, execution authority, proof, and decision live. Any blank answer identifies work the team still has to do.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>startup</category>
      <category>programming</category>
    </item>
    <item>
      <title>Hand off the feature-flag implementation without handing off the release decision</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Fri, 09 Oct 2026 08:46:50 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/hand-off-the-feature-flag-implementation-without-handing-off-the-release-decision-3cge</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/hand-off-the-feature-flag-implementation-without-handing-off-the-release-decision-3cge</guid>
      <description>&lt;p&gt;The scenario and rollout values below are illustrative, not results from a production release.&lt;/p&gt;

&lt;p&gt;A feature flag separates deployment from exposure only if the handoff preserves that distinction. “Implement the new checkout behind a flag” leaves several decisions open: who may deploy the code, who may change the flag, and what evidence is needed before more users see it?&lt;/p&gt;

&lt;p&gt;Write those boundaries before assigning the implementation. A developer can prepare a change and return evidence. The release owner still needs a clear decision point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the flag off
&lt;/h2&gt;

&lt;p&gt;Consider a hypothetical checkout summary that recalculates shipping after a user changes an address. The task is to implement the new summary behind &lt;code&gt;checkout_summary_v2&lt;/code&gt;, with the existing behavior retained when the flag is off.&lt;/p&gt;

&lt;p&gt;The product owner defines the expected user behavior. An engineer prepares the repository context, tests, and constraints. The runner executes with their own authorized tools and environment. A reviewer judges the implementation, and the release owner authorizes deployment and exposure changes separately.&lt;/p&gt;

&lt;p&gt;Neither access to a flag dashboard nor a passing test implies permission to enable production traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use a brief with separate exit conditions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature: checkout_summary_v2
Default: off

Implementation scope:
- Add the alternate summary path behind the flag.
- Preserve the existing path when disabled.
- Do not change payment authorization or order persistence.

Required checks:
- Flag off: existing address-change behavior remains intact.
- Flag on: displayed totals match the approved calculation fixture.
- Flag changes: no duplicate charge or duplicate order request.
- Missing flag configuration: retain the approved safe default.

Delivery package:
Revision, changed files, exact test commands and outputs,
screenshots from the same fixture, known limits.

Implementation acceptance: [named engineering reviewer]
Product acceptance: [named product owner]
Production deployment: [named release owner]
Exposure changes: [named flag owner]

Stop boundary:
Return the reviewed change. Do not deploy or enable production traffic.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a task template, not a record of completed checks. Replace the placeholders with real owners and attach actual evidence before acceptance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the staged rollout a separate decision
&lt;/h2&gt;

&lt;p&gt;An illustrative rollout could progress from internal users to 1%, then 10%, then broader exposure. Those percentages are planning examples, not universal recommendations. The release owner must define observation windows, relevant metrics, and rollback thresholds for the actual service.&lt;/p&gt;

&lt;p&gt;Require explicit approval at each stage. A quiet dashboard over a short interval may simply mean that too few users exercised the feature. Include a minimum useful sample or a representative manual check instead of assuming that elapsed time proves safety.&lt;/p&gt;

&lt;p&gt;For the checkout example, inspect calculation mismatches and failed completion attempts. Also check whether the old path still works when the flag is disabled. Document who may halt the rollout and where that decision is recorded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make rollback a behavior, not a slogan
&lt;/h2&gt;

&lt;p&gt;Turning a flag off is only a rollback if the old path can still operate with the state produced by the new one. If a migration or irreversible side effect has occurred, disabling exposure may not restore the previous behavior.&lt;/p&gt;

&lt;p&gt;The example deliberately excludes payment and persistence changes to keep the task narrow. If implementation discovers that either must change, stop and revise the brief. Do not stretch a UI task into a transaction-system change without a new review.&lt;/p&gt;

&lt;p&gt;A useful rollback rehearsal records the starting state, the disabling action, and the resulting user behavior. An unexecuted runbook is still a plan, even if the commands look correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the delivery and the approval connected
&lt;/h2&gt;

&lt;p&gt;Teams that manage work in one system need to preserve the difference between “a runner returned a change” and “the accountable owner accepted it.” &lt;a href="https://wagglet.com/blog/wagglet-workflow-request-draft-ticket-delivery" rel="noopener noreferrer"&gt;Wagglet’s request-to-delivery workflow&lt;/a&gt; describes that separation; this brief makes the responsibilities explicit regardless of the tracking tool.&lt;/p&gt;

&lt;p&gt;The reviewer should be able to identify the accepted revision, the evidence supporting it, and any unresolved limitation. The release owner should see the same information before approving exposure. If new evidence invalidates the decision, the task history should explain why the rollout stopped.&lt;/p&gt;

&lt;p&gt;The flag’s default, the delivery’s acceptance, and the release’s approval are three different facts. Write each one down, assign each decision to a person, and let the implementation handoff end at the boundary you actually authorized.&lt;/p&gt;

</description>
      <category>management</category>
      <category>product</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>NixieFX tutorial: trigger a PixiJS combo flare only when the meter crosses its threshold</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Thu, 08 Oct 2026 10:02:27 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/nixiefx-tutorial-trigger-a-pixijs-combo-flare-only-when-the-meter-crosses-its-threshold-29ik</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/nixiefx-tutorial-trigger-a-pixijs-combo-flare-only-when-the-meter-crosses-its-threshold-29ik</guid>
      <description>&lt;p&gt;A combo-meter flare should mark the moment a player earns a new state. If it runs on every update while the meter is full, the signal becomes background noise and repeated effects can overlap unnecessarily.&lt;/p&gt;

&lt;p&gt;This NixieFX tutorial separates two responsibilities: plain JavaScript decides when the threshold is crossed, and the PixiJS scene renders a short effect. Reduced-motion mode keeps a persistent “Combo ready” message while omitting the decorative burst.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the trigger before authoring the effect
&lt;/h2&gt;

&lt;p&gt;For this example, the threshold is 100. Moving from 99 to 100 should trigger once. Moving from 100 to 105 should not trigger again. Dropping below 100 rearms the cue. These are proposed gameplay rules; change them if your meter uses a different reward model.&lt;/p&gt;

&lt;p&gt;Keep the rule independent of the renderer so it can be checked without a canvas:&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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createThresholdGate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="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="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initial&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;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Use finite meter values&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;let&lt;/span&gt; &lt;span class="nx"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;initial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="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="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&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="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid meter value&lt;/span&gt;&lt;span class="dl"&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;crossed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;next&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;crossed&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;Initializing the gate at an already-full value deliberately does not play an entrance flare. A saved game opening with a full meter should still display the ready state. Treat “ready on load” and “became ready during play” as separate events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Author a short, readable flare
&lt;/h2&gt;

&lt;p&gt;Create a Pixi-oriented effect named “Combo Flare” in a local NixieFX project. Start with one unlit billboard emitter, a single burst of 12 particles, no continuous emission, and a lifetime of 0.35 seconds. Use a soft texture, modest outward movement, and an alpha fade to zero. These values are design starting points, not measured performance recommendations.&lt;/p&gt;

&lt;p&gt;Place the origin beside the meter rather than over the number. Preview against the actual HUD background and reduce the burst if it obscures useful information. Keep prepared 3D meshes, mesh-surface emission, lit shading, and GPU-depth-dependent behavior out of this Pixi recipe.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nixiefx.com/pixijs-particle-effects/" rel="noopener noreferrer"&gt;The NixieFX PixiJS integration guide&lt;/a&gt; covers exporting the effect and loading it into the Pixi adapter. Follow that setup first, then use the event wiring below in the initialized scene. Confirm that the exported effect ID is &lt;code&gt;combo-flare&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect the gate to the existing scene
&lt;/h2&gt;

&lt;p&gt;The following integration fragment assumes &lt;code&gt;app&lt;/code&gt;, &lt;code&gt;vfx&lt;/code&gt;, and the validated &lt;code&gt;bundle&lt;/code&gt; already exist. It also assumes a real HTML status element named &lt;code&gt;combo-status&lt;/code&gt; beside the canvas. The &lt;a href="https://valentina-mkrtu.github.io/demos/nixie-runtime-lab.html" rel="noopener noreferrer"&gt;runnable lab and embedded source&lt;/a&gt; supply a complete isolated fixture. Configure PixiVfxRenderer with createPixiVfx2dProjection({ yAxis: "down" }) when passing screen coordinates, and rotate the circle emitter 90 degrees around X into the XY plane.&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;crossedThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createThresholdGate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#combo-status&lt;/span&gt;&lt;span class="dl"&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;motion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchMedia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(prefers-reduced-motion: reduce)&lt;/span&gt;&lt;span class="dl"&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;definition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;effectsById&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;combo-flare&lt;/span&gt;&lt;span class="dl"&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;status&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;definition&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;Missing status or effect&lt;/span&gt;&lt;span class="dl"&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;live&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setCombo&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="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&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;crossed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;crossedThreshold&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&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;nextReady&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nextReady&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ready&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Combo ready&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Combo charging&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;crossed&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;live&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vfx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;definition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;clearFlares&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &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;fx&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;live&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;vfx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;live&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onMotionChange&lt;/span&gt;&lt;span class="p"&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;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;clearFlares&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onMotionChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Use this as this scene's single VFX update path.&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ticker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vfx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ticker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deltaMS&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for &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;fx&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;live&lt;/span&gt;&lt;span class="p"&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;fx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;vfx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;live&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fx&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ticker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;disposeComboCue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ticker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tick&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onMotionChange&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;clearFlares&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;Use coordinates in the VFX parent’s local space. If the meter belongs to a scaled or translated container, convert its position before calling &lt;code&gt;setCombo&lt;/code&gt;. Do not add a second VFX update loop if the scene already owns one. Initialize the HTML status as “Combo charging” and use &lt;code&gt;role="status"&lt;/code&gt;; update it on state changes rather than every frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproduce the important cases
&lt;/h2&gt;

&lt;p&gt;Feed the sequence 0, 99, 100, 105, 80, 100 into the gate. The expected crossing count is two. Repeat with reduced motion enabled: the threshold logic is unchanged, but no decorative flare should be created. Toggle reduced motion while a flare is active and confirm it clears.&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%2Fexp2d4t9qg6zbxqxv1ss.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%2Fexp2d4t9qg6zbxqxv1ss.png" alt="PixiJS combo meter at 100 with the ready message and a small flare beside the meter, frozen at 0.10 seconds." width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also check repeated values, an initial value above the threshold, a scene exit, and missing assets. The gate does not prevent legitimate rapid recrossings; add a game-specific cooldown or hysteresis only if that matches the intended rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observed runtime result
&lt;/h2&gt;

&lt;p&gt;The fixture uses NixieFX 0.1.17 and PixiJS 8.22.0. The sequence produced two threshold events, two created effect instances, and zero remaining instances after completion. Reduced motion preserved two threshold events while creating zero instances. At the frozen 0.10-second capture, the renderer reported twelve active particles. The export validated for pixi2d and three3d with no errors. These are functional observations from an isolated fixture, not a performance benchmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;p&gt;The JavaScript gate can be verified independently. Visual quality, exported-effect compatibility, and device performance require the real PixiJS build. Reduced motion is implemented by the host application here; it is not an automatic property of the authored effect. Do not infer a frame-rate guarantee from the small particle count.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>gamedev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Validate the review packet before you review the patch</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Wed, 07 Oct 2026 10:25:20 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/validate-the-review-packet-before-you-review-the-patch-40jp</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/validate-the-review-packet-before-you-review-the-patch-40jp</guid>
      <description>&lt;p&gt;A green build can arrive with evidence for the wrong commit. A detailed delivery can leave the security reviewer unnamed. Neither problem requires reading every line of the patch to detect.&lt;/p&gt;

&lt;p&gt;This tutorial builds a small evidence gate for a fictional search-filter change. The gate checks that a review packet is ready for human inspection. It deliberately does not decide whether the code is correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate implementation from acceptance
&lt;/h2&gt;

&lt;p&gt;The task author prepares the outcome, fixture, scope, and acceptance criteria. The runner implements the change using their own authorized tools. A qualified reviewer judges the technical evidence, and the authorized task reviewer records the final decision.&lt;/p&gt;

&lt;p&gt;If your requirement is “delegate AI task without sharing account,” place repository access and tool authorization in the runner’s setup checklist. The task should carry context and expected results, not somebody else’s login or provider token.&lt;/p&gt;

&lt;p&gt;In this example, a search field should trim surrounding whitespace without changing authorization, query scope, or result ranking. If the implementation reaches those areas, the runner stops for technical review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the evidence packet
&lt;/h2&gt;

&lt;p&gt;Use actual revision identifiers and attach the full output of the checks you run. The values below are fictional placeholders illustrating the shape, not successful test results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"candidate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"REPLACE_WITH_COMMIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"runner"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"runner-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reviewer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"qualified-reviewer-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"criterion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search-trims-whitespace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"revision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"REPLACE_WITH_COMMIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"not-run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"evidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"criterion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"empty-search-keeps-existing-behavior"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"revision"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"REPLACE_WITH_COMMIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"not-run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"evidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"escalations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save that as &lt;code&gt;review-packet.json&lt;/code&gt;. A task-specific required list matters: otherwise an empty or conveniently shortened checklist can pass a generic gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check completeness with a small script
&lt;/h2&gt;

&lt;p&gt;Save this as &lt;code&gt;check-review-packet.mjs&lt;/code&gt; and run &lt;code&gt;node check-review-packet.mjs review-packet.json&lt;/code&gt; with a current Node.js release.&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;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node:fs&lt;/span&gt;&lt;span class="dl"&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;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search-trims-whitespace&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;empty-search-keeps-existing-behavior&lt;/span&gt;&lt;span class="dl"&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;problems&lt;/span&gt; &lt;span class="o"&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;hasText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&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;catch&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;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;Provide a readable JSON review packet.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="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;p&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&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;p&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;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;The packet 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="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="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="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-f0-9&lt;/span&gt;&lt;span class="se"&gt;]{40}&lt;/span&gt;&lt;span class="sr"&gt;$/i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;??&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="nx"&gt;problems&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Use the full candidate commit SHA.&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;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;hasText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;hasText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reviewer&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;problems&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name the runner and qualified reviewer.&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;else&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;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reviewer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;problems&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This task requires an independent reviewer.&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;checks&lt;/span&gt; &lt;span class="o"&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;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checks&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="k"&gt;for &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;criterion&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;required&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;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;criterion&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;criterion&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;matches&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;problems&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;criterion&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: expected exactly one record.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;continue&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;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;revision&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pass&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;hasText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;problems&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;criterion&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: missing current passing evidence.`&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;escalations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;escalations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;problems&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Resolve and document escalations before review.&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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;Packet complete. Human review is still required.&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Work through a handoff
&lt;/h2&gt;

&lt;p&gt;The author records the existing empty-search behavior before work starts. The runner changes the input normalization and gathers evidence for the two named criteria. They record the candidate commit once the implementation is stable.&lt;/p&gt;

&lt;p&gt;Now imagine a follow-up edit changes that commit after the tests run. The packet gate rejects check records carrying the previous revision. The runner either reruns the relevant checks or obtains a documented review decision about which evidence remains applicable; they do not simply relabel old output as new evidence.&lt;/p&gt;

&lt;p&gt;If the runner discovers that trimming is happening inside an authorization-sensitive query builder, they add an escalation describing the affected path. The qualified engineer decides whether the proposed scope is still appropriate. A founder can understand that blocked state without personally certifying the query implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand what the gate cannot prove
&lt;/h2&gt;

&lt;p&gt;The script accepts text supplied by people. It cannot verify that a named reviewer is qualified, that an evidence link is accessible, that a command really ran, or that the chosen tests are sufficient. It does not inspect Git or enforce identity. Use it as a completeness check before review, never as a replacement for review.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://wagglet.com/blog/meaningful-work-with-human-ai-pairs" rel="noopener noreferrer"&gt;Wagglet’s human–AI pairing article&lt;/a&gt; discusses why a useful human role includes judgment and a clear route to expertise. The same principle applies here: automate the missing-field check, then leave the consequential decision with somebody who can assess the result.&lt;/p&gt;

&lt;p&gt;The final review note should name the candidate revision, explain the verdict, and retain unresolved limits. “Packet complete” means the reviewer has something coherent to inspect. It does not mean the patch is accepted, merged, or ready to deploy.&lt;/p&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>Put a compatibility gate between your particle export and your game</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Tue, 06 Oct 2026 10:05:32 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/put-a-compatibility-gate-between-your-particle-export-and-your-game-p95</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/put-a-compatibility-gate-between-your-particle-export-and-your-game-p95</guid>
      <description>&lt;p&gt;This article was prepared with AI assistance. The code below is an original application-side check. The helper was checked with synthetic inputs; the cross-backend rendering steps below are a proposed integration procedure, not a completed visual benchmark.&lt;/p&gt;

&lt;p&gt;A particle effect can look right in an editor and still be the wrong export for a game scene. The practical question is not whether the editor supports a setting somewhere. It is whether the selected runtime can represent the effect the team is shipping.&lt;/p&gt;

&lt;p&gt;This tutorial adds a small compatibility gate to a proposed PixiJS and Three.js comparison. The purpose is to make unsupported behavior visible before someone evaluates the screenshots.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose one effect and a narrow comparison
&lt;/h2&gt;

&lt;p&gt;Create an original short burst with a simple unlit particle appearance. Use a portable target, disable looping, and avoid imported meshes for the first comparison. Keep the same authored source and random seed for both hosts.&lt;/p&gt;

&lt;p&gt;The comparison should answer three separate questions: does the export declare support, does each host load the required files, and does the effect look acceptable in the intended scene? Passing the first check does not answer the other two.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://nixiefx.com/vfx-runtime-docs/" rel="noopener noreferrer"&gt;NixieFX runtime documentation&lt;/a&gt; describes the export and renderer boundaries for this 2D and 3D particle editor. PixiJS and Three.js should not be treated as visually interchangeable: PixiJS lacks mesh-surface emission and lit shading, and editor preview bloom is not exported.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make a strict review policy explicit
&lt;/h2&gt;

&lt;p&gt;The helper below consumes the documented per-backend status fields. Its deliberately strict policy accepts only an explicit supported status. A partial report may be usable after a human reviews its approximations, but this particular comparison should stop there until that decision is recorded.&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;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;inspectTargets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;compiledEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt;&lt;span class="p"&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="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;targets&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="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;Choose at least one target&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;reports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;compiledEffect&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;support&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;backends&lt;/span&gt; &lt;span class="o"&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;targets&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;target&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;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reports&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;]?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;missing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;supported&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;support&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;backends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;pixi2d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;partial&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;three3d&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;supported&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="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;table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;inspectTargets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pixi2d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;three3d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sample is synthetic. It demonstrates the helper's decision and makes no claim about an actual exported effect. Local checks confirmed that a partial report is rejected, a supported report is allowed, a missing report is rejected, and an empty target list throws. These checks exercise the helper only, not particle rendering. Do not manufacture a report object in the real integration: read it from the compiled export and retain the original warnings for review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation steps for a reproducible render
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Record the installed NixieFX and renderer versions in the project lockfile. Keep the authored effect in source control.&lt;/li&gt;
&lt;li&gt;Validate and export that project. Save the generated manifest, compiled effect, referenced assets, and diagnostics together.&lt;/li&gt;
&lt;li&gt;Run the helper on the compiled effect with pixi2d and three3d as the target list. Stop if either result is missing, partial, or blocked under this tutorial's strict policy.&lt;/li&gt;
&lt;li&gt;Build one minimal PixiJS host and one minimal Three.js host using the installed package's integration examples. Load the export through the official bundle loader; the helper does not replace its validation.&lt;/li&gt;
&lt;li&gt;Use the same fixed seed. Choose a documented scene scale for each host and a fixed camera for Three.js. Advance each renderer once per host frame using elapsed seconds.&lt;/li&gt;
&lt;li&gt;Capture the burst at a recorded simulation time, then let it finish. Remove finished instances and destroy the owning renderer on scene teardown.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a UI burst, the PixiJS host can place the effect beside a stationary marker. The Three.js host can place it at a stationary world point. Those are different coordinate spaces; equal numeric positions do not establish an equivalent composition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Record evidence without claiming parity
&lt;/h2&gt;

&lt;p&gt;The review record should include the source revision, package versions, export status, seed, scene scale, camera, capture time, and cleanup observation. Keep loading failures in the record rather than replacing them with an editor screenshot.&lt;/p&gt;

&lt;p&gt;When implementing the comparison, capture one frame from each actual runtime at the same recorded simulation time. Label each capture with the backend, viewport, seed, and export revision. No cross-backend runtime captures are presented here.&lt;/p&gt;

&lt;p&gt;The expected reproducible result is a compatibility decision followed by two independently inspected renders. The images need not be pixel-identical. Different cameras, scaling, material representation, and scene composition can change their appearance even when the shared effect data is valid.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this gate does not prove
&lt;/h2&gt;

&lt;p&gt;The helper does not parse assets, benchmark rendering, validate the complete export schema, or inspect visual quality. It only makes a team's acceptance policy for backend status explicit. Keep the official loader, actual screenshots, and human review in the workflow.&lt;/p&gt;

&lt;p&gt;The useful failure is an early, readable stop: this effect needs a compatibility decision before it becomes a runtime claim in a tutorial or a shipped scene.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Resume an abandoned agent patch with a failing test, not a fresh prompt</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Mon, 05 Oct 2026 07:48:34 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/resume-an-abandoned-agent-patch-with-a-failing-test-not-a-fresh-prompt-1l9m</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/resume-an-abandoned-agent-patch-with-a-failing-test-not-a-fresh-prompt-1l9m</guid>
      <description>&lt;p&gt;An agent has changed a retry helper, left a short note about “finishing the defaults,” and stopped. The developer who started the task is unavailable. Another teammate can run the project, but the conversation alone does not establish what the patch actually does.&lt;/p&gt;

&lt;p&gt;Instead of starting with “continue the previous agent's work,” give the next runner a small failing behavior to investigate. A reproducible boundary turns a vague recovery assignment into a task someone else can execute and a reviewer can assess.&lt;/p&gt;

&lt;p&gt;Here is a deliberately small, hypothetical example. The function and input contract are invented for this tutorial; they are not taken from a production incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Establish the input contract first
&lt;/h2&gt;

&lt;p&gt;Suppose an internal worker accepts a retry limit. The agreed contract is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;None&lt;/code&gt; means use the default of three retries.&lt;/li&gt;
&lt;li&gt;Zero means do not retry.&lt;/li&gt;
&lt;li&gt;A positive integer is an explicit limit.&lt;/li&gt;
&lt;li&gt;Negative values, booleans, strings, and floats are invalid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those choices belong to the application owner. If zero might mean “unlimited” in the real service, settle that decision before implementing this example. An agent should not infer the contract from a convenient language idiom.&lt;/p&gt;

&lt;p&gt;The partial patch contains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retry_limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That looks compact, but it collapses two different inputs into one result. Both &lt;code&gt;None&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt; return three. It also accepts values the contract rejects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn the uncertainty into a reproduction
&lt;/h2&gt;

&lt;p&gt;Create a scratch file, &lt;code&gt;retry_example.py&lt;/code&gt;, with the function above and this check beneath it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;retry_limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;retry_limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;zero must disable retries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;retry_limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with an approved local Python interpreter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 retry_example.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The zero assertion fails against the partial implementation. That is useful evidence about this function. It is not evidence that a deployed worker has retried a real job, nor that fixing this helper will repair every call site.&lt;/p&gt;

&lt;p&gt;In a real repository, record the exact revision and runtime version beside the reproduction. Keep existing uncommitted changes intact. Use the project's normal isolated-work workflow before experimenting, especially when another person may resume their own branch later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare a handoff that names the next action
&lt;/h2&gt;

&lt;p&gt;The recovery coordinator writes a record like this. Replace the bracketed fields with observed values, rather than copying an old agent's assurances.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;preserve explicit zero in retry policy&lt;/span&gt;
&lt;span class="na"&gt;prepared_by&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;recovery coordinator&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;source_revision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;full commit identifier&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;available&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;partial retry helper and original requirement&lt;/span&gt;
  &lt;span class="na"&gt;unavailable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;original author's unsaved local work&lt;/span&gt;
  &lt;span class="na"&gt;acceptance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pending&lt;/span&gt;
&lt;span class="na"&gt;evidence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;reproduction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;retry_example.py&lt;/span&gt;
  &lt;span class="na"&gt;observed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zero is converted to three&lt;/span&gt;
  &lt;span class="na"&gt;integration_checks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;not run&lt;/span&gt;
&lt;span class="na"&gt;next_action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;implement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;validate the agreed input contract&lt;/span&gt;
  &lt;span class="na"&gt;verify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default, zero, positive, and rejected input cases&lt;/span&gt;
&lt;span class="na"&gt;boundaries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;queue behavior changes, deployment, new dependencies&lt;/span&gt;
  &lt;span class="na"&gt;stop_if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;a caller relies on coercing strings or booleans&lt;/span&gt;
&lt;span class="na"&gt;handoff&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;runner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;teammate with authorized repository and tool access&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;reviewer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;owner of retry behavior&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;return&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;revision, diff, test output, unresolved callers&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The coordinator prepares the work. The runner uses their own approved tools and identity to inspect and change it. The reviewer decides whether the result satisfies the contract. A task brief transfers context; it does not transfer an account, credentials, or another person's tool allowance.&lt;/p&gt;

&lt;p&gt;An AI work handoff needs these boundaries even when everyone uses the same coding assistant. &lt;a href="https://wagglet.com/for/startups" rel="noopener noreferrer"&gt;Wagglet for startups&lt;/a&gt; describes routing prepared work to teammates or agents without sharing accounts. The concrete artifact being routed here is the reproduction plus its acceptance record, not an instruction to trust a previous conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the smallest change the contract supports
&lt;/h2&gt;

&lt;p&gt;One implementation for this specific contract is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retry_limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retry limit must be a non-negative integer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact-type check is intentional: Python booleans behave as integers in several contexts, but this contract rejects them. A service that accepts integer subclasses would need a different validation decision.&lt;/p&gt;

&lt;p&gt;Extend the reproduction with rejected inputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;invalid&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;retry_limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;invalid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;AssertionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unexpected acceptance: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;invalid&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These checks exercise the chosen function contract. The runner must still inspect callers: configuration parsing may already coerce inputs, or another component may treat zero differently. Finding such a dependency is a reason to report a scope decision, not silently broaden the patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Return a reviewable result
&lt;/h2&gt;

&lt;p&gt;The final handoff should distinguish the failing baseline from the submitted change. Include the tested revision, exact command, result, and any checks that were not run. Do not describe a successful scratch reproduction as a passing repository test suite.&lt;/p&gt;

&lt;p&gt;The reviewer can then ask a focused question: does the patch preserve the agreed retry semantics at the relevant boundary? They may accept the helper change while requiring integration evidence before deployment.&lt;/p&gt;

&lt;p&gt;This process will not recover inaccessible edits or resolve missing product decisions. It gives the replacement runner a concrete starting point, and makes the remaining uncertainty visible to the person responsible for acceptance.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>testing</category>
    </item>
    <item>
      <title>A review contract for an AI-assisted VFX change</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Fri, 02 Oct 2026 11:36:20 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/a-review-contract-for-an-ai-assisted-vfx-change-557n</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/a-review-contract-for-an-ai-assisted-vfx-change-557n</guid>
      <description>&lt;p&gt;An AI workflow for VFX integration needs a definition of success that survives beyond the agent session. A short contract can make that definition inspectable before the implementation starts.&lt;/p&gt;

&lt;p&gt;Suppose a game already exposes an objective-completed event. The proposed change adds a brief visual response. It must not change how rewards are awarded.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write the contract
&lt;/h3&gt;

&lt;p&gt;Use the following as a task template. The durations are design targets for this example, not measured results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;change&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;objective-completion-feedback&lt;/span&gt;
&lt;span class="na"&gt;trigger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;existing_confirmed_objective_completion_event&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;one_visual_effect&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;event_binding&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;lifecycle_cleanup&lt;/span&gt;
&lt;span class="na"&gt;out_of_scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;reward_amounts&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;authentication&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;backend_schema&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;native_plugins&lt;/span&gt;
&lt;span class="na"&gt;behavior&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;max_visual_duration_ms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;700&lt;/span&gt;
  &lt;span class="na"&gt;repeated_event&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;no_duplicate_reward_or_parallel_feedback&lt;/span&gt;
  &lt;span class="na"&gt;reduced_motion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;static_label_and_icon&lt;/span&gt;
&lt;span class="na"&gt;evidence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;exact_revision&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;reproduction_steps&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;normal_and_repeated_event_recording&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;teardown_check&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;actual_test_environment&lt;/span&gt;
&lt;span class="na"&gt;review&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;visual&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;assigned_artist&lt;/span&gt;
  &lt;span class="na"&gt;integration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;assigned_engineer&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;assigned_release_owner&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before starting, replace role labels with the people responsible and the event label with the actual repository symbol. If the event does not exist, stop and agree on the expanded scope.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep state and presentation separate
&lt;/h3&gt;

&lt;p&gt;For a project using SpacetimeDB, route the visual from the game’s existing confirmed state. Do not add a second reward operation to an animation callback.&lt;/p&gt;

&lt;p&gt;For a PixiJS HUD or a Three.js scene, define where the effect lives and who owns its cleanup. In a project that uses both, decide whether both layers need feedback; two celebrations may compete for attention.&lt;/p&gt;

&lt;p&gt;For a Capacitor build, include a real device check before claiming mobile support. Browser playback answers a narrower question.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exercise the failure paths
&lt;/h3&gt;

&lt;p&gt;The happy path is one completed objective and one visual response. The review should also cover a repeated event, a scene exit during playback, a failed asset load, and reduced-motion mode.&lt;/p&gt;

&lt;p&gt;If the asset fails to load, preserve the underlying completion state and text feedback. If the scene closes, remove its event subscription and effect resources. If reduced motion is enabled, communicate the same outcome without requiring the animation.&lt;/p&gt;

&lt;p&gt;Record observations for each case. A checklist is a plan until someone runs it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make the handoff readable
&lt;/h3&gt;

&lt;p&gt;The delivery should let the reviewer locate the code, reproduce the behavior, and distinguish checked conditions from assumptions. That is the organizational problem discussed in &lt;a href="https://wagglet.com/blog/ai-native-mobile-game-studio-stack" rel="noopener noreferrer"&gt;Wagglet’s game studio workflow article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A finished implementation is only one stage. Visual approval, technical acceptance, and release remain separate decisions, each tied to the same revision.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>vfx</category>
      <category>gamedev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Tie Human Approval to the Exact Version an AI Agent Delivered</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Thu, 01 Oct 2026 11:23:27 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/tie-human-approval-to-the-exact-version-an-ai-agent-delivered-b6e</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/tie-human-approval-to-the-exact-version-an-ai-agent-delivered-b6e</guid>
      <description>&lt;p&gt;A reviewer approves a change. An agent then makes another edit. The task still shows “approved.”&lt;br&gt;
That is an easy workflow mistake to make when approval belongs to a task rather than a particular delivery.&lt;br&gt;
A practical review process should answer three questions: what was reviewed, who reviewed it, and what changed afterward? You can model those questions without building a large approval system.&lt;br&gt;
Keep the delivery and review separate&lt;br&gt;
Consider a hypothetical task to improve a form’s validation message. The agent prepares the change. A teammate checks the interaction and error wording. An engineering reviewer checks the implementation.&lt;br&gt;
The delivery record should identify the submitted version and its evidence. The review should identify the same version and record the acceptance decision.&lt;br&gt;
Here is a small JavaScript example:&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;javascript&lt;br&gt;
function canAccept(task, delivery, review, actorId) {&lt;br&gt;
  return task.status === 'awaiting_review' &amp;amp;&amp;amp;&lt;br&gt;
    Boolean(delivery.revision) &amp;amp;&amp;amp;&lt;br&gt;
    delivery.revision === task.currentRevision &amp;amp;&amp;amp;&lt;br&gt;
    Boolean(delivery.evidenceUrl) &amp;amp;&amp;amp;&lt;br&gt;
    actorId === task.reviewerId &amp;amp;&amp;amp;&lt;br&gt;
    actorId !== delivery.runnerId &amp;amp;&amp;amp;&lt;br&gt;
    review.revision === delivery.revision &amp;amp;&amp;amp;&lt;br&gt;
    review.decision === 'accept' &amp;amp;&amp;amp;&lt;br&gt;
    Boolean(review.note?.trim()) &amp;amp;&amp;amp;&lt;br&gt;
    task.criteria.length &amp;gt; 0 &amp;amp;&amp;amp;&lt;br&gt;
    task.criteria.every(id =&amp;gt; review.checks[id] === true);&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;br&gt;
`&lt;br&gt;
This function assumes the records have already been validated for their expected shape. It illustrates a workflow rule; it is not a complete authorization system.&lt;br&gt;
Try it with these sample records:&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;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;awaiting_review&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;currentRevision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rev-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reviewerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reviewer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;criteria&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;behavior&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scope&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;delivery&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;revision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rev-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;runnerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;runner&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;evidenceUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/evidence/rev-2&lt;/span&gt;&lt;span class="dl"&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;review&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;revision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rev-2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;accept&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Checked the error message and confirmed the change stayed in scope.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;behavior&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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="nf"&gt;canAccept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delivery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reviewer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// true&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="nf"&gt;canAccept&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;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;currentRevision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rev-3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;delivery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reviewer&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="c1"&gt;// false: the approval does not cover the current version.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The revision labels and evidence path are illustrative. In an implementation, use an immutable revision identifier and evidence tied to that revision.&lt;br&gt;
Make each criterion inspectable&lt;br&gt;
A checkbox called “looks good” leaves too much interpretation to the reviewer.&lt;br&gt;
For the validation-message example, define observable checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Submitting an empty required field displays the agreed message.&lt;/li&gt;
&lt;li&gt;Correcting that field clears its error.&lt;/li&gt;
&lt;li&gt;The change leaves unrelated validation behavior unchanged.
A review note should explain what was inspected and any remaining limits. Checking a field in a record does not prove the underlying behavior works.
During preparation, the function was checked against six illustrative cases: a valid acceptance, the wrong actor, an outdated review, missing evidence, an unchecked criterion, and a newer task revision. Those cases passed their expected assertions. They do not establish production security or integration correctness.
Enforce the rule where acceptance happens
In a real application, derive the reviewer’s identity from the authenticated session. Do not trust an identity supplied in a request body.
Load the current task and delivery from trusted storage. Check their revisions and apply the acceptance update atomically, so a new delivery cannot arrive between the check and the update. Keep an audit record of the decision.
An AI team management platform can store those records, but the team still has to decide which judgments belong to qualified reviewers. Wagglet’s discussion of meaningful work with human–AI pairs provides the broader context for making that human contribution explicit.
Preserve the work behind the approval
The person who reproduces an issue, identifies an ambiguous requirement, or rejects an incorrect fix has contributed to the outcome.
Keep that work visible. Record why a delivery was returned, what evidence was missing, and which specialist was needed. Include that review time when evaluating the process.
A new version should create a new review obligation. Otherwise, the approval stops describing what a person actually checked.
&lt;a href="https://wagglet.com/blog" rel="noopener noreferrer"&gt;https://wagglet.com/blog&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>automation</category>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
