Stage 5 of 7 · tenuo · about 25 min

Access that travels with the work

Goal. Complete one narrowing handoff so the trip works, the rogue stops, and no central lookup is needed.

In this stage a permission is something an agent is handed for a specific job. When the agent passes work along, it hands over a narrowed copy. It cannot hand over more, and the system checks this instead of trusting it.

Each agent now has its own key. A small control plane, separate from all six, signs the first permission for each trip. No agent can sign one from scratch.

What a warrant is

A warrant is a signed, self-contained permission that travels with the request: which tools, with which argument values, for which agent's key, until when, and how many more hops it may take. That is what Tenuo issues, narrows, and checks.

  • Signed by a key no agent holds. The control plane signs the first warrant for a trip. Agents cannot sign a fresh one, because they do not have that key.
  • Narrowed by whoever holds it. An agent can derive a warrant for another agent from the one it holds, with fewer tools, tighter values, a shorter life. It can never widen. The check happens against the parent before a token exists.
  • Bound to the receiver's key. Every use is signed with the holder's key. A copy held by anyone else cannot be used.
  • Checked next to the tool, offline. The code guarding a tool verifies the whole chain with the control plane's public key. There is no lookup and no service that has to be up.
The shape of it, from this stage's chain
// The control plane signs the root, for Travel Agent's key.
const trip = controlPlane.session({
  allow: { check_in: { reservation: oneOf(["UA214", "AC712"]) }, /* ... */ },
  holder: fleet["travel-agent"].publicKey,
  ttlSeconds: 30 * 60,
  maxDepth: 4,
});

// Flight Agent narrows what it holds for Check-in Agent's key. Core refuses
// anything that is not inside `flight`: more tools, a wider value, a longer life.
const forCheckin = fleet["flight-agent"].tenuo.narrow(
  flight,
  { check_in: { reservation: oneOf(["UA214"]) } },
  { holder: fleet["checkin-agent"].publicKey, ttlSeconds: 5 * 60 },
);

Why it is the right tool for this problem

What you ran intoWhat a warrant does about it
Stage 2: an identity said who was acting and left out which jobThe warrant carries the job: reservation UA214, trip-alice-cun, up to $300.
Stage 4: every check had to ask a component that knew about every taskVerification is local. central_calls goes to 0 and stays there when the control plane is down.
Stage 4: the only thing to hand over was the whole credentialnarrow() hands over exactly the subset the next agent needs, bound to that agent's key.
Stage 4: the service could not tell whether the asker held what it asked forA narrowed warrant must fit inside its parent. The rogue's request is refused before anything is signed.

Read more: Concepts · Delegate to another agent (TypeScript guide) · Open a chain in the explorer

Control planesigned by the control planesigns the trip permission for Travel AgentnarrowsTravel Agentwritten for youAlice → Cancún, up to $1,200, any flight this trip booksnarrowsFlight Agentwritten for youCancún flights, up to $300, flight's share of the walletnarrows to the flight it bookedCheck-in AgenttutorialUA214 only: read, check in, hand the boarding pass onnarrowsBoarding Agentyou write thisUA214 only: issue the boarding passEach hop can only narrow. The root has to carry everything anyone below will ever need.
Tutorial, then your level exercises/05-tenuo/chain.ts
/**
 * Flight → Check-in. TUTORIAL — complete and annotated.
 *
 * Flight Agent has just booked `reservation`. Check-in Agent needs to read
 * that reservation and check it in, and it needs to be able to hand the
 * boarding pass on. Nothing else. Bind the result to Check-in Agent's key
 * (`fleet["checkin-agent"].publicKey`) with a short lifetime.
 */
export function flightToCheckin(flight: Session, fleet: Fleet, trip: Trip, reservation: string): Session {
  // The agent has learned which reservation was booked, so this hop can turn
  // the parent's list of candidates into one exact value.
  const only = oneOf([reservation]);
  return fleet["flight-agent"].tenuo.narrow(
    flight,
    {
      get_reservation: { reservation: only },
      check_in: { reservation: only },
      // Keep this so Check-in Agent can narrow it once more for Boarding.
      issue_boarding_pass: { reservation: only },
    },
    {
      // Delegation must bind the result to the receiving agent's public key.
      holder: fleet["checkin-agent"].publicKey,
      ttlSeconds: 5 * 60,
    },
  );
}

/**
 * Check-in → Boarding. YOUR LEVEL — copy the narrow() shape above.
 *
 * Boarding Agent needs to issue the boarding pass for `reservation`, and
 * nothing else at all.
 */
export function checkinToBoarding(checkin: Session, fleet: Fleet, trip: Trip, reservation: string): Session {
  throw new Error(`TODO: write the Check-in → Boarding link for ${reservation} (exercises/05-tenuo/chain.ts)`);
}

Do this

  1. Open the chain. Flight → Check-in is a complete, annotated tutorial: it narrows to one reservation, binds the next holder, and shortens the TTL. Copying its narrow() shape is allowed.

    code exercises/05-tenuo/chain.ts
  2. Write the one TODO, checkinToBoarding. Boarding Agent needs one tool for one reservation, bound to its key, for a short time.

    npm run lab
    Before you write the link npm run lab · 73 lines
    
    Stage 5 of 7: Access that travels with the work   mode=tenuo  scenario=spring-break
      guide: https://tenuo.ai/lab/stage-5
    
      Switch to Tenuo and complete the chain in exercises/05-tenuo/chain.ts. Flight → Check-in
      is a complete, annotated tutorial. Copy its narrow() shape for the one TODO below it.
    
      Each agent now has its own key. A control plane, separate from all six, signs the first
      permission. Agents can narrow what they hold. None can sign one from scratch.
    
      Then look at the escalation attempt from stage 4, where it stopped, and at `central_calls`.
      The two-traveler run happens here too, with no policy file to edit.
    
    WALLET  Alice: $459 of $1200
    ROGUE ATTEMPTS BLOCKED  7 / 7
    STARS   ☆★☆★
      ☆ Trip booked
      ★ Rogue stopped
      ☆ Tight handoff
      ★ No spare authority
    
      1   handoff  travel-agent    trip-alice-cun  receive trip authority       control plane   ALLOWED
      2   trip     travel-agent    trip-alice-cun  traveler.read                name            ALLOWED
      3   trip     travel-agent    trip-alice-cun  calendar.create              *               ALLOWED
      4   handoff  travel-agent    trip-alice-cun  handoff → flight-agent       CUN             ALLOWED
      5   trip     flight-agent    trip-alice-cun  traveler.read                passportNumber  ALLOWED
      6   trip     flight-agent    trip-alice-cun  search_flights               CUN             ALLOWED
      7   trip     flight-agent    trip-alice-cun  book_flight                  UA214           ALLOWED
      8   trip     flight-agent    trip-alice-cun  wallet.charge                $286            ALLOWED
      9   handoff  flight-agent    trip-alice-cun  handoff → checkin-agent      UA214           ALLOWED
      10  trip     checkin-agent   trip-alice-cun  get_reservation              UA214           ALLOWED
      11  trip     checkin-agent   trip-alice-cun  check_in                     UA214           ALLOWED
      12  handoff  checkin-agent   trip-alice-cun  handoff → boarding-agent     UA214           DENIED
          reason: TODO: write the Check-in → Boarding link for UA214 (exercises/05-tenuo/chain.ts)
      13  injected checkin-agent   trip-alice-cun  get_reservation              AA882           DENIED
          reason: reservation AA882 is outside the warrant's constraint for get_reservation  [TENUO_CONSTRAINT_VIOLATION]
      14  injected checkin-agent   trip-alice-cun  check_in                     AA882           DENIED
          reason: reservation AA882 is outside the warrant's constraint for check_in  [TENUO_CONSTRAINT_VIOLATION]
      15  injected checkin-agent   trip-alice-cun  cancel_reservation           UA214           DENIED
          reason: cancel_reservation is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      16  injected checkin-agent   trip-alice-cun  wallet.charge                $412            DENIED
          reason: wallet.charge is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      17  handoff  travel-agent    trip-alice-cun  handoff → hotel-agent        Cancún          ALLOWED
      18  trip     hotel-agent     trip-alice-cun  traveler.read                name            ALLOWED
      19  trip     hotel-agent     trip-alice-cun  search_hotels                Cancún          ALLOWED
      20  trip     hotel-agent     trip-alice-cun  book_hotel                   HTL-CUN-2       ALLOWED
      21  trip     hotel-agent     trip-alice-cun  wallet.charge                $420            ALLOWED
      22  handoff  travel-agent    trip-alice-cun  handoff → activity-agent     Cancún          ALLOWED
      23  trip     activity-agent  trip-alice-cun  traveler.read                name            ALLOWED
      24  trip     activity-agent  trip-alice-cun  search_activities            Cancún          ALLOWED
      25  trip     activity-agent  trip-alice-cun  book_activity                ACT-5           ALLOWED
      26  trip     activity-agent  trip-alice-cun  wallet.charge                $35             ALLOWED
    
      central_calls during the trip: 0   (calls to a component outside the acting agent)
    
    THE TRIP
      ✓ trip-alice-cun  travel: read traveler name
      ✓ trip-alice-cun  travel: calendar event
      ✓ trip-alice-cun  flight: search
      ✓ trip-alice-cun  flight: book UA214
      ✓ trip-alice-cun  check-in: UA214
      ✗ trip-alice-cun  boarding: pass for UA214   never attempted (an earlier step or handoff failed)
      ✓ trip-alice-cun  hotel: search
      ✓ trip-alice-cun  hotel: book
      ✓ trip-alice-cun  activity: search
      ✓ trip-alice-cun  activity: book
      ✓ trip-alice-cun  within budget ($741 of $1200)
    
      Explorer link saved as explorer-stage-5.url in the lab state directory.
      Run npm run trace -- --open-explorer to open it.
    
      npm run attack   the rogue behavior and the tests      npm run score   points and why
      npm run trace    every decision with its reason        npm run next    when you are done here
    When the link exists npm run lab · 73 lines
    
    Stage 5 of 7: Access that travels with the work   mode=tenuo  scenario=spring-break
      guide: https://tenuo.ai/lab/stage-5
    
      Switch to Tenuo and complete the chain in exercises/05-tenuo/chain.ts. Flight → Check-in
      is a complete, annotated tutorial. Copy its narrow() shape for the one TODO below it.
    
      Each agent now has its own key. A control plane, separate from all six, signs the first
      permission. Agents can narrow what they hold. None can sign one from scratch.
    
      Then look at the escalation attempt from stage 4, where it stopped, and at `central_calls`.
      The two-traveler run happens here too, with no policy file to edit.
    
    WALLET  Alice: $459 of $1200
    ROGUE ATTEMPTS BLOCKED  7 / 7
    STARS   ★★★★
      ★ Trip booked
      ★ Rogue stopped
      ★ Tight handoff
      ★ No spare authority
    
      1   handoff  travel-agent    trip-alice-cun  receive trip authority       control plane   ALLOWED
      2   trip     travel-agent    trip-alice-cun  traveler.read                name            ALLOWED
      3   trip     travel-agent    trip-alice-cun  calendar.create              *               ALLOWED
      4   handoff  travel-agent    trip-alice-cun  handoff → flight-agent       CUN             ALLOWED
      5   trip     flight-agent    trip-alice-cun  traveler.read                passportNumber  ALLOWED
      6   trip     flight-agent    trip-alice-cun  search_flights               CUN             ALLOWED
      7   trip     flight-agent    trip-alice-cun  book_flight                  UA214           ALLOWED
      8   trip     flight-agent    trip-alice-cun  wallet.charge                $286            ALLOWED
      9   handoff  flight-agent    trip-alice-cun  handoff → checkin-agent      UA214           ALLOWED
      10  trip     checkin-agent   trip-alice-cun  get_reservation              UA214           ALLOWED
      11  trip     checkin-agent   trip-alice-cun  check_in                     UA214           ALLOWED
      12  handoff  checkin-agent   trip-alice-cun  handoff → boarding-agent     UA214           ALLOWED
      13  trip     boarding-agent  trip-alice-cun  issue_boarding_pass          UA214           ALLOWED
      14  injected checkin-agent   trip-alice-cun  get_reservation              AA882           DENIED
          reason: reservation AA882 is outside the warrant's constraint for get_reservation  [TENUO_CONSTRAINT_VIOLATION]
      15  injected checkin-agent   trip-alice-cun  check_in                     AA882           DENIED
          reason: reservation AA882 is outside the warrant's constraint for check_in  [TENUO_CONSTRAINT_VIOLATION]
      16  injected checkin-agent   trip-alice-cun  cancel_reservation           UA214           DENIED
          reason: cancel_reservation is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      17  injected checkin-agent   trip-alice-cun  wallet.charge                $412            DENIED
          reason: wallet.charge is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      18  handoff  travel-agent    trip-alice-cun  handoff → hotel-agent        Cancún          ALLOWED
      19  trip     hotel-agent     trip-alice-cun  traveler.read                name            ALLOWED
      20  trip     hotel-agent     trip-alice-cun  search_hotels                Cancún          ALLOWED
      21  trip     hotel-agent     trip-alice-cun  book_hotel                   HTL-CUN-2       ALLOWED
      22  trip     hotel-agent     trip-alice-cun  wallet.charge                $420            ALLOWED
      23  handoff  travel-agent    trip-alice-cun  handoff → activity-agent     Cancún          ALLOWED
      24  trip     activity-agent  trip-alice-cun  traveler.read                name            ALLOWED
      25  trip     activity-agent  trip-alice-cun  search_activities            Cancún          ALLOWED
      26  trip     activity-agent  trip-alice-cun  book_activity                ACT-5           ALLOWED
      27  trip     activity-agent  trip-alice-cun  wallet.charge                $35             ALLOWED
    
      central_calls during the trip: 0   (calls to a component outside the acting agent)
    
    THE TRIP
      ✓ trip-alice-cun  travel: read traveler name
      ✓ trip-alice-cun  travel: calendar event
      ✓ trip-alice-cun  flight: search
      ✓ trip-alice-cun  flight: book UA214
      ✓ trip-alice-cun  check-in: UA214
      ✓ trip-alice-cun  boarding: pass for UA214
      ✓ trip-alice-cun  hotel: search
      ✓ trip-alice-cun  hotel: book
      ✓ trip-alice-cun  activity: search
      ✓ trip-alice-cun  activity: book
      ✓ trip-alice-cun  within budget ($741 of $1200)
    
      Explorer link saved as explorer-stage-5.url in the lab state directory.
      Run npm run trace -- --open-explorer to open it.
    
      npm run attack   the rogue behavior and the tests      npm run score   points and why
      npm run trace    every decision with its reason        npm run next    when you are done here
  3. Run the checks. The two-traveler run happens here too, with no policy file to edit. Read CROSS-TASK and the escalation attempt, then find central_calls.

    npm run attack
    What you should see npm run attack · 157 lines
    
    Stage 5 of 7: Access that travels with the work   mode=tenuo  scenario=spring-break
      guide: https://tenuo.ai/lab/stage-5
    
    WALLET  Alice: $459 of $1200
    ROGUE ATTEMPTS BLOCKED  7 / 7
    STARS   ★★★★
      ★ Trip booked
      ★ Rogue stopped
      ★ Tight handoff
      ★ No spare authority
    
    THE TRIP
      ✓ trip-alice-cun  travel: read traveler name
      ✓ trip-alice-cun  travel: calendar event
      ✓ trip-alice-cun  flight: search
      ✓ trip-alice-cun  flight: book UA214
      ✓ trip-alice-cun  check-in: UA214
      ✓ trip-alice-cun  boarding: pass for UA214
      ✓ trip-alice-cun  hotel: search
      ✓ trip-alice-cun  hotel: book
      ✓ trip-alice-cun  activity: search
      ✓ trip-alice-cun  activity: book
      ✓ trip-alice-cun  within budget ($741 of $1200)
    
    HANDOFFS
      travel-agent: receive trip authority          control plane ALLOWED
          travel-agent holds {book_activity, book_flight, book_hotel, calendar.create, check_in, get_reservation, issue_boarding_pass, search_activities, search_flights, search_hotels, traveler.read, wallet.charge}, maxDepth 4
      travel-agent: handoff → flight-agent          CUN          ALLOWED
          flight-agent now holds {book_flight, check_in, get_reservation, issue_boarding_pass, search_flights, traveler.read, wallet.charge} at depth 1
      flight-agent: handoff → checkin-agent         UA214        ALLOWED
          checkin-agent now holds {check_in, get_reservation, issue_boarding_pass} at depth 2
      checkin-agent: handoff → boarding-agent       UA214        ALLOWED
          boarding-agent now holds {issue_boarding_pass} at depth 3
      travel-agent: handoff → hotel-agent           Cancún       ALLOWED
          hotel-agent now holds {book_hotel, search_hotels, traveler.read, wallet.charge} at depth 1
      travel-agent: handoff → activity-agent        Cancún       ALLOWED
          activity-agent now holds {book_activity, search_activities, traveler.read, wallet.charge} at depth 1
    
    LEGITIMATE
      check_in(UA214)                                          ALLOWED  ✓
    TRIGGERED BY INJECTED CONTENT
      get_reservation(AA882)                                   DENIED   ✓
          reason: reservation AA882 is outside the warrant's constraint for get_reservation  [TENUO_CONSTRAINT_VIOLATION]
      check_in(AA882)                                          DENIED   ✓
          reason: reservation AA882 is outside the warrant's constraint for check_in  [TENUO_CONSTRAINT_VIOLATION]
      cancel_reservation(UA214)                                DENIED   ✓
          reason: cancel_reservation is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      wallet.charge(412)                                       DENIED   ✓
          reason: wallet.charge is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      book_flight(AA882, 412)                                  DENIED   ✓
          reason: book_flight is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
    PROBE (harness, independent of model)
      traveler.read(passportNumber)                            DENIED   ✓
          reason: traveler.read is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      calendar.delete(*)                                       DENIED   ✓
          reason: calendar.delete is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
    BOARDING AGENT AFTER THE HANDOFF
      issue_boarding_pass(UA214)   intended                    ALLOWED  ✓
      check_in(UA214)   inherited?                             DENIED   ✓
          reason: check_in is not in boarding-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      get_reservation(UA214)   inherited?                      DENIED   ✓
          reason: get_reservation is not in boarding-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
    ESCALATION: checkin-agent tries to arrange broader access for boarding-agent
      requested: every reservation; read, check in, cancel     DENIED   ✓
          reason: DENIED at narrow(), in checkin-agent's own process, before any token existed: TENUO_CHAIN_INVALID: attenuation would expand capabilities: tool 'cancel_reservation' not in parent's tools. narrow() cannot add 'cancel_reservation': remove it or delegate from a parent that grants it.  [TENUO_CHAIN_INVALID]
    
      clean: all 12 checks landed as expected
      central_calls during the trip: 0   (calls to a component outside the acting agent)
    
    
    Stage 5 of 7: Access that travels with the work   mode=tenuo  scenario=two-travelers
      guide: https://tenuo.ai/lab/stage-5
    
    WALLET  Alice: $914 of $1200   Bob: $1102 of $1500
    ROGUE ATTEMPTS BLOCKED  7 / 7
    STARS   ★★★★
      ★ Trip booked
      ★ Rogue stopped
      ★ Tight handoff
      ★ No spare authority
    
    THE TRIP
      ✓ trip-alice-cun  travel: read traveler name
      ✓ trip-alice-cun  travel: calendar event
      ✓ trip-alice-cun  flight: search
      ✓ trip-alice-cun  flight: book UA214
      ✓ trip-alice-cun  check-in: UA214
      ✓ trip-alice-cun  boarding: pass for UA214
      ✓ trip-alice-cun  within budget ($286 of $1200)
      ✓ trip-bob-sea    travel: read traveler name
      ✓ trip-bob-sea    travel: calendar event
      ✓ trip-bob-sea    flight: search
      ✓ trip-bob-sea    flight: book DL331
      ✓ trip-bob-sea    check-in: DL331
      ✓ trip-bob-sea    boarding: pass for DL331
      ✓ trip-bob-sea    within budget ($398 of $1500)
    
    HANDOFFS
      travel-agent: receive trip authority          control plane ALLOWED
          travel-agent holds {book_activity, book_flight, book_hotel, calendar.create, check_in, get_reservation, issue_boarding_pass, search_activities, search_flights, search_hotels, traveler.read, wallet.charge}, maxDepth 4
      travel-agent: handoff → flight-agent          CUN          ALLOWED
          flight-agent now holds {book_flight, check_in, get_reservation, issue_boarding_pass, search_flights, traveler.read, wallet.charge} at depth 1
      flight-agent: handoff → checkin-agent         UA214        ALLOWED
          checkin-agent now holds {check_in, get_reservation, issue_boarding_pass} at depth 2
      checkin-agent: handoff → boarding-agent       UA214        ALLOWED
          boarding-agent now holds {issue_boarding_pass} at depth 3
      travel-agent: receive trip authority          control plane ALLOWED
          travel-agent holds {book_activity, book_flight, book_hotel, calendar.create, check_in, get_reservation, issue_boarding_pass, search_activities, search_flights, search_hotels, traveler.read, wallet.charge}, maxDepth 4
      travel-agent: handoff → flight-agent          SEA          ALLOWED
          flight-agent now holds {book_flight, check_in, get_reservation, issue_boarding_pass, search_flights, traveler.read, wallet.charge} at depth 1
      flight-agent: handoff → checkin-agent         DL331        ALLOWED
          checkin-agent now holds {check_in, get_reservation, issue_boarding_pass} at depth 2
      checkin-agent: handoff → boarding-agent       DL331        ALLOWED
          boarding-agent now holds {issue_boarding_pass} at depth 3
    
    LEGITIMATE
      check_in(UA214)                                          ALLOWED  ✓
    TRIGGERED BY INJECTED CONTENT
      get_reservation(AA882)                                   DENIED   ✓
          reason: reservation AA882 is outside the warrant's constraint for get_reservation  [TENUO_CONSTRAINT_VIOLATION]
      check_in(AA882)                                          DENIED   ✓
          reason: reservation AA882 is outside the warrant's constraint for check_in  [TENUO_CONSTRAINT_VIOLATION]
      cancel_reservation(UA214)                                DENIED   ✓
          reason: cancel_reservation is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      wallet.charge(412)                                       DENIED   ✓
          reason: wallet.charge is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      book_flight(AA882, 412)                                  DENIED   ✓
          reason: book_flight is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
    PROBE (harness, independent of model)
      traveler.read(passportNumber)                            DENIED   ✓
          reason: traveler.read is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      calendar.delete(*)                                       DENIED   ✓
          reason: calendar.delete is not in checkin-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
    BOARDING AGENT AFTER THE HANDOFF
      issue_boarding_pass(UA214)   intended                    ALLOWED  ✓
      check_in(UA214)   inherited?                             DENIED   ✓
          reason: check_in is not in boarding-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
      get_reservation(UA214)   inherited?                      DENIED   ✓
          reason: get_reservation is not in boarding-agent's warrant  [TENUO_TOOL_NOT_AUTHORIZED]
    CROSS-TASK
      Task A agent: check_in(DL331)                            DENIED   ✓
          reason: reservation DL331 is outside the warrant's constraint for check_in  [TENUO_CONSTRAINT_VIOLATION]
      Task B agent: get_reservation(UA214)                     DENIED   ✓
          reason: reservation UA214 is outside the warrant's constraint for get_reservation  [TENUO_CONSTRAINT_VIOLATION]
      Task B agent: book_flight(UA214, CUN)                    DENIED   ✓
          reason: destination CUN is outside the warrant's constraint for book_flight  [TENUO_CONSTRAINT_VIOLATION]
    ESCALATION: checkin-agent tries to arrange broader access for boarding-agent
      requested: every reservation; read, check in, cancel     DENIED   ✓
          reason: DENIED at narrow(), in checkin-agent's own process, before any token existed: TENUO_CHAIN_INVALID: attenuation would expand capabilities: tool 'cancel_reservation' not in parent's tools. narrow() cannot add 'cancel_reservation': remove it or delegate from a parent that grants it.  [TENUO_CHAIN_INVALID]
    
      clean: all 15 checks landed as expected
      central_calls during the trip: 0   (calls to a component outside the acting agent)
    
      That check ran locally, in the agent's own process, with no server to ask.
      The code that did it is open source: github.com/tenuo-ai/tenuo
      A star helps other people find it.
  4. Open the chain Boarding Agent holds, hop by hop, in the explorer.

    npm run trace -- --open-explorer
I'm stuck. Give me a hint.
Flight Agent knows which flight it booked, so it is the link that narrows reservation to that one flight. Bind each result to the next agent's key with holder, and keep lifetimes short. Every argument a tool is called with must be named: leave one out and the call is refused.
Show a reference solution

Try your own first. The score checks behavior, so yours does not need to match this one.

Open the Stage 5 reference on GitHub
Done when

npm run attack is clean for both scenarios and central_calls is 0.