# Writing a Verb function

URL: /code/learn/writing-a-verb-function · Id: `page:code/learn/writing-a-verb-function`

> Tutorial 3 of 12 writes the Function behind `Lease.renew` and the test that gates every Change to it.

A [Verb](/business/nouns/verb) runs its default [Function](/business/nouns/function) until a file gives it one. Leaseline declares a `Lease` [Noun](/business/nouns/noun), and `nouns/Lease.renew.ts` says what renewing does.

## What you build
You write the Function behind `Lease.renew`: it extends the end date by the term and raises the rent within the increase the manager allows. Then you write the test that every [Change](/business/nouns/change) to the Function must pass before it merges.

## Steps
1. To give the Verb its Function, create the file beside the Noun. Its name binds it; nothing registers it:

   ```ts title="nouns/Lease.renew.ts"
   export default async (lease: Lease, input: LeaseRenewInput, $: $) => {
     const end = new Date(lease.endsOn)
     end.setMonth(end.getMonth() + input.months)
     const rent = lease.rent && { ...lease.rent, amount: Math.round(lease.rent.amount * (1 + (input.increase ?? 0))) }
     return $.Lease.update({ id: lease.$id, endsOn: end.toISOString().slice(0, 10), rent })
   }
   ```

   The Function never sets `status`. When the [Action](/business/nouns/action) succeeds, the [Event](/business/nouns/event) `Lease.renewed` moves the lease to `renewed`.

2. To pin the rule down, write its test beside it:

   ```ts title="nouns/Lease.renew.test.ts"
   import { expect, run, test } from 'startup-builder/test'

   const lease = { $id: 'lease_4loEed1JG4', endsOn: '2026-12-31', rent: { amount: 1800, currency: 'USD' } }

   test('a 3% increase raises the rent', async () => {
     const { result, calls } = await run({ lease: 'lease_4loEed1JG4', months: 12, increase: 0.03 }, { Lease: { get: () => lease } })
     expect(result.rent.amount).toBe(1854)
     expect(calls).toEqual(['Lease.update'])
   })
   ```

3. To run the case, save either file. `npx startup-builder dev` reruns every case on each save.

4. To see which Function a call ran, renew one lease in test and read its Action:

   ```bash
   npx startup-builder do Lease.renew --json '{"lease":"lease_4loEed1JG4","months":12,"increase":0.03}'
   ```

   The Action names the Function [Version](/business/nouns/version) it ran, with its input, output and cost.

## Result
`Lease.renew` runs your code, and a Change that breaks the 3% case cannot merge. [Function kinds](/code/function-kinds) shows the same Verb as code, a model call, an agent and a person. Checkpoint `leaseline@ch03` (status `planned`) adds `nouns/Lease.renew.ts` and its test.

## Next steps
- [Tutorial 4](/code/learn/calling-it-four-ways) calls the Verb from every [Interface](/business/nouns/interface).
- [Verb functions](/code/file-conventions/verb-functions) and [verb tests](/code/file-conventions/verb-tests): the full contracts.