Files
noema/web/templates/pages/approvals.html
T
Andy Dixon 2ecdbc39b5 feat(ui): wants, intentions, commitments, plans, agency timeline, why, research
- Wants: active wants by effective strength with origin, means, drives,
  values, goal, reinforcement, suppressions and each conflict with its
  resolution rule; closed wants with their resolution.
- Intentions grouped by status with blocked reasons and plans, plus the
  wants that did not become intentions and why. An intention page shows
  sources, subordinate intentions, formation terms, every plan revision as
  a dependency graph, decisions and the correlated timeline; operators can
  abandon it.
- Commitments with polarity, exception, matcher, weight and due time,
  live conflicts between commitments, a creation form and close controls.
- Plans with estimate against budget; a plan page with the dependency
  graph, per-step expectations, observations and linked approvals,
  requests, executions and subordinate intentions, resources, completion
  and abort conditions, assumptions, alternatives, revisions and
  validation; operators can cancel a plan or release a blocked step.
- Agency timeline labelling each event as wanted, intended, committed,
  planned, requested, approved, acted, observed or reconsidered.
- "Why did this happen?" pages built from agency.Explain, reachable from
  events, executions in the approval centre, plan steps and intentions.
- A research dashboard per mind (volition and agency rates, introspection
  accuracy, action claims, self-model accuracy, calibration by confidence
  band, experiments on the mind) and a global research page grouping
  experiments by protocol; every figure sits next to its operational
  definition and the disclaimer. Experiment pages show the protocol,
  reproducibility, build, per-variant research measures, divergence
  extras and counterfactual findings.
- The mind tabs gain Volition; the navigation gains Research.
2026-09-24 21:16:48 +01:00

80 lines
8.4 KiB
HTML

{{define "content"}}
<div class="pagehead"><h1>Approval centre</h1><p class="muted">Actions a mind wants to take that policy marks ASK. Approvals are bound to the exact request; modified parameters are re-validated and recorded.</p></div>
{{$op := .Principal.User.Role.AtLeast "operator"}}
<section class="card">
<h2>Pending <span class="muted small">{{len .Data.Pending}}</span></h2>
{{if .Data.Pending}}{{range .Data.Pending}}
<div class="approval">
<div class="approval-head"><span class="badge rk-{{.Risk}}">{{.Risk}}</span> <strong>{{index $.Data.MindNames .MindID}}</strong> wants <code>{{.Capability}}</code>{{if .Target}} on <span class="mono">{{.Target}}</span>{{end}} <span class="muted small">· requested {{ago .CreatedAt}} · expires {{.ExpiresAt.Local.Format "02 Jan 15:04"}}{{if .EventID}} · <a href="/events/{{.EventID}}">event</a>{{end}}</span></div>
{{with index $.Data.Caps .Capability}}<p class="small muted">{{.Access}} · {{if .Idempotent}}idempotent{{else}}not idempotent{{end}}{{if .SideEffects}} · side effects: {{.SideEffects}}{{end}}</p>{{end}}
<div class="grid cols-2 tight">
<div><h3>Reason</h3><p>{{if .Reason}}{{.Reason}}{{else}}<em class="muted">none given</em>{{end}}</p>
{{if .Evidence}}<h3>Evidence</h3><ul class="plain small">{{range .Evidence}}<li><span class="badge">{{.Kind}}</span> {{if eq .Kind "event"}}<a href="/events/{{.ID}}">{{.ID}}</a>{{else}}{{.ID}}{{end}} {{.Note}}</li>{{end}}</ul>{{end}}</div>
<div><h3>Parameters</h3><pre class="json">{{pretty (jsonOf .Params)}}</pre></div>
</div>
{{if $op}}
<form method="post" action="/approvals/{{.ID}}/decide" class="stack">
<input type="hidden" name="_csrf" value="{{$.CSRF}}">
<details><summary class="small">Modify parameters before approving</summary><textarea name="params" rows="3" class="mono" placeholder="JSON object; leave empty to keep">{{pretty (jsonOf .Params)}}</textarea></details>
<div class="row"><input name="note" placeholder="note (shown to the mind)" class="grow" maxlength="500">
<button class="btn btn-primary" name="decision" value="approve">Approve once</button>
<button class="btn" name="decision" value="session" title="Also allow matching requests for this session">Approve for session</button>
<button class="btn btn-danger" name="decision" value="deny">Deny</button></div>
</form>
{{end}}
</div>{{end}}
{{else}}<p class="muted">Nothing is waiting.</p>{{end}}
</section>
<section class="card">
<h2>Capability requests <span class="muted small">{{len .Data.Batches}} batch(es)</span></h2>
<p class="muted small">Temporary, scoped authority a mind has asked for. Granting creates an expiring grant that applies only where policy says ASK; it never overrides DENY. You may grant less than was asked.</p>
{{if .Data.Batches}}{{range .Data.Batches}}
<div class="approval">
<div class="approval-head"><strong>{{index $.Data.MindNames .MindID}}</strong> · {{len .Requests}} related request(s){{if .IntentionID}} for intention <a class="mono small" href="/intentions/{{.IntentionID}}">{{trunc (printf "%s" .IntentionID) 8}}</a>{{end}}</div>
{{range .Requests}}
<div class="stack">
<div><span class="badge">{{.Access}}</span> <code>{{.Capability}}</code> on <span class="mono">{{.TargetPattern}}</span> for {{duration .DurationSeconds}}{{if .MaxOperations}}, at most {{deref_int .MaxOperations}} operations{{end}} <span class="muted small">· expires {{.ExpiresAt.Local.Format "02 Jan 15:04"}}{{if .EventID}} · <a href="/events/{{.EventID}}">event</a>{{end}}</span></div>
<div class="grid cols-2 tight">
<div><h3>Why</h3><p>{{.Reason}}</p>
{{if .Evidence}}<h3>Evidence</h3><ul class="plain small">{{range .Evidence}}<li><span class="badge">{{.Kind}}</span> {{if eq .Kind "event"}}<a href="/events/{{.ID}}">{{.ID}}</a>{{else}}{{.ID}}{{end}} {{.Note}}</li>{{end}}</ul>{{end}}
{{if .ParamConstraints}}<h3>Parameter limits</h3><pre class="json">{{pretty (jsonOf .ParamConstraints)}}</pre>{{end}}</div>
<div><h3>Risk</h3><p>{{if .Risk}}{{.Risk}}{{else}}<em class="muted">none stated</em>{{end}}</p>
{{if .Mitigation}}<h3>Mitigation</h3><p>{{.Mitigation}}</p>{{end}}
{{if .Fallback}}<h3>If refused</h3><p>{{.Fallback}}</p>{{end}}
{{if .Alternatives}}<h3>Alternatives</h3><ul class="plain small">{{range .Alternatives}}<li>{{.}}</li>{{end}}</ul>{{end}}
{{with index $.Data.Caps .Capability}}{{if .SideEffects}}<h3>Side effects</h3><p class="small">{{.SideEffects}}</p>{{end}}{{end}}
<p class="small muted">Earlier decisions on this capability for this mind: {{index .History "granted"}} granted, {{index .History "denied"}} denied. History informs; it never grants.</p></div>
</div>
{{if $op}}
<form method="post" action="/capability-requests/{{.ID}}/decide" class="row">
<input type="hidden" name="_csrf" value="{{$.CSRF}}">
<input name="duration_minutes" type="number" min="1" placeholder="minutes (≤ asked)" aria-label="duration in minutes" size="8">
<input name="max_operations" type="number" min="1" placeholder="operations" aria-label="maximum operations" size="6">
<input name="target_pattern" placeholder="{{.TargetPattern}}" aria-label="target pattern" size="12">
<input name="note" placeholder="note (shown to the mind)" class="grow" maxlength="500">
<button class="btn btn-primary" name="decision" value="grant">Grant</button>
<button class="btn btn-danger" name="decision" value="deny">Deny</button>
</form>
{{end}}
</div>
{{end}}
</div>{{end}}
{{else}}<p class="muted">No open capability requests.</p>{{end}}
</section>
<section class="card">
<h2>Temporary grants in force <span class="muted small">{{len .Data.Grants}}</span></h2>
{{if .Data.Grants}}<table class="table compact"><thead><tr><th>Mind</th><th>Capability</th><th>Target</th><th>Access</th><th>Limits</th><th>Expires</th><th>By</th><th></th></tr></thead><tbody>{{range .Data.Grants}}<tr>
<td class="small">{{index $.Data.MindNames .MindID}}</td><td><code>{{.Capability}}</code></td><td class="mono small">{{.TargetPattern}}</td><td class="small">{{.Access}}</td>
<td class="small">{{if .MaxOperations}}{{.UsedOperations}} of {{deref_int .MaxOperations}} used{{else}}{{.UsedOperations}} used{{end}}{{if .ParamConstraints}} · {{range $k, $v := .ParamConstraints}}{{$k}}={{$v}} {{end}}{{end}}</td>
<td class="small nowrap">{{.ExpiresAt.Local.Format "02 Jan 15:04"}}</td><td class="small">{{.GrantedBy}}</td>
<td>{{if $op}}<form method="post" action="/scoped-grants/{{.ID}}/revoke" class="inline"><input type="hidden" name="_csrf" value="{{$.CSRF}}"><button class="btn small btn-danger" data-confirm="Revoke this grant now?">Revoke</button></form>{{end}}</td></tr>{{end}}</tbody></table>
{{else}}<p class="muted">None. Session approvals appear on the policies page.</p>{{end}}
</section>
<section class="grid cols-2">
<div class="card"><h2>Decided recently</h2>
{{if .Data.Decided}}<table class="table compact"><thead><tr><th>Status</th><th>Mind</th><th>Action</th><th>By</th><th>Note</th><th>When</th></tr></thead><tbody>{{range .Data.Decided}}<tr><td><span class="badge ap-{{.Status}}">{{.Status}}</span></td><td class="small">{{index $.Data.MindNames .MindID}}</td><td><code>{{.Capability}}</code> <span class="mono small">{{.Target}}</span>{{if .Error}}<div class="small danger">{{.Error}}</div>{{end}}</td><td class="small">{{.DecisionBy}}</td><td class="small">{{.DecisionNote}}</td><td class="small muted nowrap">{{ago .CreatedAt}}</td></tr>{{end}}</tbody></table>{{else}}<p class="muted">None.</p>{{end}}</div>
<div class="card"><h2>Executions</h2>
{{if .Data.Executions}}<table class="table compact"><thead><tr><th>Mind</th><th>Capability</th><th>Target</th><th>Result</th><th class="num">ms</th><th></th></tr></thead><tbody>{{range .Data.Executions}}{{$x := .}}<tr><td class="small">{{index $.Data.MindNames .MindID}}</td><td><code>{{.Capability}}</code></td><td class="mono small">{{.Target}}</td><td class="small">{{if .Error}}<span class="danger">{{trunc .Error 80}}</span>{{else}}{{payloadField .Result "summary"}}{{end}}</td><td class="num">{{.DurationMS}}</td><td>{{if .EventID}}<a class="small" href="/events/{{.EventID}}">event</a>{{end}}{{with index $.Data.MindSlugs $x.MindID}} · <a class="small" href="/minds/{{.}}/why?kind=execution&id={{$x.ID}}">why?</a>{{end}}</td></tr>{{end}}</tbody></table>{{else}}<p class="muted">None yet.</p>{{end}}</div>
</section>
{{end}}