diff --git a/hub/CHANGELOG.md b/hub/CHANGELOG.md
index 57be110..b5c97ca 100644
--- a/hub/CHANGELOG.md
+++ b/hub/CHANGELOG.md
@@ -1,5 +1,24 @@
# Felhom Hub — Changelog
+## v0.68.1 — fix the Configuration page layout broken by the wrapper-sha field (2026-07-21)
+
+The v0.68.0 wrapper-sha256 row wrapped itself in a `
`. The artifacts **`
` closed the surrounding CARD from
+inside the form, and the newly-opened `
` was never closed — it swallowed the submit button and
+ran to ``. The row rendered outside the card at full page width and "Save artifact manifest"
+landed inline. Reported by the operator on first use.
+
+The field still submitted (it remained inside the form), so this was layout damage rather than data
+loss — but the unbalanced markup put every section below it inside the wrong container.
+
+Fixed by making the row plain grid cells (`grid-column: 2 / 4` for the input and the hint), with no
+nested elements at all.
+
+**There was no render assertion on this form**, which is why a hand-edit could break it silently.
+`TestConfigurationArtifactsForm_Structure` now asserts the field is inside the form, the submit
+button has not escaped, the form contains **zero** `
`s, whole-page div balance holds, and the
+sections that render after it still exist. Red-proofed by restoring the broken shape.
+
## v0.68.0 — a credential re-issue finally re-arms the box (R-39 fleet fix) + wrapper drift is visible (R-50b(a)) (2026-07-21)
**Coupling, stated honestly: this release is SAFE for agents at 0.90.0** — the new descriptor field
diff --git a/hub/internal/web/artifacts_form_render_test.go b/hub/internal/web/artifacts_form_render_test.go
new file mode 100644
index 0000000..ca1221d
--- /dev/null
+++ b/hub/internal/web/artifacts_form_render_test.go
@@ -0,0 +1,113 @@
+package web
+
+import (
+ "bytes"
+ "net/http/httptest"
+ "regexp"
+ "strings"
+ "testing"
+
+ "gitea.dooplex.hu/admin/felhom-hub/internal/store"
+)
+
+// R-50b(a) — the wrapper-sha field must render INSIDE the artifact form, and the form's grid must
+// stay structurally intact.
+//
+// This test exists because the first attempt at this field shipped broken: it wrapped the row in a
+//
and, since the
` closed the surrounding CARD from inside the form and the newly-opened
was
+// never closed — it swallowed the submit button and ran to . The page rendered with the row
+// escaped outside the card and the Save button inline. Nothing failed: there was no render
+// assertion on this form at all.
+func TestConfigurationArtifactsForm_Structure(t *testing.T) {
+ s, _ := newTestServer(t)
+ data := map[string]interface{}{
+ "CSRFToken": "tok",
+ "CSRFField": s.csrfField(httptest.NewRequest("GET", "/", nil)),
+ "AssetCount": 0,
+ "AssetLastSync": "",
+ "GlobalFloor": "0.86.0",
+ "Artifacts": store.ArtifactManifest{
+ AgentVersion: "0.91.2",
+ GoldenVersion: "0.153.0",
+ MinAgent: "0.91.2",
+ WrapperSHA256: "104db0a4401f65bbc476e82bfb1796433bcb36f8f8cce69efb3bb5c40fcb16b3",
+ },
+ }
+ var buf bytes.Buffer
+ if err := s.templates.ExecuteTemplate(&buf, "configuration.html", data); err != nil {
+ t.Fatalf("render: %v", err)
+ }
+ body := buf.String()
+
+ // 1. The field renders, carries its stored value, and is reachable for the operator.
+ if !strings.Contains(body, `name="wrapper_sha256"`) {
+ t.Fatal("the wrapper sha256 input is missing from the Configuration page")
+ }
+ if !strings.Contains(body, "104db0a4401f65bbc476e82bfb1796433bcb36f8f8cce69efb3bb5c40fcb16b3") {
+ t.Error("the stored wrapper sha256 is not rendered into the field — the operator cannot see what is vouched")
+ }
+
+ // 2. THE STRUCTURAL ASSERTION. It must sit inside the artifacts