{% from '_partials/arc_badge.html' import arc_badge %}

← All arcs

{# T-1910 Slice 2: focus toggle + inline-editable name #}
{{ arc.get('name', arc_id) }} {% if focused %}FOCUSED{% endif %}

id: {{ arc_id }}

{% if arc.get('description') %}

{{ arc.description }}

{% endif %}

status: {% if arc.status == 'in-progress' %}{{ arc.status }} {% elif arc.status == 'closed' %}{{ arc.status }}{% if arc.decision %} / {{ arc.decision }}{% endif %} {% else %}{{ arc.status }}{% endif %} {% if arc.anchor_task %} · anchor: {{ arc.anchor_task }}{% endif %} {% if arc.created %} · created: {{ arc.created }}{% endif %} {% if arc.closed_at %} · closed: {{ arc.closed_at }}{% endif %}

{{ stats.completed }} / {{ stats.total }}
Completed / Total
{{ "%.0f%%" % (stats.ratio * 100) }}
Completion ratio
{% if arc.status == 'closed' %}closed {% elif stats.ratio >= 0.80 %}audit warns ≥80% {% else %}below threshold{% endif %}
Audit detective (G-062 / T-1656)
{% if has_specialized_view %}

Specialized view available: → /orchestrator (MCP audit, live sessions, recent dispatches).

{% endif %} {# ── T-1930 (arc-006): BVP signals — arc-level scores, coherence, proposed drivers ── #} {% if bvp_info %}

BVP signals

{# Arc-level BVP numeric + per-driver breakdown #}
{% if bvp_info.has_scores %}{{ "%.3f"|format(bvp_info.norm) }}{% else %}—{% endif %}
Arc BVP_norm
{% if bvp_info.has_scores %}{{ bvp_info.raw }}{% else %}—{% endif %}
Arc BVP_raw (Σ score×weight)
{% if not bvp_info.has_scores %}

Arc has no bvp_scores: set and no constituent task scores to roll up. Score via fw bvp confirm or edit .context/arcs/{{ arc_slug }}.yaml directly.

{% elif bvp_info.bvp_mode and bvp_info.bvp_mode != 'direct-confirmed' %}

Source: {{ bvp_info.bvp_mode }} {% if bvp_info.bvp_mode == 'direct-proposed' %}— arc has estimator-proposed scores (advisory; no direct confirmation yet). {% elif bvp_info.bvp_mode == 'derived-confirmed' %}— rolled up from constituent task bvp_scores: (no arc-level scores set yet). {% elif bvp_info.bvp_mode == 'derived-proposed' %}— rolled up from constituent task scores; at least one input is estimator-proposed (advisory). {% endif %}

{% endif %} {# T-1956: surface driver weights above the fold as a compact inline list, so reviewers don't miss them. The full table stays in
for per-task contribution numbers. #} {% if bvp_info.per_driver %}

Drivers: {% for d in bvp_info.per_driver -%} {{ d.id }}={{ d.weight }}{% if not loop.last %} · {% endif %} {%- endfor %}

{% endif %}
Per-driver breakdown ({{ bvp_info.per_driver|length }} drivers) {% for d in bvp_info.per_driver %} {% endfor %}
DriverWeightScoreContribution
{{ d.id }} {{ d.weight }} {% if d.score is not none %}{{ d.score }}{% else %}{% endif %} {% if d.contrib is not none %}{{ d.contrib }}{% else %}{% endif %}
{# Coherence warnings — per-driver (T-1927, M4). Empty = passing. #} {% if bvp_info.coherence_findings %}

Coherence warnings

Arc claims a driver as important, but the constituent tasks don't support it. Either revise the arc claim or revise the rubric (R2 detection — systematic single-driver warnings indicate rubric bias).

{% else %}

No coherence warnings — arc claims align with constituent scores (or the arc has no in-progress status / no scoring constituents to compare against).

{% endif %} {# Currently approved scoped drivers — with per-row Remove (T-1976) + live weight sliders (T-1977) #} {% if bvp_info.scoped_drivers %}

Scoped drivers ({{ bvp_info.scoped_drivers|length }} / 3 max)

Drag a slider to preview the new weight (no commit). Press Commit weight changes below to persist via fw arc set-scoped-weight --from-watchtower (§ACD, D8). Rationale ≥30 chars required (R6). [T-1977]

{% for sd in bvp_info.scoped_drivers %} {# T-2117: humanized title + kebab slug for at-a-glance reading, consistent with the proposed-drivers section below and T-2080's /bvp pattern. Arc-scoped drivers have no F-id (they live in scoped_drivers: with only the kebab name as identifier), so the /bvp 'F1 — Antifragility' shape is approximated as 'Humanized Name' + muted kebab. Jinja replace+title is cheap. #} {% endfor %}
NameServerSliderCurrentRationaleApproved
{{ sd.get('name', '?')|replace('-', ' ')|title }} {{ sd.get('name', '?') }} {{ sd.get('weight', '—') }} {{ sd.get('weight', '—') }} {{ sd.get('rationale', '')|truncate(120, True) }} {{ sd.get('approved_ts', sd.get('ts', sd.get('approved_at', '—'))) }}
🗑 Remove driver
{# T-1977: batched commit for changed sliders, single rationale per commit. #}
Drag a slider to enable.
{% endif %} {# Add a custom scoped driver — T-1976 parity with /bvp add-driver form. Gated by cap (M2 max 3); estimator-proposed drivers use the Approve form below. #} {% if (bvp_info.scoped_drivers|length if bvp_info.scoped_drivers else 0) < 3 %}
Add a custom scoped driver

For drivers the estimator hasn't proposed but you want to track. M2 cap: max 3 scoped drivers per arc; weight 1-6.

{% endif %} {# Proposed drivers — agent-suggested, awaiting approve / approve-none #} {% if bvp_info.proposed_drivers %}

Proposed scoped drivers ({{ bvp_info.proposed_drivers|length }} awaiting approval)

Estimator-proposed drivers. Approve up to 3 (M2; weight ≤6), or approve none with justification (R6: ≥30 chars).

{% for p in bvp_info.proposed_drivers %}
{# T-2117: same humanized-title + kebab-slug pair used for approved scoped drivers above. Proposed drivers don't yet have an approved_at timestamp, but the identifier shape is the same. #} {{ p.get('name', '?')|replace('-', ' ')|title }} {{ p.get('name', '?') }} · proposed {{ p.get('ts', '—') }} by {{ p.get('source', 'agent') }}
{% if p.get('rationale') %}

{{ p.rationale }}

{% endif %}
{% endfor %} {% else %}

No proposed scoped drivers awaiting approval. (When the BVP estimator T-1922 runs against this arc's anchor task, candidates will appear here.)

{% endif %} {# Approve none — also flips status draft → in-progress per T-1926 #}
Approve none (mark "no scoped drivers needed")

For arcs where global D1-D4 already capture the value dimensions and no arc-specific driver would add signal.

{% endif %} {% if reports %}

Reports & evidence

Arc-keyed reports under docs/reports/{{ arc_id }}-*.md:

{% endif %}

Constituent tasks{% if constituents %} ({{ constituents|length }}){% endif %}

{% if constituents %}

BVP_norm = score weighted by drivers / max-possible, [0,1]. BVP_raw = unscaled sum. Cost = composite F8. Italic + * = estimator-proposed (not yet human-confirmed). = no score data yet. Numbers match /bvp scatter (same compute helpers). [T-1978]

{#- T-2087: max-height scroll container + sticky thead so growing arcs (121-task orchestrator-rethink hit 15kpx) stay within the 8000px guard. Same fix shape as T-2038/T-2044/T-2045 used for unbounded tables. -#}
{% for c in constituents %} {% endfor %}
ID Arc Name Type Status Horizon BVP_norm BVP_raw Cost
{% if c.missing %}{{ c.id }}{% else %}{{ c.id }}{% endif %} {{ arc_badge(c) }} {% if c.missing %}{{ c.name }}{% else %}{{ c.name }}{% endif %} {{ c.type }} {% if c.completed %}work-completed {% elif c.status == 'started-work' %}{{ c.status }} {% elif c.status == 'issues' %}{{ c.status }} {% else %}{{ c.status }}{% endif %} {{ c.horizon }} {% if c.bvp_norm is not none %} {% if c.bvp_mode == 'proposed' %}{{ '%.3f'|format(c.bvp_norm) }}* {% else %}{{ '%.3f'|format(c.bvp_norm) }}{% endif %} {% else %}{% endif %} {% if c.bvp_raw is not none %} {% if c.bvp_mode == 'proposed' %}{{ c.bvp_raw }}* {% else %}{{ c.bvp_raw }}{% endif %} {% else %}{% endif %} {% if c.cost is not none %}{{ '%.2f'|format(c.cost) }} {% else %}{% endif %}
{#- /constituents-scroll (T-2087) -#} {% else %}

No constituent tasks. Tag tasks with arc:{{ arc_id }} or run fw arc tag {{ arc_id }} T-XXXX.

{% endif %} {% if arc.status != 'closed' %}

§Arc Completion Discipline — three-question check

Per CLAUDE.md, before declaring this arc shipped, you MUST be able to answer all three with concrete evidence — not by argument:

  1. Did the integrated system run end-to-end on a fresh substrate? (A wire-level observation, not "tests pass" or "AC checked".)
  2. Did any silently-defaulted constants escape human review? (Routing thresholds, taxonomies, fallback chains, retry counts...)
  3. Does the framework that built the arc actually USE the arc? (Framework-side dispatch / audit / handover paths exercise the substrate.)

When you can answer all three with evidence, close the arc:

cd {{ project_root }} && bin/fw arc close {{ arc_id }} \
    --demo <path-to-wire-evidence> \
    --decision "<success|partial|failed|cancelled> — <one-line summary>"

§ACD/G-062 gates: --demo is REQUIRED (T-1668) — supply a path or URL whose content references the arc id {{ arc_id }} or one of its constituent tasks (.json, .jsonl, .yaml, .md, .cast, .png, .html, etc., ≥256 bytes). For arcs with no runtime mechanic, use --demo none --justification "<≥30 chars>" (logged to .context/audits/arc-bypass.jsonl).
Closure verb is human-only (T-1671). Under $CLAUDECODE=1 the command refuses; agents must redirect to fw task review {{ arc.anchor_task }}. Overrides: --i-am-human (rare human-typing-into-agent-session), --from-watchtower (used by Flask backend when Watchtower closes the arc on the human's behalf).

{% if arc.demo_evidence %}

Latest demo on file: {{ arc.demo_evidence }} — preserved across any aborted close attempts.

{% endif %} {% else %}

Arc closed

Decision: {{ arc.decision or 'unspecified' }}{% if arc.closed_at %} · {{ arc.closed_at }}{% endif %}

{% endif %}