AEROSIM-TS-10
Advance and retry lessons from recorded attempt outcomes
A recorded terminal lesson attempt changes the active pilot's progression at most once, while retry creates a new attempt from the lesson's declared initial state without changing progression.
- Verified flow state
- Unverified
- Owner
- AeroSim Architecture and Delivery
- Feature
- AEROSIM-FT-8
- Component
- API Service — lesson-attempt and progression service, Pilot Data Store — lesson attempts, and Web Application — training result client
- Repository
- corp-v1-aerosim/corp-v1-aerosim
Delivery scope
Implement the lesson-attempt command and progression transaction behind the API. StartLessonAttempt binds pilotId, lessonId, catalogueVersion, progressSnapshotVersion, inputProfileVersion, and initialStateVersion. RecordLessonOutcome accepts one terminal PASSED or FAILED result for that attempt. PASSED appends the lesson to completedLessonIds and returns a refreshed LearningPathProjection; FAILED records feedback and leaves completedLessonIds unchanged. RetryLesson creates a new attemptId for the same lesson and initialStateVersion and records priorAttemptId for lineage. The service treats the InputProfileSnapshot version validated by TASK-0009 as immutable attempt metadata; it neither remaps controls nor recalibrates devices. Progress history remains supplied through the AEROSIM-FT-28 Feature contract rather than a fabricated prerequisite Task.
Implementation contract
Implementation artifacts
- applications/api/src/training/lesson-attempt-service.ts
- applications/web/src/training/training-result-client.ts
- packages/contracts/src/training/lesson-attempt.ts
- prisma/migrations/lesson-attempt-progression/migration.sql
- tests/integration/training/lesson-attempt-progression.spec.ts
Inputs
- StartLessonAttempt { commandId, pilotId, lessonId, catalogueVersion, progressSnapshotVersion, inputProfileVersion, initialStateVersion } using a launchable row from TASK-0009.
- RecordLessonOutcome { commandId, attemptId, pilotId, result: PASSED | FAILED, completedAt, feedbackCode, evidenceRef } from the lesson runtime; non-terminal progress observations are not accepted by this command.
- RetryLesson { commandId, pilotId, priorAttemptId } for a recorded FAILED attempt.
Outputs
- LessonAttempt { attemptId, pilotId, lessonId, catalogueVersion, inputProfileVersion, initialStateVersion, priorAttemptId?, status, feedbackCode?, evidenceRef? }.
- For PASSED, one idempotent ProgressionEvent linked to attemptId and a refreshed LearningPathProjection; for FAILED, recorded feedback with no progression event.
- For retry, a new attempt linked to priorAttemptId and reset to the same initialStateVersion.
Failure boundaries
- Reject start when the lesson is not launchable in the supplied TASK-0009 projection, any referenced version is stale, or pilot identity does not match the authenticated pilot.
- Reject an outcome for an unknown attempt, a different pilot, a lesson other than the attempt lesson, an already terminal attempt with a conflicting payload, a non-terminal result, a missing evidenceRef, or a completion time earlier than attempt creation.
- Treat an exact replay of commandId and payload as the original result; reject reuse of commandId with different content and prevent a second progression event for the same attempt.
- Reject retry unless the prior attempt is recorded as FAILED; retry must not reuse attemptId, alter catalogueVersion, inputProfileVersion, or initialStateVersion, or mutate completedLessonIds.
Excluded scope
- Lesson-state evaluation from raw simulation telemetry and production of the terminal PASSED or FAILED result.
- Device binding changes, calibration changes, progress analytics, lesson recommendations, and implementation of AEROSIM-FT-28.
Verification steps
- Run tests/integration/training/lesson-attempt-progression.spec.ts against the real transaction adapter and retain the exact candidate-revision result.
- Record one PASSED outcome twice with the same command and assert one terminal attempt, one progression event, and one completed lesson; then reuse the command with changed content and assert rejection.
- Record a FAILED outcome and assert feedback is returned while completedLessonIds is unchanged; issue retry and assert a new attempt linked to the failed attempt with the same initialStateVersion and inputProfileVersion.
- Exercise stale projection, stale profile version, cross-pilot start and outcome, unknown attempt, conflicting terminal result, missing evidence reference, invalid completion time, retry of PASSED, and concurrent duplicate outcomes; assert no unauthorized progression mutation.
- Render PASSED and FAILED responses through training-result-client.ts and confirm that progression and retry state come from the API response rather than a client-authored completion assertion.
Traceability
Acceptance evidence
Required future evidence: a reviewed candidate revision must contain the command contracts, transaction migration, service, client, and integration tests; passing output must prove one-attempt lineage, idempotent progression, failed-attempt retry from the declared initial state, immutable input-profile versioning, pilot isolation, and rejection of every declared invalid transition.
Current evidence boundary
No current implementation, acceptance, release, or deployment evidence is claimed for this planned Task. Any prior implementation may be used only as prototype and discovery evidence.