<?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: Idolor Godswill Eseteru</title>
    <description>The latest articles on DEV Community by Idolor Godswill Eseteru (@big14way).</description>
    <link>https://dev.to/big14way</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%2F4160010%2F22268012-cfe0-407f-8305-557c5279ff7b.jpg</url>
      <title>DEV Community: Idolor Godswill Eseteru</title>
      <link>https://dev.to/big14way</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/big14way"/>
    <language>en</language>
    <item>
      <title>Clearance Desk: an agent that catches the admission you'd lose at clearance</title>
      <dc:creator>Idolor Godswill Eseteru</dc:creator>
      <pubDate>Sun, 04 Oct 2026 14:28:41 +0000</pubDate>
      <link>https://dev.to/big14way/clearance-desk-an-agent-that-catches-the-admission-youd-lose-at-clearance-36e8</link>
      <guid>https://dev.to/big14way/clearance-desk-an-agent-that-catches-the-admission-youd-lose-at-clearance-36e8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge, Path One: Ship an Agent That Queries Real Content&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;In Nigeria you can score well in JAMB's UTME, get offered admission, and still be turned away at &lt;strong&gt;clearance&lt;/strong&gt;. Clearance is when the university checks your O'level results against the course's rules. The mistakes are small and specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a Physics credit that came from a second sitting when the course allows only one&lt;/li&gt;
&lt;li&gt;no Further Maths credit for UNILAG Computer Science&lt;/li&gt;
&lt;li&gt;Mathematics counted as one of your UTME subjects for Law&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One wrong subject costs a whole year.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clearance Desk&lt;/strong&gt; is an agent for applicants (and the parents and teachers helping them). It checks your UTME subjects, UTME score and O'level sittings against the &lt;em&gt;published&lt;/em&gt; 2026/2027 requirements of UNILAG, UI, OAU, UNN and LASU, before you apply.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For each course it tells you &lt;strong&gt;Eligible&lt;/strong&gt;, &lt;strong&gt;At risk&lt;/strong&gt; or &lt;strong&gt;Not eligible&lt;/strong&gt;, and explains why in plain English, linking every source.&lt;/li&gt;
&lt;li&gt;Then you can &lt;strong&gt;ask the Knowledge Base what to do next&lt;/strong&gt;: deadlines, screening windows, awaited results. Answers come only from JAMB and university notices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbzty2nkak5did7y8dgxx.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%2Fbzty2nkak5did7y8dgxx.png" alt="A " width="716" height="1520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The core design rule: &lt;strong&gt;the model finds and explains; deterministic code judges.&lt;/strong&gt; Claude never decides a verdict. It finds the right rules through Sanity Context, a small TypeScript evaluator checks them, and Claude explains the result using the Knowledge Base.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live: &lt;a href="https://clearancedesk.vercel.app" rel="noopener noreferrer"&gt;https://clearancedesk.vercel.app&lt;/a&gt;&lt;/strong&gt;. No login, and it works on a phone. Tap one of the three &lt;strong&gt;sample candidates&lt;/strong&gt; at the top:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You'll watch each Sanity Context step land live.&lt;/li&gt;
&lt;li&gt;The verdict appears as soon as the code decides it, usually within 10–15 seconds.&lt;/li&gt;
&lt;li&gt;Then the explanation arrives.&lt;/li&gt;
&lt;li&gt;Finally, try one of the suggested questions under the result.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/xm8uXu6VgaY" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;In the two-minute narrated video:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Chioma (UTME 301) checks Medicine at UNILAG and gets &lt;strong&gt;Not eligible&lt;/strong&gt;: UNILAG allows one sitting, and her Physics credit is from a second one.&lt;/li&gt;
&lt;li&gt;With the &lt;em&gt;same&lt;/em&gt; results, UNN Nursing (two sittings allowed) gives &lt;strong&gt;Eligible&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;"Show courses I qualify for" checks 10 courses at once.&lt;/li&gt;
&lt;li&gt;She asks the Knowledge Base for her upload deadline, which turns out to have been extended.&lt;/li&gt;
&lt;li&gt;A look at how the Knowledge Base was built, and the trace.&lt;/li&gt;
&lt;li&gt;The eval.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/big14way" rel="noopener noreferrer"&gt;
        big14way
      &lt;/a&gt; / &lt;a href="https://github.com/big14way/clearancedesk" rel="noopener noreferrer"&gt;
        clearancedesk
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Clearance Desk&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;An AI agent that tells Nigerian university applicants whether their &lt;strong&gt;UTME subjects, UTME score and O'level results&lt;/strong&gt; meet the published requirements for a specific course at a specific university — &lt;em&gt;before&lt;/em&gt; they apply, so they don't get admitted and then rejected at clearance.&lt;/p&gt;
&lt;p&gt;Built for the DEV × Sanity Challenge, Path One: "Ship an Agent That Queries Real Content".&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://clearancedesk.vercel.app" rel="nofollow noopener noreferrer"&gt;https://clearancedesk.vercel.app&lt;/a&gt; (no login). The About page shows the architecture and live data coverage.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/big14way/clearancedesk/submission/screenshots/post/05-architecture.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fbig14way%2Fclearancedesk%2FHEAD%2Fsubmission%2Fscreenshots%2Fpost%2F05-architecture.png" alt="Architecture: one agent, two Sanity Context endpoints, one deterministic evaluator"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Core principle: the model finds and explains; deterministic code judges.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🚧 Work in progress. See &lt;a href="https://github.com/big14way/clearancedesk/BUILD_SPEC.md" rel="noopener noreferrer"&gt;&lt;code&gt;BUILD_SPEC.md&lt;/code&gt;&lt;/a&gt; for the plan and &lt;a href="https://github.com/big14way/clearancedesk/BUILD_LOG.md" rel="noopener noreferrer"&gt;&lt;code&gt;BUILD_LOG.md&lt;/code&gt;&lt;/a&gt; for the build journal.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Layout&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;studio/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sanity Studio + schema (sources, subjects, institutions, programmes, requirements)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;data/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sources.yaml&lt;/code&gt;, &lt;code&gt;catalog.yaml&lt;/code&gt;, generated &lt;code&gt;seed.ndjson&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;scripts/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;NDJSON builder, MCP endpoint checks, eval runner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;web/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Next.js app: form, &lt;code&gt;/api/check&lt;/code&gt; agent route, deterministic eligibility evaluator&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Data (Phase 2)&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;34 admission requirements for the &lt;strong&gt;2026/2027&lt;/strong&gt; session across 5…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/big14way/clearancedesk" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The repo has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Studio schema&lt;/li&gt;
&lt;li&gt;the source-traced data pipeline&lt;/li&gt;
&lt;li&gt;the evaluator, with 49 unit tests&lt;/li&gt;
&lt;li&gt;the agent and the Next.js app&lt;/li&gt;
&lt;li&gt;the eval&lt;/li&gt;
&lt;li&gt;an honest &lt;a href="https://github.com/big14way/clearancedesk/blob/main/BUILD_LOG.md" rel="noopener noreferrer"&gt;build log&lt;/a&gt; of every wrong turn&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Used Sanity
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Admission rules as structured content
&lt;/h3&gt;

&lt;p&gt;Requirements live in a Sanity dataset as data a program can check, not as prose. There are five document types: &lt;code&gt;source&lt;/code&gt;, &lt;code&gt;subject&lt;/code&gt;, &lt;code&gt;institution&lt;/code&gt;, &lt;code&gt;programme&lt;/code&gt; and &lt;code&gt;requirement&lt;/code&gt;. A &lt;code&gt;requirement&lt;/code&gt; holds one programme's rules for one session:&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;Why it's data, not text&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;utmeCompulsory&lt;/code&gt;, &lt;code&gt;utmeChoices&lt;/code&gt; (&lt;code&gt;{pick: 1, from: [subject refs]}&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;"English, Maths, Physics + Chemistry &lt;em&gt;or&lt;/em&gt; Biology" becomes a set problem the code can solve, without guessing from a sentence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;olevelCompulsory&lt;/code&gt; with a &lt;code&gt;minGrade&lt;/code&gt; per subject, plus &lt;code&gt;olevelChoices&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Further Maths at UNILAG CS is just one more compulsory subject&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;olevelMinCredits&lt;/code&gt;, &lt;code&gt;olevelMinCreditsCombined&lt;/code&gt;, &lt;code&gt;olevelMaxSittings&lt;/code&gt;, &lt;code&gt;olevelAcceptedExams&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;"Five credits at one sitting, or six at two" (UI) can only be checked if it's modelled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;utmeMinScore&lt;/code&gt; (nullable)&lt;/td&gt;
&lt;td&gt;UI publishes no 2026/27 minimum, so &lt;code&gt;null&lt;/code&gt; says "unknown", not 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;citations[]&lt;/code&gt; (a &lt;code&gt;source&lt;/code&gt; reference plus a locator such as "p. 23, COMPUTER SCIENCE row")&lt;/td&gt;
&lt;td&gt;Every rule traces to a page you can open&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;verificationStatus&lt;/code&gt; + &lt;code&gt;conflictNote&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;When JAMB's brochure and the university disagree, I store the stricter rule and explain both&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Subjects are referenced by &lt;code&gt;_id&lt;/code&gt;, with aliases, so "Use of English" vs "English Language" can't break a match.&lt;/p&gt;

&lt;p&gt;The dataset has 34 requirements across 5 universities. 13 are verified field by field against their sources, and 21 are marked &lt;code&gt;conflicting&lt;/code&gt; because official sources really do disagree, which is the whole problem. All of it is built from &lt;strong&gt;57 saved sources (51 official)&lt;/strong&gt;: JAMB's IBASS brochure API, JAMB's brochure PDFs, and each university's 2026 notices.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Two Sanity Context endpoints, and why there are two
&lt;/h3&gt;

&lt;p&gt;A Context MCP endpoint serves one kind of source: if you attach a dataset and a Knowledge Base together, the dataset wins and the KB is silently ignored. So the agent connects to two endpoints and prefixes their tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Tools the agent uses&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clearance-rules&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;dataset &lt;code&gt;cynv9mfk.production&lt;/code&gt;, with a GROQ filter to the 5 types&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;rules_groq_query&lt;/code&gt;, &lt;code&gt;rules_schema_explorer&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;clearance-policy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the Knowledge Base&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;policy_knowledge_base_read&lt;/code&gt;, &lt;code&gt;policy_knowledge_base_search&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Following Sanity's own pattern, both endpoints' &lt;code&gt;initial_context&lt;/code&gt; is fetched over HTTP and put into the system prompt. The agent starts out knowing the schema and the KB outline without spending a tool call.&lt;/p&gt;

&lt;p&gt;Each endpoint also has &lt;strong&gt;Instructions&lt;/strong&gt;. For the rules endpoint, the instructions say to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;match subjects by &lt;code&gt;_id&lt;/code&gt;, never by name&lt;/li&gt;
&lt;li&gt;treat choice groups as "pick N"&lt;/li&gt;
&lt;li&gt;always return &lt;code&gt;verificationStatus&lt;/code&gt;, &lt;code&gt;conflictNote&lt;/code&gt; and citations&lt;/li&gt;
&lt;li&gt;never decide eligibility itself, and instead pass requirement &lt;code&gt;_id&lt;/code&gt;s to the evaluator&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. What the agent actually does
&lt;/h3&gt;

&lt;p&gt;One loop (Vercel AI SDK 6 + Claude Sonnet 5.5):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;rules_groq_query&lt;/code&gt;&lt;/strong&gt; finds the requirement documents. In check mode that's the programme's requirement. In explore mode the model writes GROQ like &lt;code&gt;count(utmeCompulsory[@._ref in [...your UTME subjects]]) == count(utmeCompulsory)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;evaluate_eligibility&lt;/code&gt;&lt;/strong&gt;, a local tool, loads those documents and runs the evaluator against your results, which the server holds so the model can never retype them. It checks:

&lt;ul&gt;
&lt;li&gt;UTME subjects, using bipartite matching for choice groups&lt;/li&gt;
&lt;li&gt;the UTME score&lt;/li&gt;
&lt;li&gt;every combination of your sittings up to the course's limit&lt;/li&gt;
&lt;li&gt;credits, accepted exams and awaited results&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;policy_knowledge_base_read&lt;/code&gt;&lt;/strong&gt; reads the KB entries behind each failed or uncertain check, in one call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;submit_verdict&lt;/code&gt;&lt;/strong&gt; is a tool with no &lt;code&gt;execute&lt;/code&gt;, so calling it ends the loop. The model's explanation is merged with the evaluator's verdicts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The route streams the loop as it runs: each Sanity Context step as it finishes, then &lt;strong&gt;the verdict as soon as &lt;code&gt;evaluate_eligibility&lt;/code&gt; returns&lt;/strong&gt;, before the explanation is written. On a phone you watch the rules query and the checks land, and the decided verdict shows up in about half the total time.&lt;/p&gt;

&lt;p&gt;Some guarantees are enforced in code, not just in the prompt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a policy note is dropped unless its KB path was actually read in that run&lt;/li&gt;
&lt;li&gt;check mode can't evaluate a different course&lt;/li&gt;
&lt;li&gt;if the model never finishes, you still get the exact verdicts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every answer ships with its trace:&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%2Fhcq5v92030yen2jqnudn.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%2Fhcq5v92030yen2jqnudn.png" alt="The trace: GROQ via clearance-rules, deterministic checks, KB entries via clearance-policy" width="716" height="1772"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The Knowledge Base
&lt;/h3&gt;

&lt;p&gt;The rules say &lt;em&gt;what&lt;/em&gt;; the Knowledge Base says &lt;em&gt;why it matters and what to do&lt;/em&gt;: cut-off marks, Post-UTME screening, awaiting-result windows, upload deadlines, sitting rules. I built it from &lt;strong&gt;32 sources: 26 official&lt;/strong&gt; (JAMB, plus all five universities' notices and requirement PDFs) and &lt;strong&gt;6 blogs&lt;/strong&gt;. The blogs are in deliberately, so Context would surface where they disagree with official sources.&lt;/p&gt;

&lt;p&gt;Context found &lt;strong&gt;7 conflicts&lt;/strong&gt;. I resolved 6 and dismissed 1 as a false conflict. Each resolution became a standing instruction. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LASU's 195:&lt;/strong&gt; a blog called it a "cut-off mark"; LASU's own notices say "a minimum of 195 marks". Official wording won.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UNILAG sittings:&lt;/strong&gt; UNILAG requires five O'level credits &lt;em&gt;at one sitting only&lt;/em&gt;. This is the rule behind the demo's "Not eligible".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UNILAG's O'level upload deadline:&lt;/strong&gt; the extension notice (Monday, 24 August 2026) beats the original date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OAU English:&lt;/strong&gt; an OAU page says "a pass at O-Level … in English Language". I kept the stricter reading, a full credit, because a pass would get a candidate rejected if OAU means a credit pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UNILAG's lowest merit cut-off:&lt;/strong&gt; Education Economics (49.65), not Meteorology as an entry claimed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fka40jmvmwkng3fc4t7mz.jpg" 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%2Fka40jmvmwkng3fc4t7mz.jpg" alt="Context found 7 conflicts" width="799" height="459"&gt;&lt;/a&gt;&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%2Fixnqbmjfc9jjzxw44tto.jpg" 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%2Fixnqbmjfc9jjzxw44tto.jpg" alt="Conflict review: blog vs official LASU notice" width="799" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I wrote 4 instructions by hand:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Official JAMB sources outrank blogs.&lt;/li&gt;
&lt;li&gt;A university's own published requirement is ground truth over summaries.&lt;/li&gt;
&lt;li&gt;A rule for what an entry must do when JAMB's brochure and a university's own requirement disagree.&lt;/li&gt;
&lt;li&gt;Always name the admission session.&lt;/li&gt;
&lt;/ol&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%2F6l9idjcfqnz6p1czdm28.jpg" 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%2F6l9idjcfqnz6p1czdm28.jpg" alt="10 instructions: 4 manual, 6 from resolved issues" width="799" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Knowledge Base answers questions directly too.&lt;/strong&gt; Under every result there's an "Ask about the admission policy" box with suggested questions for that school, such as "What is the deadline to upload my O'level result for UNILAG?". A second agent answers them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It reads KB entries through &lt;code&gt;clearance-policy&lt;/code&gt; and must cite the paths it read. Citations it didn't read are dropped in code.&lt;/li&gt;
&lt;li&gt;If the KB doesn't cover the question, it says so ("answered: false") instead of guessing.&lt;/li&gt;
&lt;li&gt;It gets today's date, so it can say when a deadline has already passed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy1b80xngfpqx1x3g6int.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%2Fy1b80xngfpqx1x3g6int.png" alt="A follow-up answered from the Knowledge Base, with official sources" width="716" height="1870"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Building this exposed a real Knowledge Base problem. Its &lt;code&gt;post_utme_screening&lt;/code&gt; entry still gave UNILAG's original upload deadline (14 August), even though I had resolved that conflict in favour of the extension (24 August). I fixed it at the source, with Context's &lt;strong&gt;"Rewrite this part"&lt;/strong&gt; on that paragraph. That creates a standing rule every future build honours: &lt;em&gt;"UNILAG's 2026/2027 O'level upload deadline … is Monday, 24 August 2026 … extended from the original Friday, 14 August 2026."&lt;/em&gt; The entry rebuilt with the corrected line, and every other fact on the page survived. The follow-up agent also keeps a general safeguard: when entries give different dates, the later notice wins.&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%2F9zu5g0cl139gdxbui8z8.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%2F9zu5g0cl139gdxbui8z8.png" alt="The new standing instruction in Sanity Context" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Would keyword search get the same answer? The eval
&lt;/h3&gt;

&lt;p&gt;The organisers asked exactly this, so I measured it. I wrote 15 cases full of traps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UNILAG Computer Science's Further Maths credit&lt;/li&gt;
&lt;li&gt;one sitting vs two&lt;/li&gt;
&lt;li&gt;UI's "6 credits at two sittings"&lt;/li&gt;
&lt;li&gt;NABTEB results&lt;/li&gt;
&lt;li&gt;a UTME score of 196 against minimums of 195 and 200&lt;/li&gt;
&lt;li&gt;a course outside the data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An &lt;strong&gt;independent agent that could only read the original source files&lt;/strong&gt; set the expected verdict for each case, with quoted evidence. It couldn't see my dataset or code. Each case then ran through three systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clearance Desk&lt;/strong&gt; on production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The same model with Knowledge Base search.&lt;/strong&gt; It gets &lt;code&gt;knowledge_base_search&lt;/code&gt;/&lt;code&gt;knowledge_base_read&lt;/code&gt; on the &lt;em&gt;same&lt;/em&gt; Knowledge Base, plus its outline: keyword search over the exact same content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The same model with no tools.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both baselines got &lt;em&gt;more&lt;/em&gt; thinking time than the agent. Here is run 4; run 3 had the same Clearance Desk score.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Clearance Desk&lt;/th&gt;
&lt;th&gt;Same model + KB search&lt;/th&gt;
&lt;th&gt;Same model, no tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Correct&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;13 / 15&lt;/strong&gt; (13 in run 3 too)&lt;/td&gt;
&lt;td&gt;6 / 15 (4 in run 3)&lt;/td&gt;
&lt;td&gt;6 / 15 (8 in run 3)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Told a candidate who fails a published rule "Eligible"&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;0&lt;/strong&gt; (0)&lt;/td&gt;
&lt;td&gt;4 (2)&lt;/td&gt;
&lt;td&gt;3 (4)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Keyword search doesn't save the model.&lt;/strong&gt; With the KB it searched, read the right entries, even quoted "five credits at one sitting", and still told Chioma (two sittings, UNILAG Medicine) she was eligible. It also missed UNILAG CS's Further Maths and UI's six-credit rule. Reading a rule isn't applying it. Structured rules plus code that applies them is the difference.&lt;/p&gt;

&lt;p&gt;The eval also caught three of &lt;strong&gt;my own bugs&lt;/strong&gt;, all fixed and logged:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A data bug:&lt;/strong&gt; LASU's sources only ever say "SSCE (or equivalent)", but I had encoded that as WAEC/NECO, so a NABTEB candidate was wrongly rejected. Run 1 scored 12/15 because of it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A rate-limiter bug:&lt;/strong&gt; it counted its own refusals, so retrying kept extending the lockout.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A parser bug in the eval harness itself.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Clearance Desk's two remaining misses are deliberate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It marks every requirement with conflicting official sources "At risk", even when the candidate meets both versions.&lt;/li&gt;
&lt;li&gt;It says "no data" for a course outside its data instead of guessing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/big14way/clearancedesk/blob/main/eval/results.md" rel="noopener noreferrer"&gt;Full results, every answer, and earlier runs&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sanity Project Details
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project ID:&lt;/strong&gt; &lt;code&gt;cynv9mfk&lt;/code&gt; · &lt;strong&gt;Dataset:&lt;/strong&gt; &lt;code&gt;production&lt;/code&gt; (public)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public dataset query (every requirement):&lt;/strong&gt; &lt;a href="https://cynv9mfk.api.sanity.io/v2026-09-01/data/query/production?query=*%5B_type%3D%3D%22requirement%22%5D%7B_id%2Csession%2CverificationStatus%7D" rel="noopener noreferrer"&gt;&lt;code&gt;*[_type=="requirement"]{_id,session,verificationStatus}&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live coverage counts are on the &lt;a href="https://clearancedesk.vercel.app/about" rel="noopener noreferrer"&gt;About page&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnqu0o14poqz1qg2xnp1y.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%2Fnqu0o14poqz1qg2xnp1y.png" alt="Architecture" width="800" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent Session
&lt;/h2&gt;

&lt;p&gt;The whole thing was built with Claude Code, phase by phase. That covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the schema and the source-traced data pipeline&lt;/li&gt;
&lt;li&gt;setting up the Knowledge Base and both Context endpoints, through the browser&lt;/li&gt;
&lt;li&gt;the evaluator and the agent&lt;/li&gt;
&lt;li&gt;the UI, the deploy and the eval&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every wrong turn, and how it was fixed, is in the &lt;a href="https://github.com/big14way/clearancedesk/blob/main/BUILD_LOG.md" rel="noopener noreferrer"&gt;build log&lt;/a&gt;. The best moments are when the eval caught my own LASU data bug, and when the follow-up questions exposed a stale date in the Knowledge Base.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coverage:&lt;/strong&gt; 5 universities, 34 programmes, one session (2026/2027), UTME entry only. Direct Entry, Post-UTME scores, aggregate scores and catchment quotas aren't calculated, and meeting the minimum never guarantees admission.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflicts:&lt;/strong&gt; 21 of 34 requirements have official sources that disagree. Clearance Desk stores the stricter rule and says "At risk", which can be over-cautious, as eval case C13 shows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unpublished minimums:&lt;/strong&gt; UI publishes no 2026/27 UTME minimum, so a UI course can never come out plain "Eligible".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unchecked conditions:&lt;/strong&gt; age, first choice and upload deadlines can't be checked from results. They're listed as "check these yourself". Cambridge O'Level isn't modelled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explanations:&lt;/strong&gt; the verdict comes from code, but the explanation comes from a model. It occasionally adds generic advice no source states, which the eval and the build log both note.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Knowledge Base is in beta&lt;/strong&gt; (up to 150 documents). This one uses 32 sources.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
