<?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: Shivam Dwivedi</title>
    <description>The latest articles on DEV Community by Shivam Dwivedi (@panditshivam).</description>
    <link>https://dev.to/panditshivam</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%2F1157841%2Fd916da9c-3787-4c22-8f4d-715432202d0f.jpg</url>
      <title>DEV Community: Shivam Dwivedi</title>
      <link>https://dev.to/panditshivam</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/panditshivam"/>
    <language>en</language>
    <item>
      <title>OpenJev on text and images: a tie, then a scoring surprise</title>
      <dc:creator>Shivam Dwivedi</dc:creator>
      <pubDate>Sat, 17 Oct 2026 07:17:30 +0000</pubDate>
      <link>https://dev.to/panditshivam/openjev-and-keyword-rules-tied-on-18-issues-the-labels-needed-a-closer-look-an</link>
      <guid>https://dev.to/panditshivam/openjev-and-keyword-rules-tied-on-18-issues-the-labels-needed-a-closer-look-an</guid>
      <description>&lt;p&gt;On 18 public Ruff issues, a small local model and keyword rules each matched 11 saved labels. On two generated product images, changing how the same model's answers were scored changed every image-only decision. Both results needed more explanation than a headline score.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI disclosure: An AI agent ran the experiments, generated the test images and drafted this article. I chose the photo/text conflict-review rule during our discussion.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI-generated test images. Two designed scenes, not real product-inspection evidence.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What was tested
&lt;/h2&gt;

&lt;p&gt;This used &lt;a href="https://github.com/mjdileep/OpenJev/tree/501da7e6b59c71e1d184a0eb37e36f8cc5bc6354" rel="noopener noreferrer"&gt;mjdileep/OpenJev&lt;/a&gt;, an independent Jev-style project, rather than an official open release of TypeSafe's Jev. OpenJev turns supplied text or images into category choices. It does not create the images.&lt;/p&gt;

&lt;p&gt;The model was &lt;a href="https://huggingface.co/mlx-community/Qwen3.5-0.8B-4bit/tree/da28692b5f139cb0ec58a356b437486b7dac7462" rel="noopener noreferrer"&gt;Qwen3.5-0.8B, in 4-bit form&lt;/a&gt;, running locally through MLX on an Apple M3 Pro with 18 GiB memory and Python 3.12.11. The image tests also used MLX-VLM 0.7.8. No model training was performed. Image generation used a separate built-in image-generation service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Text: the original tie
&lt;/h2&gt;

&lt;p&gt;The saved data had 24 Ruff reports: six development examples and 18 evaluation examples, with six per category. Reference categories came from &lt;code&gt;bug&lt;/code&gt;, &lt;code&gt;documentation&lt;/code&gt; and &lt;code&gt;wish&lt;/code&gt;, mapping &lt;code&gt;wish&lt;/code&gt; to feature. The sample followed GitHub's returned order within each label and included closed reports. It was not a random sample of incoming issues.&lt;/p&gt;

&lt;p&gt;The rules searched titles for documentation words first, then feature-request words, otherwise choosing bug. OpenJev received the title and up to 1,600 body characters, without the reference label.&lt;/p&gt;

&lt;p&gt;Both methods matched &lt;strong&gt;11/18 labels&lt;/strong&gt;: six bugs, two documentation reports and three features. Nine reports matched both methods, two matched only the rules, two only the model, and five neither. Repeating the model run preserved all 18 choices. Its median request time in that repeat was 0.513 seconds, excluding loading and warm-up; this was one local timing observation, not a speed benchmark.&lt;/p&gt;

&lt;p&gt;The input difference mattered, so a later exploratory run gave both methods the same input:&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%2Fji5yz0zxzik7s22ixy82.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%2Fji5yz0zxzik7s22ixy82.png" alt="Keyword rules match 11 of 18 labels with titles and 8 with title plus body. OpenJev matches 7 with titles and 11 with title plus body." width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Measured label matches on the same 18 already-inspected reports. The follow-up reused this sample; it was not a new blind evaluation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;More text helped this model and hurt these rules. A documentation link in a bug report can trigger a rule that gives documentation words priority. That is a property of this rule recipe; it does not show that rules generally fail with longer text.&lt;/p&gt;

&lt;h3&gt;
  
  
  A question before judging the score
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/astral-sh/ruff/issues/21099" rel="noopener noreferrer"&gt;Ruff #21099&lt;/a&gt; says that &lt;code&gt;ruff analyze graph&lt;/code&gt; seems to skip notebooks. Is that a bug or a feature request?&lt;/p&gt;

&lt;p&gt;My initial reading was &lt;strong&gt;feature: notebook support is missing&lt;/strong&gt;. The saved &lt;code&gt;wish&lt;/code&gt; label agrees. But the &lt;a href="https://github.com/astral-sh/ruff/issues/21099#issuecomment-3452301468" rel="noopener noreferrer"&gt;maintainer discussion&lt;/a&gt; found code explicitly skipping notebooks. Removing that filter made notebook files appear, though their imports were still missing. The intended behaviour matters before deciding which category is right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/astral-sh/ruff/issues/28493" rel="noopener noreferrer"&gt;Ruff #28493&lt;/a&gt; gives another reason to inspect labels. It describes a supposedly safe fix creating a type-checker error. The maintainer explains Ruff's runtime-oriented safety definition and accepts documenting the limitation. A documentation label fits that resolution, while a classifier reading the original report could reasonably choose bug.&lt;/p&gt;

&lt;p&gt;These discussions were inspected after evaluation. The original reference answers were not rewritten. The measured quantity remains agreement with repository labels, rather than independently checked accuracy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Images: make your prediction first
&lt;/h2&gt;

&lt;p&gt;The pictures above show a red mug with no visible damage and a blue bowl with a visible chip and crack. Each image was classified on three attributes: object, colour and condition. The agent visually inspected the generated outputs before inference; these are not independent human labels.&lt;/p&gt;

&lt;p&gt;Each scene was tested with image only, a matching description, a conflicting description, and a text-only control. The instruction said to judge the image when supplied. For text-only controls, the expected answer followed the description.&lt;/p&gt;

&lt;p&gt;The default image-only calls got &lt;strong&gt;0/6 attributes right&lt;/strong&gt;. A smaller batch did not change that result. The same model's direct descriptions, using a different prompt through MLX-VLM, correctly described the red mug and chipped blue bowl.&lt;/p&gt;

&lt;p&gt;That prompted a scoring check. With the same image-only inputs, questions, weights and batch size of one, switching from &lt;code&gt;score_mode="full"&lt;/code&gt; to &lt;code&gt;score_mode="binary"&lt;/code&gt; matched &lt;strong&gt;6/6 attributes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fye3fe5bb3gayli8r7sxu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fye3fe5bb3gayli8r7sxu.gif" alt="Animated replay of saved image-only decisions: default scoring picks the wrong object, colour and condition for both scenes; yes/no scoring matches all six attributes." width="799" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AI-generated scenes with an animated replay of measured outputs. This GIF is not live inference. Six attributes across two pictures do not establish general accuracy. The scoring diagnostic was chosen after the initial failures.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why did the ranking reverse?
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/mjdileep/OpenJev/blob/501da7e6b59c71e1d184a0eb37e36f8cc5bc6354/docs/architecture.md" rel="noopener noreferrer"&gt;default scoring&lt;/a&gt; compares the model's support for “yes” for each candidate. Binary scoring instead compares “yes” against “no” for that candidate.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Inspect the scores behind the colour reversal
  &lt;p&gt;For the red-mug colour question, the saved default run produced approximately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Red candidate: “yes” 0.005198; “no” 0.00006146.&lt;/li&gt;
&lt;li&gt;Blue candidate: “yes” 0.420787; “no” 0.420787.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Default scoring selects blue because its “yes” value is larger. Comparing only yes and no gives a different ranking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yes / (yes + no)
red  ≈ 0.9883
blue ≈ 0.5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The red candidate's “yes” is small, but its “no” is smaller still. These are response scores, not calibrated chances that a category is correct. We have not established which other possible response words explain the difference.&lt;/p&gt;



&lt;br&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The caption tests were also imperfect: default scoring matched 0/6 image attributes with accurate captions and 1/6 with conflicting captions. Text-only controls matched 5/6 description attributes. Captions were not separately rerun under binary scoring, so the image-only result does not establish resistance to misleading text.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should happen when the photo and text disagree?
&lt;/h2&gt;

&lt;p&gt;My choice from the discussion was: &lt;strong&gt;flag the conflict for review&lt;/strong&gt;. Show the conflicting details before accepting a category.&lt;/p&gt;

&lt;p&gt;A blue bowl paired with “an intact red mug” should not silently become a settled product record. But disagreement alone does not prove which source is wrong: the photo, description or model could be mistaken. This is a chosen review rule, not an implemented or validated conflict detector. The executed test still forces category choices.&lt;/p&gt;

&lt;h2&gt;
  
  
  What these results support
&lt;/h2&gt;

&lt;p&gt;The text comparison gives no reason to replace the simple rules for this small task. The image example shows that candidate scoring can reverse decisions even when the underlying model can describe the scenes. It does not establish a general OpenJev bug or show that binary scoring is always better.&lt;/p&gt;

&lt;p&gt;The limits are substantial: one model, one repository, 18 previously inspected issue reports and two designed images. The image attributes change together, the choices have no “unknown” option, and no real-photo or independent human evaluation was performed. Source issues may also have appeared in training data. No larger-model comparison or production reliability claim follows.&lt;/p&gt;

&lt;p&gt;The useful questions were what the labels describe, what information reaches each method, and how a response score becomes a decision. Those questions explain more than the score alone.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
