Enforcing Hard Constraints
Define constraints as an explicit, checkable spec before generating any content:
YAMLconstraints: length: max_words: 150 min_words: 100 format: structure: "bullet list" required_sections: ["Problem", "Solution", "Next Steps"] variables: allowed_fields: ["name", "date", "amount"] forbidden_terms: ["guarantee", "promise", "always"] tone: register: "formal, neutral" forbidden: ["sarcasm", "humor", "superlatives"]
Generate output, then validate against each constraint. If any limit is breached, regenerate only the violating portion — don't discard the whole output.
Progress:
- Step 1: Extract or elicit the hard limits (length, format, variables, tone) from the task
- Step 2: Encode limits as a machine-checkable spec (numbers, enums, regex, allowed lists)
- Step 3: Generate a draft response
- Step 4: Run a constraint check pass — treat it like a redline gauge, not a suggestion
- Step 5: If any constraint is violated, trim/rewrite the specific violating segment
- Step 6: Re-check until all constraints pass simultaneously
- Step 7: Report which constraints were binding (near the limit) vs. slack
Step 1 — Extract limits. Ask: what breaks the system if exceeded? Length overruns break UI/UX or token budgets. Format violations break downstream parsers. Disallowed variables break data contracts. Wrong tone breaks brand/trust. Each is a "redline."
Step 2 — Encode, don't eyeball. Convert vague instructions ("keep it short", "stay professional") into numeric or enumerable checks:
- "short" → max_words: 150
- "professional" → forbidden word list + sentence-length cap + no emoji/exclamation marks
- "use only these variables" → explicit allow-list, reject anything else
Step 3–4 — Generate, then inspect, separately. Never trust generation alone to self-regulate. Run a dedicated check pass: count words, scan for forbidden terms, verify structure matches template, confirm tone markers.
Step 5–6 — Localized repair. Like an engine governor cutting fuel only when RPM redlines (not shutting off entirely), fix only the offending clause/section rather than regenerating from scratch.
Step 7 — Report margins. State which constraints were tight (e.g., "148/150 words") so the user knows how much headroom exists — this surfaces when limits are too tight for the content and need renegotiating.
Example 1: Input: "Write a customer apology email. Max 80 words. Must include: acknowledgment, cause, fix, no promises of future perfection. Tone: sincere, not groveling." Output:
Subject: Regarding Your Recent Order Delay
We're sorry your order arrived four days late. The delay was caused
by a warehouse system outage on our end, not a fault of yours.
We've issued a full refund for shipping and flagged your account
for priority handling on your next order.
Thank you for your patience.
— The Fulfillment Team
(Word count: 58/80 — within limit; no "promise/always/guarantee" language; structure matches required sections.)
Example 2: Input: "Generate a JSON record using only fields: id, status, timestamp. Status must be one of [pending, active, closed]." Output:
JSON{"id": "A1029", "status": "active", "timestamp": "2024-03-11T14:02:00Z"}
Rejected draft (caught in check pass): {"id": "A1029", "status": "in progress", ...} — "in progress" is not in the allowed enum; corrected to "active".
- Always convert soft language ("concise", "friendly") into hard, checkable numbers or lists before generating.
- Validate in a separate pass from generation — self-grading during writing is unreliable.
- Repair locally; don't regenerate the whole output for one violated line.
- Surface how close output is to each limit — near-limit = fragile, worth flagging.
- When constraints conflict (e.g., required sections won't fit in word limit), report the conflict instead of silently violating one.
- Treating constraints as suggestions that can be "mostly" honored — a redline exists because crossing it causes failure, not degradation.
- Checking only the easiest constraint (e.g., length) while ignoring tone or variable restrictions.
- Rewriting the entire response after one small violation, introducing new, unchecked risk.
- Leaving constraints implicit/vague, making the check pass impossible to automate or verify.
- Failing to report when constraints are mutually incompatible, producing an output that quietly breaks one rule to satisfy another.