<?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: Hyunsik Park</title>
    <description>The latest articles on DEV Community by Hyunsik Park (@hyunsik_park_7c24c2e4f4fc).</description>
    <link>https://dev.to/hyunsik_park_7c24c2e4f4fc</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%2F4158944%2F393113eb-70cd-4218-8847-b9bb0bf14eb1.png</url>
      <title>DEV Community: Hyunsik Park</title>
      <link>https://dev.to/hyunsik_park_7c24c2e4f4fc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hyunsik_park_7c24c2e4f4fc"/>
    <language>en</language>
    <item>
      <title>ShiftCal: a local Gemma roster reader for someone close to me</title>
      <dc:creator>Hyunsik Park</dc:creator>
      <pubDate>Mon, 05 Oct 2026 01:04:11 +0000</pubDate>
      <link>https://dev.to/hyunsik_park_7c24c2e4f4fc/shiftcal-a-local-gemma-roster-reader-for-someone-close-to-me-4dbf</link>
      <guid>https://dev.to/hyunsik_park_7c24c2e4f4fc/shiftcal-a-local-gemma-roster-reader-for-someone-close-to-me-4dbf</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Someone close to me finds it cumbersome to move a rotating shift roster into a calendar. ShiftCal takes their own shifts as text, uses local Gemma to read the dates and shift types, and prepares a calendar file after they check each row.&lt;/p&gt;

&lt;p&gt;A night shift makes the problem concrete. &lt;code&gt;31일 나이트&lt;/code&gt; means a night shift on the 31st. With the example hours of 23:00–07:00, an October shift ends on November 1. Typing the wrong end date would leave a misleading calendar entry. ShiftCal calculates that boundary in tested code and shows both dates for review.&lt;/p&gt;

&lt;p&gt;The real-person need is confirmed. The schedules shown here are fictional, and I have not yet collected feedback from the recipient.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://hyunsikparker.github.io/shiftcal/" rel="noopener noreferrer"&gt;Open the interactive recorded demo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Try a recorded example&lt;/strong&gt;. The fourth row, &lt;code&gt;4일 이브닝?&lt;/code&gt;, stays unresolved. Correct it to Evening only if the original roster confirms that shift, or remove it. Check each remaining row to enable the calendar export. Day-off rows stay visible but create no event.&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%2Fxnf7obgulpk9on7lfy01.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%2Fxnf7obgulpk9on7lfy01.png" alt="ShiftCal showing the source roster beside rows to review" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The public page replays a saved response from an actual Gemma run; it does not host inference. To process new text, follow the local setup in the README. The app needs Python and Ollama, with no Python or JavaScript packages. It currently accepts text only and uses Korea Standard Time.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/HyunsikParker/shiftcal" rel="noopener noreferrer"&gt;Source, setup and tests on GitHub&lt;/a&gt; · MIT license.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Gemma (&lt;code&gt;gemma4:12b-it-q4_K_M&lt;/code&gt;, through Ollama) extracts a day and a D/E/N/O shift code from each Korean or English input line. Each result remains beside its source. Missing or duplicated model rows are flagged; explicit uncertainty stays unresolved.&lt;/p&gt;

&lt;p&gt;JavaScript handles dates, shift hours and iCalendar formatting. It rejects invalid dates, duplicate dates and overlapping shifts. Changing a row or its settings clears the relevant confirmation. Export stays blocked until the remaining rows are valid and checked. There is no automatic calendar sync.&lt;/p&gt;

&lt;p&gt;The Python server listens on loopback, calls a fixed local Ollama address and rejects foreign origins and Host headers. It limits input size and handles one extraction at a time. It does not log or save roster text. Users are asked to leave out names, workplace details and other people's shifts.&lt;/p&gt;

&lt;p&gt;Fifteen unit tests passed, including month and year boundaries, leap years, overnight overlaps, uncertainty and server access checks. Four synthetic fixtures also went through the actual model: three matched exactly, with 13 of 14 date/code pairs matching overall. In the remaining row, &lt;code&gt;주간&lt;/code&gt; had no date. Gemma left both fields unresolved instead of retaining the expected day-shift code. The row remained visible and could not be exported. These are small functional checks, not an accuracy benchmark.&lt;/p&gt;

&lt;p&gt;Desktop and mobile layouts were checked, along with a fresh three-line extraction in the browser. Calendar-app import and recipient field testing remain unverified. Reimporting a file may create duplicates; the app recommends a separate calendar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;An open-weight model makes local roster processing possible without sending each schedule to a hosted model service. Open source makes the boundary around that model visible: the prompt, schema, validation and export code are all in the repository. Someone adapting ShiftCal can change the shift hours or inspect a date calculation without depending on a private API.&lt;/p&gt;

&lt;p&gt;The first model download needs an internet connection and disk space. Local inference still needs suitable hardware and electricity; the application has no per-request service charge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Gemma.&lt;/strong&gt; Gemma performs the Korean and English roster extraction in the local application. The public demo includes a recorded response from that same implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI disclosure:&lt;/strong&gt; Codex generated and revised the implementation, tests and prose under my direction. I supplied and confirmed the real-person problem. Executed tests and model responses were checked; no interview, testimonial or field trial is claimed. This entry uses the Fully Autonomous development disclosure.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>Constraint Clerk: A Source-Cited Changeover Agent</title>
      <dc:creator>Hyunsik Park</dc:creator>
      <pubDate>Sat, 03 Oct 2026 15:13:18 +0000</pubDate>
      <link>https://dev.to/hyunsik_park_7c24c2e4f4fc/constraint-clerk-a-source-cited-changeover-agent-2jfg</link>
      <guid>https://dev.to/hyunsik_park_7c24c2e4f4fc/constraint-clerk-a-source-cited-changeover-agent-2jfg</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;p&gt;&lt;strong&gt;Fully Autonomous AI build.&lt;/strong&gt; Codex generated and revised the implementation, original fictional records and this writeup. The verification below is an actual Sanity Content Agent response. No human coding or venue experience is claimed.&lt;/p&gt;

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

&lt;p&gt;Constraint Clerk checks a changeover plan for a fictional pocket theater. A cart needs to reach backstage before an 18:12 cue. The September survey records a 940 mm passage, but an October sound screen reduces it to 690 mm. The unfolded cart is 880 mm wide.&lt;/p&gt;

&lt;p&gt;Finding both numbers is not enough. The agent must identify which claim applies, follow the explicit supersession, then combine width with cart state, preparation time, route duration and crew availability. Folding makes the cart narrower, but requires two crew and three minutes of preparation. The wider east passage has a timed closure. The west passage has no measured width.&lt;/p&gt;

&lt;p&gt;The output separates &lt;strong&gt;blocked&lt;/strong&gt;, &lt;strong&gt;feasible&lt;/strong&gt; and &lt;strong&gt;unknown&lt;/strong&gt;, with source records for each check. It never converts a missing measurement into permission to proceed. All venue and equipment records are original fiction, not a real inspection or safety assessment.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://hyunsikparker.github.io/constraint-clerk/" rel="noopener noreferrer"&gt;Open Constraint Clerk&lt;/a&gt; — no login required.&lt;/p&gt;

&lt;p&gt;Start with &lt;strong&gt;View recorded AI verification&lt;/strong&gt;. It loads the real October 3 response, its calculated result and the retrieval trace. Expand &lt;strong&gt;Full actual answer&lt;/strong&gt; and &lt;strong&gt;Actual retrieval trace&lt;/strong&gt; to inspect them. Selecting a source opens the original record, including the superseded survey.&lt;/p&gt;

&lt;p&gt;The public demo is static: viewing the recording makes &lt;strong&gt;no new AI request&lt;/strong&gt;. The other controls run the local checker. Changing inputs clears the recorded response, so a local result cannot be mistaken for a fresh model answer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;th&gt;Verification scope&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Original unfolded cart, north route&lt;/td&gt;
&lt;td&gt;Blocked: 880 mm cart, 690 mm passage&lt;/td&gt;
&lt;td&gt;Real Content Agent + Context conversation; also locally reproducible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Folded cart, same route and two crew&lt;/td&gt;
&lt;td&gt;Feasible against the documented constraints; finish 18:10&lt;/td&gt;
&lt;td&gt;Local deterministic check only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Folded cart, unmeasured west route&lt;/td&gt;
&lt;td&gt;Unknown; width evidence is missing&lt;/td&gt;
&lt;td&gt;Local deterministic check only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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%2Fzgfe2oux2d3qcn5hlfgf.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%2Fzgfe2oux2d3qcn5hlfgf.png" alt="Constraint Clerk showing the recorded agent response, constraint results and current source record" width="800" height="845"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/HyunsikParker/constraint-clerk" rel="noopener noreferrer"&gt;Source repository&lt;/a&gt; · MIT licensed.&lt;/p&gt;

&lt;p&gt;The React interface, TypeScript checker, local agent server, Sanity Studio schema and pinned lockfiles are included. The README explains how to run the local demo and reproduce the cloud integration with a separate project and your own credentials. &lt;strong&gt;21 local tests pass&lt;/strong&gt;, including source supersession, closure boundaries, missing measurements, canonical reference recovery and transport limits. Type checking and the production build pass.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  One dataset, two scoped Context endpoints
&lt;/h3&gt;

&lt;p&gt;The Content Lake holds 19 fictional documents: 11 &lt;code&gt;ccSource&lt;/code&gt; records and eight &lt;code&gt;ccClaim&lt;/code&gt; constraints. A claim stores its target, property, value, effective date and optional &lt;code&gt;supersedes&lt;/code&gt; reference. Routes refer to passages; folding requirements and crew rosters remain separate records.&lt;/p&gt;

&lt;p&gt;A Knowledge Base was built from that dataset. One read-only Context MCP endpoint exposes only the KB. A second exposes only the project's &lt;code&gt;ccSource&lt;/code&gt; and &lt;code&gt;ccClaim&lt;/code&gt; records. The agent uses Sanity Content Agent through the AI SDK, with built-in read, write and web search disabled.&lt;/p&gt;

&lt;p&gt;The request follows this path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The harness reads the KB outline and exposes &lt;code&gt;knowledge_base_read&lt;/code&gt; to the model.&lt;/li&gt;
&lt;li&gt;The model reads a relevant KB entry, then calls the custom &lt;code&gt;check_plan&lt;/code&gt; tool.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;check_plan&lt;/code&gt; queries the live dataset using Context's &lt;code&gt;groq_query&lt;/code&gt;, restores canonical reference arrays using &lt;code&gt;array_field_reader&lt;/code&gt;, validates the typed records and runs the checker.&lt;/li&gt;
&lt;li&gt;The model explains that result with exact source document IDs. The structured result is authoritative for the selected plan.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The actual result
&lt;/h3&gt;

&lt;p&gt;One live conversation on October 3 made &lt;strong&gt;four model HTTP requests and four agent tool calls&lt;/strong&gt;: two KB reads and two plan checks. Each plan check retrieved 19 structured records and restored four canonical reference arrays.&lt;/p&gt;

&lt;p&gt;The final answer cited &lt;code&gt;cc-claim-north-current&lt;/code&gt; for &lt;strong&gt;690 mm&lt;/strong&gt; and &lt;code&gt;cc-claim-north-old&lt;/code&gt; for the explicitly superseded &lt;strong&gt;940 mm&lt;/strong&gt; survey. It blocked the &lt;strong&gt;880 mm&lt;/strong&gt; unfolded cart, a &lt;strong&gt;190 mm&lt;/strong&gt; shortfall. The roster and 18:07 calculated finish passed; width was the blocker.&lt;/p&gt;

&lt;p&gt;The response also kept its scope: it described folding's requirements but did not claim to have evaluated the folded variant. That alternative is shown separately as a local check.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where retrieval needed a stricter boundary
&lt;/h3&gt;

&lt;p&gt;Context can outline an array instead of returning its full contents, even when it has one reference. The first adapter rejected that output rather than calculating with incomplete links. The corrected adapter reads each outlined array through &lt;code&gt;array_field_reader&lt;/code&gt; and checks its document ID, field, count, indices and cropping flags. A truncated response fails closed.&lt;/p&gt;

&lt;p&gt;The KB also has one reviewed, unresolved issue: a derived east-passage entry omits a closure interval that exists in the original structured source. The issue has not been dismissed. Exact intervals and measurements come from the validated records, not generated KB prose. The saved dataset was read back and matched the original seed's full typed-content hash.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cost and runtime limits
&lt;/h3&gt;

&lt;p&gt;The project was automatically assigned a &lt;strong&gt;USD0 Growth Trial&lt;/strong&gt;, with automatic downgrade to Free after 30 days. Only Free-included features were used; there was no paid upgrade or hosting purchase. Paid overages were disallowed.&lt;/p&gt;

&lt;p&gt;A durable one-conversation permit was reserved before inference. Limits were four model requests, four agent tool calls, 90 seconds, no SDK retries and 512 KiB per model response. The provider has no token-output cap, so none is claimed. No further live attempts were made. Immediately afterward, the usage screen still showed 0/1,000 credits and USD0; the settled consumed-credit count was not yet reflected and is not claimed to be zero.&lt;/p&gt;

&lt;p&gt;The public site has no model endpoint or tokens. The optional agent server is loopback-only. The README discloses two low-severity production dependency advisories and 12 separate Studio/CLI advisories, including the mitigations and remaining limits. No all-clean security audit is claimed.&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;r7tbo2j3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset:&lt;/strong&gt; &lt;code&gt;production&lt;/code&gt; (public, original fictional records)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document types:&lt;/strong&gt; &lt;code&gt;ccSource&lt;/code&gt;, &lt;code&gt;ccClaim&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge Base:&lt;/strong&gt; Constraint Clerk — North Pier Room (&lt;code&gt;kb4e4xT6fMwh&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset source filter:&lt;/strong&gt; &lt;code&gt;_type in ["ccSource", "ccClaim"] &amp;amp;&amp;amp; _id match "cc-*"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a separate project from the Path Two entry. Neither its content nor its submission was changed for this build.&lt;/p&gt;

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

&lt;p&gt;The public &lt;a href="https://github.com/HyunsikParker/constraint-clerk/blob/main/src/recorded-verification.json" rel="noopener noreferrer"&gt;recorded verification&lt;/a&gt; contains the actual question, selected plan, answer, structured result and timestamped retrieval trace. Its answer and trace match the original private run receipt. Credentials, private paths and unrelated work are excluded. This is the application agent's verification record, not an uploaded coding-session transcript.&lt;/p&gt;

&lt;p&gt;The integration follows the official &lt;a href="https://www.sanity.io/docs/ai/sanity-context-mcp" rel="noopener noreferrer"&gt;Sanity Context MCP&lt;/a&gt;, &lt;a href="https://www.sanity.io/docs/ai/sanity-context-create-knowledge-base" rel="noopener noreferrer"&gt;Knowledge Base&lt;/a&gt; and &lt;a href="https://reference.sanity.io/content-agent/" rel="noopener noreferrer"&gt;Content Agent&lt;/a&gt; interfaces.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
    <item>
      <title>Alibi Atlas: A Continuity Workbench for Fiction</title>
      <dc:creator>Hyunsik Park</dc:creator>
      <pubDate>Sat, 03 Oct 2026 09:22:23 +0000</pubDate>
      <link>https://dev.to/hyunsik_park_7c24c2e4f4fc/alibi-atlas-a-continuity-workbench-for-fiction-2gej</link>
      <guid>https://dev.to/hyunsik_park_7c24c2e4f4fc/alibi-atlas-a-continuity-workbench-for-fiction-2gej</guid>
      <description>&lt;p&gt;&lt;em&gt;An entry for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge — Path Two&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Alibi Atlas is a continuity workbench for fiction. It asks a narrow question: can a character be where the scene puts them?&lt;/p&gt;

&lt;p&gt;The starter case, &lt;strong&gt;The missing lantern&lt;/strong&gt;, has three characters, four places and six events. Mira appears at the archive and the dock at overlapping times. Theo has four minutes to make a ten-minute journey. Jules says they visited the dock, but that statement is not treated as an established scene.&lt;/p&gt;

&lt;p&gt;The app puts physical conflicts beside a timeline and a diagram of authored routes. Select an event, try different times or a different place, and see which conflicts remain. These preview changes stay in the browser; they do not rewrite the author's Sanity content.&lt;/p&gt;

&lt;p&gt;It is a tool for checking a fictional draft, not for deciding whether a real person's account is truthful.&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://hyunsikparker.github.io/alibi-atlas/" rel="noopener noreferrer"&gt;Open Alibi Atlas&lt;/a&gt; — no login needed.&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%2Fyz37g2pp4dhpf7bky2bh.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%2Fyz37g2pp4dhpf7bky2bh.jpg" alt="The published story contains two planted continuity errors" width="800" height="982"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try this short walkthrough:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;Checks the departing boat&lt;/strong&gt;. Change its time to &lt;strong&gt;18:34–18:44&lt;/strong&gt;, then choose &lt;strong&gt;Apply to preview&lt;/strong&gt;. Mira's overlap is resolved, with enough time for the eight-minute journey.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Delivers to the keeper&lt;/strong&gt; and try &lt;strong&gt;18:30–18:38&lt;/strong&gt;. The second physical conflict disappears.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Jules's account needs a decision&lt;/strong&gt;. Change it to &lt;strong&gt;This happens in the story&lt;/strong&gt;. A new overlap appears: the keeper is now established at the tower and the dock at the same time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reset preview&lt;/strong&gt; restores the loaded story. &lt;strong&gt;Inspect report JSON&lt;/strong&gt; shows the case, changes, findings and source metadata for inspection or manual copying.&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%2F0gvd7m0cjvjzlikb3ecb.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%2F0gvd7m0cjvjzlikb3ecb.jpg" alt="Two preview corrections remove the physical conflicts; the reported account stays separate" width="800" height="1006"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/HyunsikParker/alibi-atlas/blob/main/docs/preview-example.json" rel="noopener noreferrer"&gt;Example preview report&lt;/a&gt; · &lt;a href="https://github.com/HyunsikParker/alibi-atlas/blob/main/docs/mobile.jpg" rel="noopener noreferrer"&gt;390px layout&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://github.com/HyunsikParker/alibi-atlas" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; — MIT licensed, with local setup, Studio instructions and tests.&lt;/p&gt;

&lt;p&gt;The public viewer is a Next.js static export on GitHub Pages. It reads the real public Sanity dataset through &lt;code&gt;@sanity/client&lt;/code&gt;. Studio runs separately for authenticated authoring. No write token is bundled into the viewer, and there is no runtime AI call.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Build Process
&lt;/h2&gt;

&lt;p&gt;Codex generated and revised the implementation, fictional case, documentation and this article. This is a record of an autonomous AI build, not a claim that I wrote the code by hand or a verbatim prompt transcript.&lt;/p&gt;

&lt;h3&gt;
  
  
  The brief and the schema
&lt;/h3&gt;

&lt;p&gt;The working brief, paraphrased, was to build a fiction-continuity editor backed by real Sanity content. Characters, places, journeys and scenes needed their own documents. A character's statement had to remain separate from an event established by the author. Readers needed to test corrections without changing the published story.&lt;/p&gt;

&lt;p&gt;That distinction became an explicit &lt;code&gt;certainty&lt;/code&gt; field rather than something inferred from the wording of a scene. Each event also keeps the author's scene or dialogue note visible in the inspector.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Document&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;th&gt;What it records&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Character&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Name and role&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Place&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Name and diagram coordinates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Journey&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Two place references and a minimum time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Story event&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Character, place, interval, certainty and source note&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Case&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Time window and references to the other documents&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The case references those documents instead of storing the story as one block of prose. A GROQ query dereferences them into the graph used by the workbench. Journey times are authored constraints, not estimates from map coordinates. The analysis uses the shortest connected, undirected route; a missing route stays unknown and appears as a review item.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where the early attempts broke
&lt;/h3&gt;

&lt;p&gt;An initial-value resolver tried to use &lt;code&gt;context.documentId&lt;/code&gt;. TypeScript rejected that API. The replacement uses fixed starter IDs and explicit initial-value templates. The starter tool creates the 18 linked documents through the authenticated Studio client and reads them back without overwriting existing documents.&lt;/p&gt;

&lt;p&gt;The first architecture put Studio inside the Next.js app. It was separated so the public reader could be a static export while authoring retained its authenticated session. This build uses the Sanity client and Studio, not the App SDK or Sanity Workflows.&lt;/p&gt;

&lt;p&gt;The first all-clear wording was too strong when a route could be missing. It now says only that no physical conflicts were detected under the authored constraints. Unknown journeys still need review.&lt;/p&gt;

&lt;p&gt;Browser checks also caught a stale validation message after reset. Reset now starts a fresh inspector without remounting it on every input change. The time-input automation changed displayed values without updating React until native key input was used; the final correction checks used keyboard input.&lt;/p&gt;

&lt;h3&gt;
  
  
  What was checked
&lt;/h3&gt;

&lt;p&gt;All 12 domain tests passed, including nested overlaps, route choice, reported accounts, missing routes and invalid references or intervals. The public Pages workflow passed tests, type checking, the static build and deployment. At 390px, the page had no horizontal overflow; the timeline scrolls inside its own container.&lt;/p&gt;

&lt;p&gt;A published description change produced the live-update notice and kept an in-progress preview. An actual Studio event edit reduced the public viewer from two physical conflicts to one after refresh, without preview edits. That test edit was then restored. A complete case readback matched the pre-test snapshot, and the dataset again contained the original 18 documents.&lt;/p&gt;

&lt;p&gt;The visible report was read back with two preview edits, zero physical conflicts and one reported-account review. Browser automation did not confirm a completed file download or clipboard contents, so neither is claimed from the buttons alone. The inspectable JSON and linked example make the payload available directly. The controller also stalled on a dirty-preview refresh confirmation; a separate reader verified the new published content, and clean-preview refresh worked.&lt;/p&gt;

&lt;p&gt;The prototype handles one case and one time window. It does not infer travel times, prove a statement is true or review every kind of plot hole. The aim is to expose contradictions the author can inspect, with the underlying event and source note still visible.&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;0k0a3q37&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset:&lt;/strong&gt; &lt;code&gt;production&lt;/code&gt; — public, original fictional demonstration content only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Published documents:&lt;/strong&gt; 18 across the five schema types above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The viewer queries published content without a token. Sanity remains the authoring source: publishing a change raises a notice, and the reader chooses when to reload it. A connected query failure shows an error instead of silently substituting the local fixture.&lt;/p&gt;

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