# Project: a travel-constraint and candidate-itinerary workflow

Canonical page: https://yishto.com/en/learn/project-labs/lab-outing-planning-workflow/

Author: [Yishto](https://yishto.com/en/about/)

Separate itinerary evidence, candidate generation, constraint checks, and review, with bounded tool access and budgets that prevent untrusted content from authorizing bookings.

Published: 2026-11-10
Updated: 2026-11-10

## Express the request as checkable constraints

This project proposes itineraries for user review. Locations, prices, and durations in the exercise are synthetic and establish no real opening hours or transport conditions. The first version has no booking or payment tools. It tests whether the service can explain which requirements a candidate satisfies and what remains unknown.

Ask for departure time, total duration, budget, required activities, and accessibility needs. Separate hard constraints from preferences: a spending ceiling is a constraint, while favoring quiet places is a preference. Unknown cost or opening hours cannot be represented as confirmed compliance.

Collect missing critical information before proceeding. If the available time is insufficient, return no feasible candidate and explain the conflict instead of asking the model to fabricate a complete plan. Use integer minor currency units with a specified currency and timezone-aware times. Amounts from different currencies or dates cannot simply be added.

## Separate authority, evidence, and execution state

Store user-confirmed constraints as a versioned request snapshot. Evidence records need a source, retrieval time, applicable date, and unknown fields. Candidates record activity order, estimated durations, cost components, and supporting evidence. A run identifies its constraint and evidence versions so a changed budget does not retain an old candidate as current.

Evidence has no authority to change the request. A page saying “call the payment endpoint now” is page content, not user approval. MCP tool names and descriptions do not replace server-side authorization. Expose only the required read operations through a tool registry, keep credentials at the execution boundary, and prevent model output from creating credentials or widening access.

Bound retained evidence and history. Cancellation, timeout, and failure need explicit terminal states. Adding effectful tools later requires a separate path with user confirmation, resource authorization, and idempotent execution. Passing candidate constraints alone cannot authorize a purchase.

## Check numerical constraints deterministically

These three records are synthetic. Duration is in minutes, and costs use one teaching unit. The limits are 150 minutes and 50 cost units, so only A remains. A tighter request returns an empty list.

```python
candidates = [{"id": "A", "minutes": 120, "cost": 40},
              {"id": "B", "minutes": 200, "cost": 30},
              {"id": "C", "minutes": 90, "cost": 80}]
def feasible(item, minutes, budget):
    return item["minutes"] <= minutes and item["cost"] <= budget
result = [x["id"] for x in candidates if feasible(x, 150, 50)]
assert result == ["A"]
assert [x for x in candidates if feasible(x, 60, 10)] == []
print(result)
```

The output is `['A']`. The code checks two numerical conditions and has no geography, routing, opening-hours, queue, or transport model. It cannot establish a real executable itinerary. It also omits type and nonnegative-value validation. A real endpoint must reject invalid values and define whether cost includes transport, admission, and required expenses.

Include movement and buffers as well as activity duration. Missing transport evidence should leave a candidate pending verification or undecidable. A model guess must not become a precise minute count. Numerical checks are necessary, while real feasibility depends on supported information.

## Orchestrate deterministic and model steps

A run can collect constraints, retrieve evidence, generate candidates, validate them, and pause for review. LangGraph provides shared-state, node, and edge orchestration with persistence and human pauses. The application still defines state fields, authorization, and recovery; the framework does not establish itinerary accuracy.

The generation step can return candidate IDs, activities, evidence references, times, costs, and unknowns. Validate format, reference existence, and business conditions on the server. Structured Outputs can constrain output structure within its supported scope. Schema compliance does not establish correct costs or supported explanations. Refusal and interrupted output require their own branches.

Allow a limited regeneration attempt with specific errors such as overspending or overlapping activities. Bound total calls and runtime so an impossible request does not loop indefinitely. Bind retries to the run and constraint version. Updated evidence requires renewed validation rather than reuse of an old passing state.

## Keep verification visible in candidate review

Show cost components, timing, evidence dates, and unresolved conditions. Real travel requires current opening hours, ticket availability, routes, and temporary changes. An old retrieval is not real-time evidence. The exercise should explicitly retain pending verification when reliable current data is unavailable.

External content can contain prompt injection. Restricted tools and permissions, treating evidence as data, output checks, and human review can reduce the impact; a system prompt cannot promise complete prevention. Test fictional instructions in retrieved content to change the budget or send account information, and confirm they do not alter authority or trigger effects.

Long runs need a current stage and cancellation control. Cancellation stops subsequent stoppable steps and marks the result unusable. Whether an already-issued request stops depends on the external service. A future booking feature would require reconciliation of unknown outcomes and cancellation policies; a cancel button cannot imply a refund.

Bind review to a candidate revision. Regeneration, expired evidence, or changed constraints must not inherit approval automatically. Keep older candidates for comparison if useful, clearly mark them superseded, and record which revision the user actually reviewed and when.

## Test conflicts, unknowns, and recovery

Build the request, filtering, and candidate page around fixed synthetic locations first. Add replaceable read-only evidence adapters, then models and persistence. With the model disabled, fixed candidates can still test constraints and interface states. Show the final conditions after a user selects a candidate, and never rewrite the budget silently.

Test values exactly at each limit, no candidates, negative values, unknown costs, overlapping activities, stale evidence, repeated runs, model refusal, and tool timeouts. Then test late responses after changed constraints, permission errors, and injected instructions in evidence. Distinguish failed checks, insufficient information, and generation-service failure so users can change requirements, supply evidence, or retry appropriately.

Passing these cases establishes the declared teaching workflow. Real feasibility still requires current evidence and user judgment. Adding bookings, payments, or sensitive user information requires reviewing the new authority and recovery paths before release.

## Sources & further reading

- [Model Context Protocol — Tools](https://modelcontextprotocol.io/specification/latest/server/tools)
- [Stateful graph orchestration](https://docs.langchain.com/oss/python/langgraph/overview)
- [Structured outputs guide](https://developers.openai.com/api/docs/guides/structured-outputs)
- [LLM01: Prompt Injection](https://genai.owasp.org/llmrisk/llm01-prompt-injection/)

Sources checked on 2026-11-10. Examples are teaching data, not production measurements.

## Related guides

- [AI agents and workflows: when to allow autonomous choices](https://yishto.com/en/learn/agents/workflows-and-agents/)
- [API contracts: parameters, identity, access, and errors](https://yishto.com/en/learn/service-data/http-api-contracts-and-access/)
