Compare commits

..

No commits in common. "8cf124530cfbe6b7de5d58f16ee1ac94cdcb7b1c" and "4eab03346b8aa39830a2fa02020bcadaed75a8e6" have entirely different histories.

15 changed files with 189 additions and 220 deletions

View file

@ -18,7 +18,7 @@
| workplan | TREV-WP-0008 | finished | — | workplans/TREV-WP-0008-governance-and-pilot-rollout.md | | workplan | TREV-WP-0008 | finished | — | workplans/TREV-WP-0008-governance-and-pilot-rollout.md |
| workplan | TREV-WP-0009 | finished | — | workplans/TREV-WP-0009-target-revenue-control-plane.md | | workplan | TREV-WP-0009 | finished | — | workplans/TREV-WP-0009-target-revenue-control-plane.md |
| workplan | TREV-WP-0010 | finished | — | workplans/TREV-WP-0010-development-effort-calculator.md | | workplan | TREV-WP-0010 | finished | — | workplans/TREV-WP-0010-development-effort-calculator.md |
| workplan | TREV-WP-0011 | finished | — | workplans/TREV-WP-0011-railiance-reef-deployment.md | | workplan | TREV-WP-0011 | active | — | workplans/TREV-WP-0011-railiance-reef-deployment.md |
| workplan | TREV-WP-0012 | finished | — | workplans/TREV-WP-0012-phase-provenance-and-policy-modeling.md | | workplan | TREV-WP-0012 | finished | — | workplans/TREV-WP-0012-phase-provenance-and-policy-modeling.md |
| workplan | TREV-WP-0013 | finished | — | workplans/TREV-WP-0013-remission-credit-automation.md | | workplan | TREV-WP-0013 | finished | — | workplans/TREV-WP-0013-remission-credit-automation.md |
| workplan | TREV-WP-0014 | finished | — | workplans/TREV-WP-0014-control-plane-extensions-breach-attestation-ui.md | | workplan | TREV-WP-0014 | finished | — | workplans/TREV-WP-0014-control-plane-extensions-breach-attestation-ui.md |
@ -90,7 +90,7 @@
| task | TREV-WP-0011-T02 | done | — | workplans/TREV-WP-0011-railiance-reef-deployment.md | | task | TREV-WP-0011-T02 | done | — | workplans/TREV-WP-0011-railiance-reef-deployment.md |
| task | TREV-WP-0011-T03 | done | — | workplans/TREV-WP-0011-railiance-reef-deployment.md | | task | TREV-WP-0011-T03 | done | — | workplans/TREV-WP-0011-railiance-reef-deployment.md |
| task | TREV-WP-0011-T04 | done | — | workplans/TREV-WP-0011-railiance-reef-deployment.md | | task | TREV-WP-0011-T04 | done | — | workplans/TREV-WP-0011-railiance-reef-deployment.md |
| task | TREV-WP-0011-T05 | done | — | workplans/TREV-WP-0011-railiance-reef-deployment.md | | task | TREV-WP-0011-T05 | todo | — | workplans/TREV-WP-0011-railiance-reef-deployment.md |
| task | TREV-WP-0012-T01 | done | — | workplans/TREV-WP-0012-phase-provenance-and-policy-modeling.md | | task | TREV-WP-0012-T01 | done | — | workplans/TREV-WP-0012-phase-provenance-and-policy-modeling.md |
| task | TREV-WP-0012-T02 | done | — | workplans/TREV-WP-0012-phase-provenance-and-policy-modeling.md | | task | TREV-WP-0012-T02 | done | — | workplans/TREV-WP-0012-phase-provenance-and-policy-modeling.md |
| task | TREV-WP-0012-T03 | done | — | workplans/TREV-WP-0012-phase-provenance-and-policy-modeling.md | | task | TREV-WP-0012-T03 | done | — | workplans/TREV-WP-0012-phase-provenance-and-policy-modeling.md |

View file

@ -41,19 +41,8 @@ Coulombcore ArgoCD Application exists for future multi-cluster sync but was
`platform/workloads/target-revenue/runtime-secrets` (signing key, session secret, DSNs). `platform/workloads/target-revenue/runtime-secrets` (signing key, session secret, DSNs).
4. **Image:** `docker build/push …:0.1.1` (0.1.0 had schema-path bug; fixed). 4. **Image:** `docker build/push …:0.1.1` (0.1.0 had schema-path bug; fixed).
5. **`kubectl apply -k k8s/railiance/`** on railiance01. 5. **`kubectl apply -k k8s/railiance/`** on railiance01.
6. **Founding token:** bootstrap Job mints `founding-admin`. Canonical copy 6. **Founding token:** bootstrap Job log →
lives in OpenBao (never commit): `~/.config/target-revenue/revenue-coulomb-binky.token` (chmod 600; never commit).
```text
platform/operators/founding-admin/revenue
fields: token, credential_label, licensor_id, rights, host, ...
```
```bash
bao kv get -mount=platform operators/founding-admin/revenue
```
Optional local cache: `~/.config/target-revenue/revenue-coulomb-binky.token`.
7. **Phase POR:** re-registered 7. **Phase POR:** re-registered
`trsl:phase:info-tech-canon-service-surface` on the public API; local `trsl:phase:info-tech-canon-service-surface` on the public API; local
`trf-pilot-pg` is superseded (ledger was empty, so no entry migration). `trf-pilot-pg` is superseded (ledger was empty, so no entry migration).

View file

@ -30,7 +30,7 @@ spec:
fsGroup: 10001 fsGroup: 10001
containers: containers:
- name: bootstrap - name: bootstrap
image: forgejo.coulomb.social/coulomb/target-revenue:0.1.3 image: forgejo.coulomb.social/coulomb/target-revenue:0.1.1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
env: env:
- name: TRF_BOOTSTRAP_BINKY - name: TRF_BOOTSTRAP_BINKY

View file

@ -25,7 +25,7 @@ spec:
fsGroup: 10001 fsGroup: 10001
containers: containers:
- name: target-revenue - name: target-revenue
image: forgejo.coulomb.social/coulomb/target-revenue:0.1.3 image: forgejo.coulomb.social/coulomb/target-revenue:0.1.1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
ports: ports:
- name: http - name: http

View file

@ -28,7 +28,7 @@ spec:
fsGroup: 10001 fsGroup: 10001
containers: containers:
- name: migrate - name: migrate
image: forgejo.coulomb.social/coulomb/target-revenue:0.1.3 image: forgejo.coulomb.social/coulomb/target-revenue:0.1.1
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
env: env:
- name: TRF_RUN_MIGRATIONS - name: TRF_RUN_MIGRATIONS

View file

@ -15,7 +15,6 @@ default so a single Service port works without Traefik strip-prefix.
from __future__ import annotations from __future__ import annotations
from fastapi import FastAPI from fastapi import FastAPI
from fastapi.responses import RedirectResponse
from .app import app as trust_service_app from .app import app as trust_service_app
from .control_plane_app import app as control_plane_app from .control_plane_app import app as control_plane_app
@ -28,12 +27,6 @@ def healthz() -> dict[str, str]:
return {"status": "ok"} return {"status": "ok"}
@app.get("/ui")
def ui_no_trailing_slash() -> RedirectResponse:
"""Browsers often hit /ui without a trailing slash; the mount needs /ui/."""
return RedirectResponse(url="/ui/", status_code=307)
# More specific mount first. # More specific mount first.
app.mount("/ui", control_plane_app) app.mount("/ui", control_plane_app)
app.mount("/", trust_service_app) app.mount("/", trust_service_app)

View file

@ -166,22 +166,11 @@ def login_submit(
token: str = Form(...), token: str = Form(...),
conn: Connection = Depends(get_connection), conn: Connection = Depends(get_connection),
): ):
# OpenBao / password-manager paste often includes trailing newlines or quotes.
cleaned = token.strip().strip('"').strip("'").strip()
if not cleaned:
return _redirect("/login", request, "Credential token is required.", "danger")
try: try:
registry.authenticate(conn, cleaned) registry.authenticate(conn, token)
except registry.RegistrationError: except registry.RegistrationError:
return _redirect( return _redirect("/login", request, "Invalid or revoked credential token.", "danger")
"/login", request.session["token"] = token
request,
"Invalid or revoked credential token. Use field `token` from "
"OpenBao path platform/operators/founding-admin/revenue "
"(not a runtime DSN or signing key).",
"danger",
)
request.session["token"] = cleaned
return _redirect("/", request) return _redirect("/", request)

View file

@ -13,26 +13,26 @@
{% endif %} {% endif %}
<h3>Issue a new credential</h3> <h3>Issue a new credential</h3>
<form class="wn-form" method="post" action="{{ root_path }}/admin/credentials"> <form class="wn-form" method="post" >
<label>Credential label (human name) <wn-field-row label="Credential label (human name)">
<input name="credential_label" required> <wn-input name="credential_label" required></wn-input>
</label> </wn-field-row>
<label>Rights <wn-field-row label="Rights">
<select name="rights"> <wn-select name="rights">
<option value="viewer">viewer</option> <option value="viewer">viewer</option>
<option value="contributor">contributor</option> <option value="contributor">contributor</option>
<option value="operator">operator</option> <option value="operator">operator</option>
<option value="admin">admin</option> <option value="admin">admin</option>
</select> </wn-select>
</label> </wn-field-row>
<button type="submit">Issue credential</button> <wn-button type="submit" variant="primary">Issue credential</wn-button>
</form> </form>
<h3>Revoke a credential</h3> <h3>Revoke a credential</h3>
<form class="wn-form" method="post" action="{{ root_path }}/admin/credentials/revoke"> <form class="wn-form" method="post" >
<label>Token to revoke <wn-field-row label="Token to revoke">
<input name="token" required> <wn-input name="token" required></wn-input>
</label> </wn-field-row>
<button type="submit" class="secondary">Revoke</button> <wn-button type="submit" variant="secondary">Revoke</wn-button>
</form> </form>
{% endblock %} {% endblock %}

View file

@ -3,8 +3,8 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>{% block title %}Target Revenue Control Plane{% endblock %}</title> <title>{% block title %}Target Revenue Control Plane{% endblock %}</title>
<link rel="stylesheet" href="{{ root_path }}/static/whynot-design/styles/colors_and_type.css"> <link rel="stylesheet" >
<link rel="stylesheet" href="{{ root_path }}/static/whynot-design/styles/components.css"> <link rel="stylesheet" >
<script type="importmap"> <script type="importmap">
{ {
"imports": { "imports": {
@ -14,17 +14,8 @@
</script> </script>
<script type="module" src="{{ root_path }}/static/whynot-design/index.js"></script> <script type="module" src="{{ root_path }}/static/whynot-design/index.js"></script>
<style> <style>
body { max-width: 960px; margin: 0 auto; padding: 1.5rem; font-family: system-ui, sans-serif; } body { max-width: 960px; margin: 0 auto; padding: 1.5rem; }
form.wn-form { display: flex; flex-direction: column; gap: 0.75rem; max-width: 480px; } form.wn-form { display: flex; flex-direction: column; gap: 0.75rem; max-width: 480px; }
form.wn-form label { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.9rem; }
form.wn-form input, form.wn-form select, form.wn-form textarea {
padding: 0.5rem 0.6rem; font-size: 1rem; border: 1px solid #ccc; border-radius: 4px;
}
form.wn-form button[type=submit] {
padding: 0.55rem 1rem; font-size: 1rem; cursor: pointer;
background: #1a1a1a; color: #fff; border: none; border-radius: 4px; width: fit-content;
}
form.wn-form button[type=submit].secondary { background: #555; }
.wn-flash { margin: 1rem 0; } .wn-flash { margin: 1rem 0; }
table.wn-plain { width: 100%; border-collapse: collapse; } table.wn-plain { width: 100%; border-collapse: collapse; }
table.wn-plain th, table.wn-plain td { text-align: left; padding: 0.4rem 0.6rem; border-bottom: 1px solid #ddd; } table.wn-plain th, table.wn-plain td { text-align: left; padding: 0.4rem 0.6rem; border-bottom: 1px solid #ddd; }
@ -39,12 +30,12 @@
<p> <p>
Signed in as <strong>{{ session_credential_label }}</strong> Signed in as <strong>{{ session_credential_label }}</strong>
({{ session_rights }}) for <strong>{{ session_licensor_id }}</strong> ({{ session_rights }}) for <strong>{{ session_licensor_id }}</strong>
&middot; <a href="{{ root_path }}/">Dashboard</a> &middot; <a >Dashboard</a>
&middot; <a href="{{ root_path }}/extensions">Extensions</a> &middot; <a >Extensions</a>
{% if session_rights in ("operator", "admin") %}&middot; <a href="{{ root_path }}/proposals">Proposals</a>{% endif %} {% if session_rights in ("operator", "admin") %}&middot; <a >Proposals</a>{% endif %}
{% if session_rights == "admin" %}&middot; <a href="{{ root_path }}/admin/credentials">Credentials</a>{% endif %} {% if session_rights == "admin" %}&middot; <a >Credentials</a>{% endif %}
&middot; <a href="{{ root_path }}/audit">Audit log</a> &middot; <a >Audit log</a>
&middot; <form method="post" action="{{ root_path }}/logout" style="display:inline"><button type="submit">Sign out</button></form> &middot; <form method="post" style="display:inline"><button type="submit">Sign out</button></form>
</p> </p>
{% endif %} {% endif %}
@ -57,18 +48,25 @@
<p style="margin-top:3rem;color:#888;font-size:0.85rem;"> <p style="margin-top:3rem;color:#888;font-size:0.85rem;">
Pilot Control Plane (alpha/beta). First declared Phase: Pilot Control Plane (alpha/beta). First declared Phase:
<code>trsl:phase:info-tech-canon-service-surface</code> <code>trsl:phase:info-tech-canon-service-surface</code>
(WP-0008-T05, 2026-08-05). Live at (WP-0008-T05, 2026-08-05). Further Phases require an explicit declaration act.
<a href="https://revenue.coulomb.social/ui/">revenue.coulomb.social/ui/</a>. Visual language vendored from <code>whynot-design</code> — see
<code>static/whynot-design/VENDORED.md</code>.
</p> </p>
<script> <script>
// Mirror wn-* named fields into real form fields when Lit components are present. // whynot-design's wn-input/wn-select/wn-textarea/wn-button are plain Lit
// Native <input>/<button> work without this; this keeps dual support. // components, not form-associated custom elements — their real <input>/
// <select>/<button> live inside shadow DOM, invisible to an ancestor
// <form>. Without this, clicking a wn-button[type=submit] does nothing,
// and even if it did, none of the field values would be part of the POST.
// This bridges both gaps generically, for every .wn-form on every page,
// without touching the vendored library itself.
(function () { (function () {
function readValue(el) { function readValue(el) {
var native = el.shadowRoot && el.shadowRoot.querySelector("input, select, textarea"); var native = el.shadowRoot && el.shadowRoot.querySelector("input, select, textarea");
return native ? native.value : (el.value != null ? el.value : ""); return native ? native.value : (el.value != null ? el.value : "");
} }
document.querySelectorAll("form").forEach(function (form) { document.querySelectorAll("form").forEach(function (form) {
form.addEventListener("submit", function () { form.addEventListener("submit", function () {
form.querySelectorAll("[name]").forEach(function (el) { form.querySelectorAll("[name]").forEach(function (el) {
@ -86,6 +84,7 @@
hidden.value = readValue(el); hidden.value = readValue(el);
}); });
}); });
form.querySelectorAll("wn-button[type=submit]").forEach(function (btn) { form.querySelectorAll("wn-button[type=submit]").forEach(function (btn) {
btn.addEventListener("click", function () { btn.addEventListener("click", function () {
if (typeof form.requestSubmit === "function") form.requestSubmit(); if (typeof form.requestSubmit === "function") form.requestSubmit();

View file

@ -6,7 +6,7 @@
</wn-page-header> </wn-page-header>
{% if session_rights in ("operator", "admin") %} {% if session_rights in ("operator", "admin") %}
<p><a href="{{ root_path }}/phases/new">+ Register a new Phase</a></p> <p><a >+ Register a new Phase</a></p>
{% endif %} {% endif %}
{% if phases %} {% if phases %}
@ -18,7 +18,7 @@
<td>{{ phase.phase.id }}</td> <td>{{ phase.phase.id }}</td>
<td>{{ phase.phase.milestone_release.name }}</td> <td>{{ phase.phase.milestone_release.name }}</td>
<td>{{ phase.phase.initial_target.amount }} {{ phase.phase.initial_target.currency }}</td> <td>{{ phase.phase.initial_target.amount }} {{ phase.phase.initial_target.currency }}</td>
<td><a href="{{ root_path }}/phases/{{ phase.phase.id }}">View</a></td> <td><a >View</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -31,10 +31,10 @@
<td>{{ ext.licensor_id }}</td> <td>{{ ext.licensor_id }}</td>
<td> <td>
{% if session_rights == "admin" and ext.status == "registered" %} {% if session_rights == "admin" and ext.status == "registered" %}
<form method="post" action="{{ root_path }}/extensions/promote" style="display:inline" class="wn-form"> <form method="post" style="display:inline" class="wn-form">
<input type="hidden" name="extension_id" value="{{ ext.extension_id }}"> <input type="hidden" name="extension_id" value="{{ ext.extension_id }}">
<input type="hidden" name="version" value="{{ ext.version }}"> <input type="hidden" name="version" value="{{ ext.version }}">
<button type="submit" class="secondary">Promote to canonical</button> <wn-button type="submit" variant="secondary">Promote to canonical</wn-button>
</form> </form>
{% endif %} {% endif %}
</td> </td>
@ -53,35 +53,35 @@
{% if session_rights in ("operator", "admin") %} {% if session_rights in ("operator", "admin") %}
<h3>Register a new extension</h3> <h3>Register a new extension</h3>
<form class="wn-form" method="post" action="{{ root_path }}/extensions"> <form class="wn-form" method="post" >
<label>Extension id (trsl:extension:...) <wn-field-row label="Extension id (trsl:extension:...)">
<input name="extension_id" required> <wn-input name="extension_id" required></wn-input>
</label> </wn-field-row>
<label>Version (e.g. 1.0) <wn-field-row label="Version (e.g. 1.0)">
<input name="version" required> <wn-input name="version" required></wn-input>
</label> </wn-field-row>
<label>Value description <wn-field-row label="Value description">
<input name="value_description" required> <wn-input name="value_description" required></wn-input>
</label> </wn-field-row>
<label>Pricing method <wn-field-row label="Pricing method">
<input name="pricing_method" required> <wn-input name="pricing_method" required></wn-input>
</label> </wn-field-row>
<label>Allocation rule <wn-field-row label="Allocation rule">
<input name="allocation_rule" required> <wn-input name="allocation_rule" required></wn-input>
</label> </wn-field-row>
<label>Default rate (01, optional) <wn-field-row label="Default rate (01, optional)">
<input type="number" step="0.01" min="0" max="1" name="default_rate"> <wn-input type="number" step="0.01" min="0" max="1" name="default_rate"></wn-input>
</label> </wn-field-row>
<label>Recognition event <wn-field-row label="Recognition event">
<input name="recognition_event" value="payment-settled" required> <wn-input name="recognition_event" value="payment-settled" required></wn-input>
</label> </wn-field-row>
<label>Reversal rule <wn-field-row label="Reversal rule">
<input name="reversal_rule" required> <wn-input name="reversal_rule" required></wn-input>
</label> </wn-field-row>
<label>Evidence requirement <wn-field-row label="Evidence requirement">
<input name="evidence_requirement" required> <wn-input name="evidence_requirement" required></wn-input>
</label> </wn-field-row>
<button type="submit">Register extension</button> <wn-button type="submit" variant="primary">Register extension</wn-button>
</form> </form>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View file

@ -5,12 +5,10 @@
<span slot="title">Sign in</span> <span slot="title">Sign in</span>
</wn-page-header> </wn-page-header>
<p>Paste the credential token you were issued by an Admin.</p> <p>Paste the credential token you were issued by an Admin.</p>
{# Native controls: reliable under /ui mount even if Lit components fail to hydrate. #} <form class="wn-form" method="post" >
<form class="wn-form" method="post" action="{{ root_path }}/login"> <wn-field-row label="Credential token">
<label> <wn-input type="password" name="token" required></wn-input>
Credential token </wn-field-row>
<input type="password" name="token" required autocomplete="current-password"> <wn-button type="submit" variant="primary">Sign in</wn-button>
</label>
<button type="submit">Sign in</button>
</form> </form>
{% endblock %} {% endblock %}

View file

@ -11,7 +11,7 @@
<p> <p>
Raw reference: <code>{{ manifest.phase.ledger }}</code> Raw reference: <code>{{ manifest.phase.ledger }}</code>
{% if manifest.phase.ledger.startswith('/phases/') %} {% if manifest.phase.ledger.startswith('/phases/') %}
&middot; <a href="{{ manifest.phase.ledger }}">view live JSON</a> &middot; <a >view live JSON</a>
{% endif %} {% endif %}
</p> </p>
</details> </details>
@ -28,7 +28,7 @@
<td>Degeneration policy</td> <td>Degeneration policy</td>
<td> <td>
{{ manifest.phase.degeneration_policy }} {{ manifest.phase.degeneration_policy }}
&middot; <a href="{{ root_path }}/reference/policies/{{ policy_slug(manifest.phase.degeneration_policy) }}">view spec</a> &middot; <a >view spec</a>
</td> </td>
</tr> </tr>
<tr><td>Longstop</td><td>{{ metrics.facts.longstop_at or "—" }}</td></tr> <tr><td>Longstop</td><td>{{ metrics.facts.longstop_at or "—" }}</td></tr>
@ -63,8 +63,8 @@
</tr> </tr>
</table> </table>
{% if session_rights in ("operator", "admin") %} {% if session_rights in ("operator", "admin") %}
<form class="wn-form" method="post" action="{{ root_path }}/phases/{{ manifest.phase.id }}/remission" style="margin-bottom:1.5rem;"> <form class="wn-form" method="post" style="margin-bottom:1.5rem;">
<button type="submit" class="secondary">Apply policy remission now</button> <wn-button type="submit" variant="secondary">Apply policy remission now</wn-button>
<p style="color:#888;font-size:0.85rem;margin-top:0.5rem;"> <p style="color:#888;font-size:0.85rem;margin-top:0.5rem;">
Writes a <code>remission-credit</code> delta under <code>system:policy-engine</code> Writes a <code>remission-credit</code> delta under <code>system:policy-engine</code>
(idempotent — no double-remit if already current). (idempotent — no double-remit if already current).
@ -90,31 +90,31 @@
<h3> <h3>
{% if session_rights == "contributor" %}Propose a Development Credit entry{% else %}Add a Development Credit entry{% endif %} {% if session_rights == "contributor" %}Propose a Development Credit entry{% else %}Add a Development Credit entry{% endif %}
</h3> </h3>
<form class="wn-form" method="post" action="{{ root_path }}/phases/{{ manifest.phase.id }}/ledger"> <form class="wn-form" method="post" >
<label>Entry id (trsl:entry:...) <wn-field-row label="Entry id (trsl:entry:...)">
<input name="entry_id" required> <wn-input name="entry_id" required></wn-input>
</label> </wn-field-row>
<label>Amount <wn-field-row label="Amount">
<input type="number" step="0.01" name="amount" required> <wn-input type="number" step="0.01" name="amount" required></wn-input>
</label> </wn-field-row>
<label>Currency <wn-field-row label="Currency">
<input name="currency" value="{{ manifest.phase.initial_target.currency }}" required> <wn-input name="currency" value="{{ manifest.phase.initial_target.currency }}" required></wn-input>
</label> </wn-field-row>
<label>Recognized at (ISO 8601) <wn-field-row label="Recognized at (ISO 8601)">
<input name="recognized_at" required> <wn-input name="recognized_at" required></wn-input>
</label> </wn-field-row>
<label>Evidence reference <wn-field-row label="Evidence reference">
<input name="evidence_reference" required> <wn-input name="evidence_reference" required></wn-input>
</label> </wn-field-row>
<label>Extension id (trsl:extension:...) <wn-field-row label="Extension id (trsl:extension:...)">
<input name="extension_id" required> <wn-input name="extension_id" required></wn-input>
</label> </wn-field-row>
<label>Extension version <wn-field-row label="Extension version">
<input name="extension_version" required> <wn-input name="extension_version" required></wn-input>
</label> </wn-field-row>
<button type="submit"> <wn-button type="submit" variant="primary">
{% if session_rights == "contributor" %}Submit for review{% else %}Append{% endif %} {% if session_rights == "contributor" %}Submit for review{% else %}Append{% endif %}
</button> </wn-button>
</form> </form>
{% endif %} {% endif %}
@ -180,35 +180,35 @@
an affirmative CUA authorization check (License V1C1 §7.4) — this form an affirmative CUA authorization check (License V1C1 §7.4) — this form
records that assertion; it does not verify the CUA text. records that assertion; it does not verify the CUA text.
</p> </p>
<form class="wn-form" method="post" action="{{ root_path }}/phases/{{ manifest.phase.id }}/breach"> <form class="wn-form" method="post" >
<label>Record id (unique) <wn-field-row label="Record id (unique)">
<input name="record_id" required> <wn-input name="record_id" required></wn-input>
</label> </wn-field-row>
<label>Case id <wn-field-row label="Case id">
<input name="case_id" required> <wn-input name="case_id" required></wn-input>
</label> </wn-field-row>
<label>Event type (alleged|cured|determined|terminated) <wn-field-row label="Event type (alleged|cured|determined|terminated)">
<input name="event_type" value="alleged" required> <wn-input name="event_type" value="alleged" required></wn-input>
</label> </wn-field-row>
<label>Category <wn-field-row label="Category">
<input name="category" required> <wn-input name="category" required></wn-input>
</label> </wn-field-row>
<label>Event at (ISO 8601) <wn-field-row label="Event at (ISO 8601)">
<input name="event_at" required> <wn-input name="event_at" required></wn-input>
</label> </wn-field-row>
<label>Evidence reference (optional) <wn-field-row label="Evidence reference (optional)">
<input name="evidence_reference"> <wn-input name="evidence_reference"></wn-input>
</label> </wn-field-row>
<label>Anonymized (true/false) <wn-field-row label="Anonymized (true/false)">
<input name="anonymized" value="true" required> <wn-input name="anonymized" value="true" required></wn-input>
</label> </wn-field-row>
<label>Named entitlement holder (only if anonymized=false) <wn-field-row label="Named entitlement holder (only if anonymized=false)">
<input name="named_entitlement_holder"> <wn-input name="named_entitlement_holder"></wn-input>
</label> </wn-field-row>
<label>Named disclosure authorized under CUA (true if named) <wn-field-row label="Named disclosure authorized under CUA (true if named)">
<input name="named_disclosure_authorized" value="false"> <wn-input name="named_disclosure_authorized" value="false"></wn-input>
</label> </wn-field-row>
<button type="submit" class="secondary">Publish breach record</button> <wn-button type="submit" variant="secondary">Publish breach record</wn-button>
</form> </form>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View file

@ -6,54 +6,55 @@
</wn-page-header> </wn-page-header>
<p style="color:#888;"> <p style="color:#888;">
This registers a real Phase Manifest against the hosted Trust Service. This registers a real Phase Manifest against the hosted Trust Service.
Further Phases beyond the T05 pilot still need an explicit declaration act. It does not itself authorize going live for a repo — see
<code>workplans/TREV-WP-0008-governance-and-pilot-rollout.md</code> T05.
</p> </p>
<form class="wn-form" method="post" action="{{ root_path }}/phases/new"> <form class="wn-form" method="post" >
<label>Phase id (trsl:phase:...) <wn-field-row label="Phase id (trsl:phase:...)">
<input name="phase_id" required> <wn-input name="phase_id" required></wn-input>
</label> </wn-field-row>
<label>Milestone Release name <wn-field-row label="Milestone Release name">
<input name="milestone_release_name" required> <wn-input name="milestone_release_name" required></wn-input>
</label> </wn-field-row>
<label>Source revision <wn-field-row label="Source revision">
<input name="source_revision" required> <wn-input name="source_revision" required></wn-input>
</label> </wn-field-row>
<label>Repo hub (stable Forgejo instance slug) <wn-field-row label="Repo hub (stable Forgejo instance slug)">
<input name="repo_hub" value="forgejo-coulomb" required> <wn-input name="repo_hub" value="forgejo-coulomb" required></wn-input>
</label> </wn-field-row>
<label>Repo hub URI <wn-field-row label="Repo hub URI">
<input name="repo_hub_uri" value="https://forgejo.coulomb.social" required> <wn-input name="repo_hub_uri" value="https://forgejo.coulomb.social" required></wn-input>
</label> </wn-field-row>
<label>Repo id (Forgejo's own numeric id) <wn-field-row label="Repo id (Forgejo's own numeric id)">
<input type="number" name="repo_id" required> <wn-input type="number" name="repo_id" required></wn-input>
</label> </wn-field-row>
<label>Repo name (owner/repo) <wn-field-row label="Repo name (owner/repo)">
<input name="repo_name" required> <wn-input name="repo_name" required></wn-input>
</label> </wn-field-row>
<label>Base Phase id (optional — only for a successive Phase) <wn-field-row label="Base Phase id (optional — only for a successive Phase)">
<input name="base_phase_id"> <wn-input name="base_phase_id"></wn-input>
</label> </wn-field-row>
<label>Initial Target amount <wn-field-row label="Initial Target amount">
<input type="number" step="0.01" name="initial_target_amount" required> <wn-input type="number" step="0.01" name="initial_target_amount" required></wn-input>
</label> </wn-field-row>
<label>Currency (ISO 4217) <wn-field-row label="Currency (ISO 4217)">
<input name="currency" value="EUR" required> <wn-input name="currency" value="EUR" required></wn-input>
</label> </wn-field-row>
<label>Future License <wn-field-row label="Future License">
<select name="future_license"> <wn-select name="future_license">
<option value="MIT">MIT</option> <option value="MIT">MIT</option>
<option value="Apache-2.0">Apache-2.0</option> <option value="Apache-2.0">Apache-2.0</option>
</select> </wn-select>
</label> </wn-field-row>
<label>Degeneration policy <wn-field-row label="Degeneration policy">
<input name="degeneration_policy" value="trsl:policy:linear-longstop-v0@1.0" required> <wn-input name="degeneration_policy" value="trsl:policy:linear-longstop-v0@1.0" required></wn-input>
</label> </wn-field-row>
<p style="margin-top:-0.5rem;color:#888;font-size:0.85rem;"> <p style="margin-top:-0.5rem;color:#888;font-size:0.85rem;">
<a href="{{ root_path }}/reference/policies/linear-longstop-v0">view the linear-longstop-v0 spec</a> <a >view the linear-longstop-v0 spec</a>
</p> </p>
<label>Longstop date (ISO 8601) <wn-field-row label="Longstop date (ISO 8601)">
<input name="longstop_at" required> <wn-input name="longstop_at" required></wn-input>
</label> </wn-field-row>
<button type="submit">Register Phase</button> <wn-button type="submit" variant="primary">Register Phase</wn-button>
</form> </form>
{% endblock %} {% endblock %}

View file

@ -16,11 +16,11 @@
<td>{{ p.entry.amount }}</td> <td>{{ p.entry.amount }}</td>
<td>{{ p.created_at }}</td> <td>{{ p.created_at }}</td>
<td> <td>
<form method="post" action="{{ root_path }}/proposals/{{ p.id }}/approve" style="display:inline"> <form method="post" style="display:inline">
<button type="submit">Approve</button> <wn-button type="submit" variant="primary">Approve</wn-button>
</form> </form>
<form method="post" action="{{ root_path }}/proposals/{{ p.id }}/reject" style="display:inline"> <form method="post" style="display:inline">
<button type="submit" class="secondary">Reject</button> <wn-button type="submit" variant="secondary">Reject</wn-button>
</form> </form>
</td> </td>
</tr> </tr>