{% extends "base.html" %} {% block title %}Missions — FORGE Academy{% endblock %} {% block extra_css %} {% include "forge_academy/partials/_chrome_clearance.html" %} {% endblock %} {% block content %}

Mission Browser

{% if listing is defined and listing %} {{ listing.takeable }} mission{{ '' if listing.takeable == 1 else 's' }} you can take {%- if active_tier %} in Tier {{ active_tier }}{% endif %} {%- if listing.track_label %} on the {{ listing.track_label }} track{% else %} across all roles{% endif %} {%- if listing.coming_soon %} · {{ listing.coming_soon }} more coming soon (no steps yet){% endif %} {% else %} {{ missions|length }} missions listed {% endif %}

← Hub
Tier: All T1 Foundations T2 Role Tracks T3 Expert Type: Coding Guided Studio Chat Lab
{% if error %}
⚠ {{ error }}
{% endif %} {% set tiers = missions|map(attribute='tier')|unique|sort|list %} {% for tier in tiers %} {% set tier_missions = missions|selectattr('tier','equalto',tier)|list %} {% if tier_missions %}
Tier {{ tier }} — {% if tier==1 %}Foundations{% elif tier==2 %}Role Tracks{% else %}ICDEV Expert{% endif %}
{% for m in tier_missions %} {% set stripe = '#4a90d9' if m.tier==1 else ('var(--fa-orange)' if m.tier==2 else '#FF2D55') %} {% set status = progress_map.get(m.id, 'pending') %}
{{ m.title }}
{# A mission with no steps is a dead end; say so on the card rather than after the click (fga-wire-06). is_available is derived from step count in list_missions. #} {% if m.is_available is defined and not m.is_available %} coming soon {% elif m.is_locked %} {# aca-ux-04: locked-but-readable — say so before the click. The card still navigates; the mission just cannot earn credit yet. #} 🔒 locked {% else %} {{ m.mission_type|default('coding') }} {% endif %}

{{ m.tagline|default('') }}

{# aca-trn-03: the card advertised three costs — XP, minutes, difficulty — and never what the learner walks away able to DO. For training used in a compliance context that is the auditable unit, so it belongs above the costs, not beside them. Rendered only where the authored content states one: the column is NULL otherwise and the line is omitted, because an absent objective is a visible content gap and an invented one is an invisible false record. Distinguished from the tagline above it — that is marketing copy, this is the claim an auditor reads. #} {% if m.learning_objective %}
{# "Objective", not "You'll be able to": the extracted text is authored in whichever register its section used — declarative ("A GoalValidator that…") or imperative ("Design a 3-stage pipeline…") — and a label that only fits one of them would misread half the catalogue. #} Objective {{ m.learning_objective }}
{% endif %} {# aca-ux-06: 86 of 122 missions declare prerequisites and none were shown, so a 122-mission catalogue had no visible ordering. Advisory, not a gate — the card still navigates, matching the locked-but-readable choice made in aca-ux-04. #} {% set pre = prereq_state.get(m.id) if prereq_state is defined else None %} {% if pre and pre.prereqs %}
Requires: {% for p in pre.prereqs %} {{ '✓'|safe if p.satisfied else '○'|safe }} {{ p.title }} {% if not loop.last %},{% endif %} {% endfor %}
{% endif %}
+{{ m.xp_reward }} XP {{ m.difficulty|default('beginner') }} ~{{ m.estimated_minutes|default(30) }}m {% if fa_user %} {% if status=='completed' %}✓ Done{% elif status=='in_progress' %}● Active{% else %}○ Start{% endif %} {% endif %}
{% endfor %}
{% endif %} {% else %}
No missions match the current filter. Clear filters
{% endfor %}
{% endblock %}