> ## Documentation Index
> Fetch the complete documentation index at: https://docs.timeback.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Completion

> Finalize a lesson, interpret results, and understand Caliper behavior

When the [question loop](/beta/build-on-timeback/sdk/managed-lessons/question-loop) is done, call `session.complete()` to finalize the lesson. This triggers server-side scoring, flushes the final time tracking data, and returns a comprehensive result object.

## Complete a lesson

```typescript theme={null}
const result = await session.complete()
```

The result includes everything you need to render a results screen: `score`, `accuracy`, `totalQuestions`, `correctQuestions`, `timeSpentSeconds`, and more.

<Info>
  See the [reference](/beta/build-on-timeback/sdk/managed-lessons/reference#lessonsessioncompleteresult) for the full return type.
</Info>

## What happens under the hood

`session.complete()` does three things in sequence:

```mermaid theme={null}
graph LR
    A["session.complete()"] --> B["PowerPath finalize"]
    B --> C["Flush time data"]
    C --> D["Return merged result"]
```

1. **Server**: reads progress. For an unfinalized linear lesson it attempts `finalStudentAssessmentResponse()`, catches errors, and reads progress again. For an adaptive lesson it uses the current progress without that finalization call.
2. **Client**: calls `activity.end()` to flush the final time tracking window as a `TimeSpentEvent`
3. **Client**: returns a merged result combining the server response with client-side timing data

## Caliper event flow

Managed Lessons split Caliper responsibility between the SDK and PowerPath:

| Concern | Handled by | Event |
| - | - | - |
| Time tracking | SDK (automatic) | `TimeSpentEvent` heartbeats throughout the session |
| Completion + XP | PowerPath (server-side) | `ActivityEvent` with calculated XP |

The SDK does **not** send an `ActivityCompletedEvent` for Managed Lessons. PowerPath is the source of truth for scoring, XP calculation, and OneRoster gradebook updates.

This means you do not need to calculate XP or report completion metrics yourself -- PowerPath handles it when `session.complete()` calls the finalization endpoint.

## Handle time tracking errors

The final time flush and scoring are separate. `timeTrackingSent: false` means the tracker's `end()` call rejected. A true value is not delivery confirmation: heartbeat network errors are normally reported internally and swallowed, so they may leave this flag true.

```typescript theme={null}
const result = await session.complete()

if (!result.timeTrackingSent) {
    console.warn('Time tracking flush failed:', result.error)
    // Inspect result.finalized and the score separately.
    // Reconcile analytics separately; there is no fixed maximum loss window.
}
```

<Note>
  These operations delegate to PowerPath and return its progress. For linear lessons, check `finalized` before displaying a completed result. The SDK catches finalization errors and re-reads progress, so a resolved promise can still return `finalized: false`. Adaptive completion returns the current score and marks the SDK result finalized; it does not itself establish that a mastery threshold was reached.
</Note>

## Render results

Use the completion result to build a results screen:

```typescript theme={null}
const result = await session.complete()

if (!result.finalized) {
    showPendingFinalization(result) // Your application handles the retry/review state.
} else {
    const payload = { kind: 'completed' as const, ...result }
    renderResults(payload)
}
```

## Next steps

<CardGroup cols={2}>
  <Card title="Attempt history" icon="clock-rotate-left" href="/beta/build-on-timeback/sdk/managed-lessons/attempt-history">
    Review past attempts and per-question data
  </Card>

  <Card title="Reference" icon="code" href="/beta/build-on-timeback/sdk/managed-lessons/reference">
    Parameters, properties, methods, and return types
  </Card>
</CardGroup>
