TypeGlish 0.9.0: the deadline meets the duration
Your prompt has always been able to promise a deadline. As of this release it can also state how long the work actually takes, in a way the solver reads. When those two disagree, that is not a wording problem any more. It is two blocking errors.
TL;DR 0.9.0 lands the clock-containment arc, and the half you will feel is the takes frame: A refund takes 5 days. is typed time now, not prose, so it collides with the rule that promises a two-day resolution. That pair is 2 blocking logic/time errors on one refund · duration slot, and the identical six-line file checks 0 error on 0.7.2. Exactly four completion verbs put a deadline on that slot: resolve, close, finish, complete. The release also ships five follow-ups to the @{name} pointer SSOT. One upgrade note that matters more than usual: 0.8.0 and 0.8.1 never reached npm, so expect new findings to appear. npm i -D typeglish@latest.
Every contact centre runs two clocks. One is the process: a refund clears in five days, a chargeback in forty-five, an escalation in two hours, and those numbers come from ops. The other is the promise the agent makes on the call, and it comes from the prompt. When we pulled apart a real response-time section in two clocks on the same promise, the checker could already prove that two promises disagreed. What it could not read was the sentence that says how long the work needs, because that sentence is a statement of fact and facts were prose. 0.9.0 closes exactly that gap, and it turns out to be the gap the customer hears about.
§1A statement of fact is typed time now
Here is a six-line billing prompt with nothing unusual in it. One line records what ops told you. The next line is the deadline somebody wrote into the policy. Read them in order and the problem is obvious to a human; the point is that nothing in the toolchain used to say so.
# Role You are a billing support agent for Acme. # Constraints - A refund takes 5 days. - You MUST resolve a refund within 2 days. - NEVER state a specific price.
refund, which turns out to be enough.On 0.9.0 the two lines land on one slot and the proof is short:
refunds.tg:4:1 error logic/time Conflicts with line 5. Time conflict — "takes 5 days" and "within 2 days" cannot both bound "refund · duration": the windows never intersect. refunds.tg:5:1 error logic/time Conflicts with line 4. Time conflict — "takes 5 days" and "within 2 days" cannot both bound "refund · duration": the windows never intersect. ✗ 1 file — 2 error, 0 warning, 0 info
refund · duration. The subject of takes became a slot, and the deadline in line 5 is a bound on that same slot. Two intervals that never intersect is the oldest proof in the checker; what is new is that a declarative sentence was allowed to carry one.Now run the byte-identical file on the previous version anyone could install:
✓ 1 file — 0 error, 0 warning, 0 info
The fix is not a syntax repair, which is the part worth sitting with. The checker has handed you a policy decision: either ops is wrong about five days, or the promise has to change. Change the promise and the file goes quiet.
# Role You are a billing support agent for Acme. # Constraints - A refund takes 5 days. - You MUST resolve a refund within 7 days. - NEVER state a specific price.
Why this matters more than its size suggests: the five-day number was already the most reliable fact in the building, and it was the one fact the prompt could not be held to. A rule that promises two days does not become true because ops disagrees quietly. It becomes a transcript where your agent commits the company to something the process cannot do, which is the same failure mode as promising the refund instead of issuing it, arriving one layer down.
§2Four words open the door
The obvious question is which rules get checked against a takes line, and the answer is narrow enough to be worth memorizing. A deadline lands on the same · duration slot when its verb is one of four completion verbs: resolve, close, finish, complete. Against A refund takes 5 days., each of those written within 2 days returns the same 2 blocking errors.
Eight other verbs we tried on the identical shape stay silent: process, handle, issue, send, approve, deliver, answer, escalate. That reads like a gap and is mostly the right call, because issuing a refund and a refund completing are genuinely two different events, and only one of them takes five days. It does mean the collision is caught when your rule is about finishing the work, and missed when your rule is about starting it. If you want the check, write the verb that means done.
One real boundary, since it cost us a guess. The frame crosses with within and under, and not with at most or at least. Onboarding takes 2 weeks. beside Onboarding takes at most 3 days. checks at 0 error, 0 warning, 0 info, even though two weeks plainly does not fit in three days. Two takes statements do cross, and they cross units correctly: takes 2 weeks beside takes 3 days is 2 blocking errors. So the shape to write today is within, and the shape to not rely on yet is at most pointed at a duration you stated elsewhere.
§3The window half was already yours
The changelog files this release as one arc, window containment plus the takes frame, and honesty requires splitting them. Schedules were already typed time on 0.7.2, and they behave identically on 0.9.0 in every shape we could build. Worth showing anyway, because a lot of people are still writing business hours as prose and do not know the checker reads them.
# Role You are a scheduling agent for Acme. # Constraints - The desk is open from 9am to 5pm UTC. - The desk is open at 7pm UTC.
"from 9am to 5pm UTC" and "at 7pm UTC" put two times on one "desk · open" slot; a slot holds one time per scope. Guard one with IF (different days or conditions) or remove one. Two blocking errors, on 0.9.0 and on 0.7.2 alike.Swap 7pm for 10am and the same file checks clean, which is containment stated as behavior rather than as a feature name: a time inside the declared window is not a second schedule, it is the schedule being kept.
# Role You are a scheduling agent for Acme. # Constraints - The desk is open from 9am to 5pm UTC. - The desk is open at 10am UTC.
UTC on both lines, which is not decoration. Drop it and the file picks up prompt/naive-time, the info that says your prompt states clock times and never fixes a zone, so the model guesses one at runtime. That is its own failure mode, and it is the reason every clock example here is qualified.§4Pointers: five follow-ups, and a code you have never seen
The other entry in this changelog is a fix set: the five pointer-SSOT follow-ups, named the mask, the scan, the shadow, the receipt and the refusal. We are quoting rather than decoding, because matching five internal names to five behaviors from the outside would be guessing, and this blog does not do that. What we can show is the shape of the thing they harden, and why it is arriving in your terminal now.
@{name} is the one pointer grammar, and a pointer name begins with a letter. Write a hyphen in one and 0.9.0 stops the build:
# Role You are a support agent for @{customer-id}.
The renderer cannot read it either, so the model receives this line with the compile-time @ still on it. Rename the symbol — @{customer_id} is the mechanical rewrite. A pointer-shaped name splits two ways and both land on this code: the ones the renderer still expands, which reach the model as a {placeholder} nothing can fill, and the ones it cannot read at all, which reach the model with the @ attached. Either way the customer sees it.On 0.7.2 that identical file is 0 error, 0 warning, 0 info, and the reason is the subject of the next section.
§5Two versions you were never offered
This upgrade is wider than its version bump. The published history skips a minor:
0.2.0 0.2.1 0.2.2 0.2.3 0.3.0 0.4.0 0.5.0 0.6.0 0.7.0 0.7.1 0.7.2 0.9.0
npm view output, which prints one version per line. 0.8.0 and 0.8.1 are in the changelog and were never published, which the 0.7.2 notes half-predicted when they recorded a 0.8.0 being walked back. So the jump from the newest version you could install is three releases, not one.That is why structure/bad-pointer-name reads as brand new from npm even though the pointer SSOT itself landed in 0.8.0. The same is true of everything else 0.8.0 carried, and the changelog is the honest inventory of it rather than this post, which is about 0.9.0.
The practical consequence, stated plainly: unlike 0.7.2, which spent its release notes giving findings back, this one adds them. A prompt you have not touched can start failing, and the two families it fails in are a deadline that outruns a duration you stated yourself, and a pointer name that was already broken on the way to the model. Both are worth the red build. Neither is a reason to be surprised by it at 9am on a Monday.
npm i -D typeglish@latest # 0.9.0 npx typeglish@latest check prompts/ # do this before you trust exit codes in CI npx typeglish@latest --explain logic/time
Energy check: this is one feature arc and one fix set, which is a focused release, not a landmark. It reads bigger than it is only because it crosses two versions that never shipped to npm. Method: we installed the published 0.7.2 and 0.9.0 tarballs and ran the real CLI over the same files, so every before and after here is a diff between two shipped builds rather than a benchmark, and the counts quoted (2 errors, 0 errors, 4 verbs, 8 silent verbs) are from those runs. Three things we deliberately did not claim. We could not demonstrate any behavioral change in the window half of the arc: every schedule and containment shape we built behaves the same on both builds, so we describe windows as existing rather than as new. We do not say which of the five pointer follow-ups is the mask, the scan, the shadow, the receipt or the refusal, because from the outside that would be invention. And one rough edge found while writing this, reported here rather than dressed up: the cited line number in a conflict message counts non-blank lines, so if you put a blank line above your rules the message says a line number one off from the one your editor shows. The diagnostics themselves land on the right lines. The full changelog lives on GitHub.
FAQQuestions about 0.9.0
- What is the takes frame?
- A reading of the verb
takesthat puts a plain statement of fact into the time layer. Before 0.9.0 a duration only reached the solver through a bound word on a directive:within 30 minutes,at most 2 hours. A sentence likeA refund takes 5 days.was prose. As of 0.9.0 it fills a duration slot named after its subject,refund · duration, so it can be checked against anything else that bounds the same slot. In practice: the sentence describing your process and the rule promising a deadline finally meet. - Which verbs put a deadline on the same slot as
takes? - Four completion verbs:
resolve,close,finish,complete. AgainstA refund takes 5 days., each of them writtenwithin 2 daysreturns 2 blockinglogic/timeerrors onrefund · duration. Verbs that name a different act stay silent:process,handle,issue,send,approve,deliver,answerandescalateall check clean against the same line. That is defensible, because issuing a refund and the refund completing are two different events, but it means the checker catches the collision only when your rule is really about finishing the work. - Will 0.9.0 fire new errors on prompts I already wrote?
- Yes, and that is the difference between this release and 0.7.2. The takes frame reads sentences that were previously prose, so a file you have shipped for months can start returning blocking errors with no edit from you. The example in §1 is six lines and returns 0 error on 0.7.2 and 2 error on 0.9.0. Run
npx typeglish@latest check prompts/before you upgrade a pipeline that gates on the exit code. - Why did my
at mostrule not conflict withtakes? - Because the frame crosses with
withinandunder, not withat mostorat least.Onboarding takes 2 weeks.besideOnboarding takes at most 3 days.checks at 0 error, 0 warning, 0 info on 0.9.0, even though two weeks cannot fit inside three days. Twotakesstatements do cross, including across units:takes 2 weeksbesidetakes 3 daysis 2 blocking errors. Writewithinif you want the promise checked today. - Did schedule and business-hours checking change?
- Not in any shape we could construct. Windows were already typed time on 0.7.2 and behave identically on 0.9.0: two windows on one slot conflict, a clock time outside a declared window conflicts, and a clock time inside it checks clean.
The desk is open from 9am to 5pm UTC.besideThe desk is open at 7pm UTC.is 2 blocking errors on both builds; the same pair with10amis clean on both. The changelog files window containment and the takes frame under one arc, and the takes frame is the half with a delta we can demonstrate. - What happened to 0.8.0 and 0.8.1?
- They exist in the changelog and never reached npm:
npm view typeglish versionsgoes 0.7.0, 0.7.1, 0.7.2, then 0.9.0. So this upgrade crosses three releases. The pointer work is the visible consequence: THE POINTER SSOT landed in 0.8.0 with one@{name}grammar, 0.9.0 adds five follow-ups to it, and the net effect for an npm user is thatstructure/bad-pointer-nameis a blocking code they have never seen.@{customer-id}is silent on 0.7.2 and one blocking error on 0.9.0. - Should I upgrade?
- Yes, with one deliberate step:
npm i -D typeglish@latest, then runcheckacross your prompts before you trust the exit code in CI. Expect findings to appear rather than disappear, which is the reverse of the 0.7.2 upgrade. The new errors fall into two families that are both worth having: a deadline that outruns a duration you stated yourself, and a pointer name the compiler cannot read, which was reaching your model broken either way.