package handler

import (
	"bytes"
	"context"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"codeberg.org/VARASYS/ZDDC/zddc/internal/config"
	"codeberg.org/VARASYS/ZDDC/zddc/internal/zddc"
)

// auth_invariants_test.go — behavioral lock-in for the admin/elevation/
// WORM invariants. These tests must pass against the CURRENT code before
// the consolidation refactor (single bypass site in InternalDecider) so
// the refactor can be validated against a green baseline.
//
// Each test covers one invariant called out in the security audit. The
// names are deliberately verbose — when one fails, the failure message
// alone tells you which property got broken.

// invariantsFixture sets up a synthetic ZDDC root with:
//
//   - admin@example.com  — root super-admin
//   - alice@example.com  — subtree admin of Project-1/archive/Acme/working
//     (via per-dir .zddc admins:) — used to test
//     subtree scope
//   - bob@example.com    — document_controller role member (gets WORM cr
//     on received/ + issued/ via cascade defaults)
//   - eve@example.com    — non-admin, project_team only (read-only across
//     the project per defaults)
//
// Plus one file each in working/, issued/, received/ so we can exercise
// reads + writes across the cascade.
func invariantsFixture(t *testing.T) (config.Config, string) {
	t.Helper()
	root := t.TempDir()

	mustWriteHelper(t, filepath.Join(root, ".zddc"),
		"admins:\n  - admin@example.com\n"+
			"roles:\n"+
			"  document_controller:\n    members: [bob@example.com]\n"+
			"  project_team:\n    members: [\"*@example.com\"]\n")

	for _, d := range []string{
		"Project-1/archive/Acme/working/eve@example.com",
		"Project-1/archive/Acme/received/Acme-0042",
		"Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test",
	} {
		if err := os.MkdirAll(filepath.Join(root, d), 0o755); err != nil {
			t.Fatalf("mkdir %s: %v", d, err)
		}
	}

	// Register the party (party_source: ssr) so writes under the
	// party_source peers aren't rejected before the WORM/admin checks
	// these invariants actually exercise.
	mustWriteHelper(t, filepath.Join(root, "Project-1/ssr/Acme.yaml"), "kind: SSR\n")

	// Subtree-admin grant: alice administers Project-1/archive/Acme/working/.
	mustWriteHelper(t,
		filepath.Join(root, "Project-1/archive/Acme/working/.zddc"),
		"admins:\n  - alice@example.com\n")

	// Files to act on.
	mustWriteHelper(t,
		filepath.Join(root, "Project-1/archive/Acme/working/eve@example.com/draft.md"),
		"# eve's draft\n")
	mustWriteHelper(t,
		filepath.Join(root, "Project-1/archive/Acme/received/Acme-0042/Acme-0042_A (RFI) - Test.pdf"),
		"%PDF-A\n")
	mustWriteHelper(t,
		filepath.Join(root, "Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test/Acme-0099_0A (IFR) - Test.md"),
		"# issued draft\n")
	zddc.InvalidateCache(root)

	return config.Config{
		Root:          root,
		EmailHeader:   "X-Auth-Request-Email",
		MaxWriteBytes: 64 * 1024,
	}, root
}

// do executes a request with the given email / elevation flag. URL-encoding
// is computed from the path so spaces and parens (real ZDDC filenames)
// round-trip cleanly.
func doReq(cfg config.Config, method, urlPath, email string, elevated bool, body []byte, op string) *httptest.ResponseRecorder {
	u := &url.URL{Path: urlPath}
	req := httptest.NewRequest(method, u.RequestURI(), bytes.NewReader(body))
	if op != "" {
		req.Header.Set(headerOp, op)
	}
	ctx := context.WithValue(req.Context(), EmailKey, email)
	ctx = context.WithValue(ctx, ElevatedKey, elevated)
	req = req.WithContext(ctx)
	rec := httptest.NewRecorder()
	ServeFileAPI(cfg, rec, req)
	return rec
}

// ── Invariant 1 — Un-elevated admin has no admin authority ────────────────

func TestInvariant_UnelevatedAdminCannotBypassWorm(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	target := "/Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test/Acme-0099_0A (IFR) - Test.md"
	rec := doReq(cfg, http.MethodPut, target, "admin@example.com", false, []byte("# mutated\n"), "")
	if rec.Code != http.StatusForbidden {
		t.Fatalf("un-elevated admin write succeeded: status=%d body=%s", rec.Code, rec.Body.String())
	}
}

func TestInvariant_UnelevatedAdminCanEditZddc(t *testing.T) {
	// Config-edit is a STANDING permission: .zddc edits route through the
	// decider as ActionAdmin, which IsConfigEditor grants to a subtree
	// admin WITHOUT elevation (elevation is reserved for the WORM/
	// destructive overrides — see TestInvariant_UnelevatedAdminNoSilentBypass).
	// Exercised at the HTTP boundary: a PUT to a .zddc the principal
	// administers, from an un-elevated admin, must succeed.
	cfg, _ := invariantsFixture(t)
	target := "/Project-1/archive/Acme/working/.zddc"
	rec := doReq(cfg, http.MethodPut, target, "admin@example.com", false, []byte("title: mutated\n"), "")
	if rec.Code != http.StatusOK && rec.Code != http.StatusCreated {
		t.Fatalf("un-elevated admin .zddc write blocked: status=%d body=%s", rec.Code, rec.Body.String())
	}
}

func TestInvariant_ElevatedAdminCanEditZddc(t *testing.T) {
	// Positive control: a super-admin who has elevated CAN write any
	// .zddc. The decider's IsActiveAdmin short-circuit fires in
	// AllowActionFromChainP and the file API write proceeds.
	cfg, _ := invariantsFixture(t)
	target := "/Project-1/archive/Acme/working/.zddc"
	rec := doReq(cfg, http.MethodPut, target, "admin@example.com", true, []byte("title: elevated edit\n"), "")
	if rec.Code != http.StatusOK && rec.Code != http.StatusCreated {
		t.Fatalf("elevated admin .zddc write blocked: status=%d body=%s", rec.Code, rec.Body.String())
	}
}

// ── Invariant 2 — Elevated admin can do everything (positive control) ─────

func TestInvariant_ElevatedAdminBypassesWorm(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	target := "/Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test/Acme-0099_0A (IFR) - Test.md"
	rec := doReq(cfg, http.MethodPut, target, "admin@example.com", true, []byte("# fix-mis-filed\n"), "")
	if rec.Code != http.StatusOK && rec.Code != http.StatusCreated {
		t.Fatalf("elevated admin write blocked: status=%d body=%s", rec.Code, rec.Body.String())
	}
}

// ── Invariant 3 — Subtree admin scope ──────────────────────────────────────

func TestInvariant_ElevatedSubtreeAdminWritesInScope(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	target := "/Project-1/archive/Acme/working/eve@example.com/draft.md"
	rec := doReq(cfg, http.MethodPut, target, "alice@example.com", true, []byte("# alice override\n"), "")
	// alice is subtree admin of Project-1/archive/Acme/working/ — should override eve's
	// fenced auto-own and write through.
	if rec.Code != http.StatusOK && rec.Code != http.StatusCreated {
		t.Fatalf("elevated subtree admin write in scope blocked: status=%d body=%s", rec.Code, rec.Body.String())
	}
}

func TestInvariant_ElevatedSubtreeAdminBlockedOutsideScope(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	// alice is subtree admin of /Project-1/archive/Acme/working/, NOT of /Project-1/archive/.
	target := "/Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test/Acme-0099_0A (IFR) - Test.md"
	rec := doReq(cfg, http.MethodPut, target, "alice@example.com", true, []byte("# out-of-scope\n"), "")
	if rec.Code != http.StatusForbidden {
		t.Fatalf("subtree admin escaped scope: status=%d body=%s", rec.Code, rec.Body.String())
	}
}

// ── Invariant 4 — .zddc strict-ancestor self-elevation prevention ─────────

// Strict-ancestor was retired — a subtree admin owns their .zddc.
// These tests pin the post-change contract: an elevated admin
// granted in /<dir>/.zddc CAN edit that file (add collaborators,
// adjust ACLs, even — accidentally — remove themselves). Footgun
// is recoverable via super-admin restore.

func TestInvariant_SubtreeAdminCanEditOwnSubtreeZddc(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	p := zddc.Principal{Email: "alice@example.com", Elevated: true}
	dir := filepath.Join(cfg.Root, "Project-1/archive/Acme/working")
	chain, err := zddc.EffectivePolicy(cfg.Root, dir)
	if err != nil {
		t.Fatalf("EffectivePolicy: %v", err)
	}
	if !zddc.IsAdminForChain(chain, p.Email) {
		t.Fatalf("subtree admin lost authority to edit own .zddc — strict-ancestor wasn't supposed to apply")
	}
}

func TestInvariant_SubtreeAdminCanEditDeeperZddc(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	p := zddc.Principal{Email: "alice@example.com", Elevated: true}
	dir := filepath.Join(cfg.Root, "Project-1/archive/Acme/working/eve@example.com")
	chain, err := zddc.EffectivePolicy(cfg.Root, dir)
	if err != nil {
		t.Fatalf("EffectivePolicy: %v", err)
	}
	if !zddc.IsAdminForChain(chain, p.Email) {
		t.Fatalf("subtree admin blocked from editing deeper .zddc")
	}
}

// ── Invariant 5 — Empty email never matches ────────────────────────────────

func TestInvariant_EmptyEmailHasNoAuthority(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	target := "/Project-1/archive/Acme/working/eve@example.com/draft.md"
	rec := doReq(cfg, http.MethodPut, target, "", true, []byte("# anon\n"), "")
	if rec.Code != http.StatusForbidden && rec.Code != http.StatusUnauthorized {
		t.Fatalf("empty-email write succeeded: status=%d body=%s", rec.Code, rec.Body.String())
	}
}

// ── Invariant 6 — WORM cr survives for document_controller (no admin) ─────

func TestInvariant_DocControllerCanCreateInWormZone(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	// bob is a document_controller (per role membership) but NOT an admin.
	// He must be able to CREATE new files in received/<tracking>/ even
	// without elevation — the WORM cr grant carries.
	target := "/Project-1/archive/Acme/received/Acme-0042/Acme-0042_B (RFI) - Followup.pdf"
	rec := doReq(cfg, http.MethodPut, target, "bob@example.com", false, []byte("%PDF-B\n"), "")
	if rec.Code != http.StatusOK && rec.Code != http.StatusCreated {
		t.Fatalf("doc_controller blocked from WORM create: status=%d body=%s", rec.Code, rec.Body.String())
	}
}

func TestInvariant_DocControllerCannotOverwriteInWormZone(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	// bob can CREATE in WORM but cannot OVERWRITE — the worm strip
	// removes w/d for everyone, even WORM-listed principals.
	target := "/Project-1/archive/Acme/received/Acme-0042/Acme-0042_A (RFI) - Test.pdf"
	rec := doReq(cfg, http.MethodPut, target, "bob@example.com", false, []byte("%PDF-mutated\n"), "")
	if rec.Code != http.StatusForbidden {
		t.Fatalf("doc_controller bypassed WORM overwrite-strip: status=%d body=%s", rec.Code, rec.Body.String())
	}
}

// ── Invariant 7 — project_team has read but no write ──────────────────────

func TestInvariant_ProjectTeamCanReadCannotWrite(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	// eve is project_team (r at project level) and the file lives under
	// her own working/ home — but she is NOT in any admin list and not
	// elevated, so writes must be ACL-gated.
	//
	// In her own home, eve has auto-own rwcda via the working/<email>/
	// auto-own pattern; the cascade gives her create+write there. So
	// the right test is a write OUTSIDE her home — into a peer's area
	// or into archive.
	target := "/Project-1/archive/Acme/received/Acme-0042/Acme-0042_A (RFI) - Test.pdf"
	rec := doReq(cfg, http.MethodPut, target, "eve@example.com", false, []byte("# eve overwrite\n"), "")
	if rec.Code != http.StatusForbidden {
		t.Fatalf("project_team escaped WORM strip: status=%d body=%s", rec.Code, rec.Body.String())
	}
}

// ── Invariant 8 — Forward-auth endpoint requires admin membership ─────────

func TestInvariant_ForwardAuthEndpointGatesOnAdminsList(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	for _, tc := range []struct {
		email string
		want  int
		why   string
	}{
		{"admin@example.com", http.StatusOK, "root admin"},
		{"alice@example.com", http.StatusForbidden, "subtree admin only — /.auth/admin gates on ROOT admins:, not subtree"},
		{"eve@example.com", http.StatusForbidden, "non-admin"},
		{"", http.StatusForbidden, "anonymous"},
	} {
		req := httptest.NewRequest(http.MethodGet, "/.auth/admin", nil)
		ctx := context.WithValue(req.Context(), EmailKey, tc.email)
		req = req.WithContext(ctx)
		rec := httptest.NewRecorder()
		ServeAuthAdmin(cfg, rec, req)
		if rec.Code != tc.want {
			t.Errorf("/.auth/admin for %q (%s): got %d, want %d",
				tc.email, tc.why, rec.Code, tc.want)
		}
	}
}

// ── Invariant 10 — .zddc write matrix at root / project / subtree ─────────

// TestInvariant_ZddcPutMatrix exercises every (principal × elevation ×
// target) combination for PUT to a .zddc file. The decider's
// IsActiveAdmin short-circuit is the single bypass; this matrix locks
// down that it only fires for an Elevated principal who is named in
// the admins: list of some level on the target's chain.
//
// Targets:
//   - /.zddc                       — root file (root admins: govern)
//   - /Project-1/.zddc             — project file (no on-disk .zddc;
//     write must materialise it; root
//     admins still govern via cascade)
//   - /Project-1/archive/Acme/working/.zddc     — subtree file; alice administers
//     this subtree via its own admins:
//     list (so alice's write doesn't
//     require root-admin authority).
//
// Expected status: 200 or 201 on success; 403 on denial; 404 only when
// resolveTargetPath rejects the path (e.g. empty email gets 403 from
// the decider, not 404).
func TestInvariant_ZddcPutMatrix(t *testing.T) {
	type principal struct {
		email    string
		elevated bool
	}
	rootAdminElevated := principal{"admin@example.com", true}
	rootAdminUnelevated := principal{"admin@example.com", false}
	subtreeAdminElevated := principal{"alice@example.com", true}
	subtreeAdminUnelevated := principal{"alice@example.com", false}
	nonAdmin := principal{"eve@example.com", true}
	anon := principal{"", true}

	const (
		ok  = http.StatusOK
		den = http.StatusForbidden
	)
	cases := []struct {
		name   string
		target string
		who    principal
		want   int
	}{
		// Root .zddc. Config-edit is standing for an admin OF that path: the
		// root super-admin edits the root .zddc un-elevated; a subtree admin
		// (alice) does NOT administer root, so she's denied either way.
		{"root admin elevated → root .zddc", "/.zddc", rootAdminElevated, ok},
		{"root admin un-elevated → root .zddc", "/.zddc", rootAdminUnelevated, ok},
		{"subtree admin elevated → root .zddc", "/.zddc", subtreeAdminElevated, den},
		{"subtree admin un-elevated → root .zddc", "/.zddc", subtreeAdminUnelevated, den},
		{"non-admin → root .zddc", "/.zddc", nonAdmin, den},
		{"anonymous → root .zddc", "/.zddc", anon, den},

		// Project .zddc (no on-disk file yet — PUT creates it). The root admin
		// administers all subtrees (cascade), so standing-edits it un-elevated;
		// alice's admin scope is below this path, so she's out-of-scope.
		{"root admin elevated → project .zddc", "/Project-1/.zddc", rootAdminElevated, http.StatusCreated},
		{"root admin un-elevated → project .zddc", "/Project-1/.zddc", rootAdminUnelevated, http.StatusCreated},
		{"subtree admin elevated (out-of-scope) → project .zddc", "/Project-1/.zddc", subtreeAdminElevated, den},
		{"non-admin → project .zddc", "/Project-1/.zddc", nonAdmin, den},

		// Subtree .zddc (alice administers this subtree). Both the root admin
		// and alice standing-edit it un-elevated; non-admins/anon denied.
		{"root admin elevated → subtree .zddc", "/Project-1/archive/Acme/working/.zddc", rootAdminElevated, ok},
		{"root admin un-elevated → subtree .zddc", "/Project-1/archive/Acme/working/.zddc", rootAdminUnelevated, ok},
		{"subtree admin elevated → subtree .zddc", "/Project-1/archive/Acme/working/.zddc", subtreeAdminElevated, ok},
		{"subtree admin un-elevated → subtree .zddc", "/Project-1/archive/Acme/working/.zddc", subtreeAdminUnelevated, ok},
		{"non-admin → subtree .zddc", "/Project-1/archive/Acme/working/.zddc", nonAdmin, den},
		{"anonymous → subtree .zddc", "/Project-1/archive/Acme/working/.zddc", anon, den},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			cfg, _ := invariantsFixture(t)
			body := []byte("title: matrix probe\n")
			rec := doReq(cfg, http.MethodPut, tc.target, tc.who.email, tc.who.elevated, body, "")
			if tc.want == den {
				if rec.Code != http.StatusForbidden && rec.Code != http.StatusUnauthorized {
					t.Fatalf("want denial, got %d body=%s", rec.Code, dumpBody(rec))
				}
			} else if rec.Code != tc.want {
				t.Fatalf("want %d, got %d body=%s", tc.want, rec.Code, dumpBody(rec))
			}
		})
	}
}

// TestInvariant_ZddcDeleteMatrix mirrors ZddcPutMatrix for DELETE. The
// project-level .zddc target is dropped (no on-disk file → 404 lives
// outside the auth surface). The cases that remain pin: only an
// elevated admin with authority over the .zddc's directory can drop
// the file.
func TestInvariant_ZddcDeleteMatrix(t *testing.T) {
	type principal struct {
		email    string
		elevated bool
	}
	rootAdminElevated := principal{"admin@example.com", true}
	rootAdminUnelevated := principal{"admin@example.com", false}
	subtreeAdminElevated := principal{"alice@example.com", true}
	subtreeAdminUnelevated := principal{"alice@example.com", false}
	nonAdmin := principal{"eve@example.com", true}

	cases := []struct {
		name   string
		target string
		who    principal
		want   int
	}{
		// .zddc DELETE is also ActionAdmin → standing config-edit within scope.
		{"root admin elevated → subtree .zddc", "/Project-1/archive/Acme/working/.zddc", rootAdminElevated, http.StatusNoContent},
		{"root admin un-elevated → subtree .zddc", "/Project-1/archive/Acme/working/.zddc", rootAdminUnelevated, http.StatusNoContent},
		{"subtree admin elevated → own .zddc", "/Project-1/archive/Acme/working/.zddc", subtreeAdminElevated, http.StatusNoContent},
		{"subtree admin un-elevated → own .zddc", "/Project-1/archive/Acme/working/.zddc", subtreeAdminUnelevated, http.StatusNoContent},
		{"non-admin → subtree .zddc", "/Project-1/archive/Acme/working/.zddc", nonAdmin, http.StatusForbidden},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			cfg, _ := invariantsFixture(t)
			rec := doReq(cfg, http.MethodDelete, tc.target, tc.who.email, tc.who.elevated, nil, "")
			if rec.Code != tc.want {
				t.Fatalf("want %d, got %d body=%s", tc.want, rec.Code, dumpBody(rec))
			}
		})
	}
}

// ── Invariant 11 — anti-bypass: un-elevated admin gets nothing extra ──────

// TestInvariant_UnelevatedAdminNoSilentBypass is the anti-test for the
// elevation gate, scoped to what elevation actually guards now: the
// WORM/destructive overrides. Config-edit (ActionAdmin on .zddc) is a
// STANDING permission and is exercised separately (ZddcPutMatrix /
// ZddcDeleteMatrix / UnelevatedAdminCanEditZddc) — it's deliberately NOT
// here. For every (admin-flavour × probe) below, an un-elevated admin must
// behave exactly like a non-admin: WORM records and other principals' homes
// stay off-limits without elevation. Any pass indicates a bypass leak.
func TestInvariant_UnelevatedAdminNoSilentBypass(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	type op struct {
		method string
		path   string
		body   []byte
		op     string
	}
	probes := []op{
		// WORM writes (ActionWrite / ActionCreate stripped)
		{http.MethodPut, "/Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test/Acme-0099_0A (IFR) - Test.md", []byte("# mutate\n"), ""},
		{http.MethodPut, "/Project-1/archive/Acme/received/Acme-0042/new.pdf", []byte("%PDF\n"), ""},
		{http.MethodDelete, "/Project-1/archive/Acme/issued/2026-05-15_Acme-0099 (IFR) - Test/Acme-0099_0A (IFR) - Test.md", nil, ""},
		// Regular write into someone else's working/ home (no ACL grant)
		{http.MethodPut, "/Project-1/archive/Acme/working/eve@example.com/draft.md", []byte("# steal\n"), ""},
	}

	admins := []struct {
		name  string
		email string
	}{
		{"root super-admin", "admin@example.com"},
		{"subtree admin (alice)", "alice@example.com"},
	}

	for _, a := range admins {
		for _, p := range probes {
			t.Run(a.name+" "+p.method+" "+p.path, func(t *testing.T) {
				rec := doReq(cfg, p.method, p.path, a.email, false, p.body, p.op)
				if rec.Code != http.StatusForbidden {
					t.Fatalf("BYPASS LEAK: %s un-elevated reached %s %s with status %d body=%s",
						a.email, p.method, p.path, rec.Code, dumpBody(rec))
				}
			})
		}
	}
}

// ── Invariant 9 — Profile admin endpoints 404 (not 403) for non-admins ────

func TestInvariant_ProfileAdminEndpointsHideFromNonAdmins(t *testing.T) {
	// These checks lock in the existence-hiding property: non-admins must
	// see 404, never 403, so they can't probe which admin-only resources
	// exist. ServeProfile is the dispatcher (the refactor this test waited
	// on); its adminOnly wrapper denies with 404 before the sub-handler
	// runs, so a nil ring/index is safe for the non-admin paths.
	cfg, _ := invariantsFixture(t)

	adminEndpoints := []string{"/whoami", "/config", "/logs", "/effective-policy", "/reindex"}

	profileGet := func(sub, email string, elevated bool) *httptest.ResponseRecorder {
		req := httptest.NewRequest(http.MethodGet, ProfilePathPrefix+sub, nil)
		ctx := context.WithValue(req.Context(), EmailKey, email)
		ctx = context.WithValue(ctx, ElevatedKey, elevated)
		req = req.WithContext(ctx)
		rec := httptest.NewRecorder()
		ServeProfile(cfg, nil, nil, rec, req)
		return rec
	}

	// Non-admin (eve, project_team only) and anonymous callers must get
	// 404 on every admin endpoint — never 403, never 200.
	for _, who := range []struct {
		email    string
		elevated bool
		label    string
	}{
		{"eve@example.com", false, "non-admin"},
		{"", false, "anonymous"},
		{"admin@example.com", false, "un-elevated admin"}, // sudo-style: no authority until elevated
	} {
		for _, sub := range adminEndpoints {
			rec := profileGet(sub, who.email, who.elevated)
			if rec.Code != http.StatusNotFound {
				t.Errorf("%s GET /.profile%s = %d, want 404 (existence-hiding)", who.label, sub, rec.Code)
			}
		}
	}

	// Positive control: an elevated root admin must NOT get 404 on the
	// gated routes that need no ring/index — proving the 404s above are
	// the admin gate, not a missing route. (/whoami and /config don't
	// touch the log ring or archive index.)
	for _, sub := range []string{"/whoami", "/config"} {
		rec := profileGet(sub, "admin@example.com", true)
		if rec.Code == http.StatusNotFound {
			t.Errorf("elevated admin GET /.profile%s = 404; the gate should admit admins", sub)
		}
	}
}

// dump prints the rec body when t.Logf would help debugging — used in
// failure messages to avoid silently empty 403 cases.
func dumpBody(rec *httptest.ResponseRecorder) string {
	s := rec.Body.String()
	return strings.TrimSpace(s)
}

// Regression: "I'm a document_controller but creating a folder in working/
// says I need document-controller permissions." A DC (role member at the site
// root, NOT an admin, un-elevated) must be able to (1) register a party by
// creating ssr/<party>.yaml and (2) create folders under working/<party>/,
// per the embedded per-peer grants (ssr → document_controller rwc; working →
// document_controller rwcda). Exercises role resolution from a deep peer level
// back to the root role definition.
func TestInvariant_DocumentControllerRegistersPartyAndCreatesInWorking(t *testing.T) {
	cfg, _ := invariantsFixture(t)
	// 1. Register a new party: create ssr/<party>.yaml.
	rec := doReq(cfg, http.MethodPut, "/Project-1/ssr/Beta.yaml", "bob@example.com", false, []byte("kind: SSR\n"), "")
	if rec.Code != http.StatusCreated && rec.Code != http.StatusOK {
		t.Fatalf("DC register party ssr/Beta.yaml: status=%d body=%s (want 201/200)", rec.Code, rec.Body.String())
	}
	zddc.InvalidateCache(cfg.Root)
	// 2. Create a folder under working/<party>/.
	rec2 := doReq(cfg, http.MethodPost, "/Project-1/working/Beta/draft/", "bob@example.com", false, nil, "mkdir")
	if rec2.Code != http.StatusCreated && rec2.Code != http.StatusOK {
		t.Fatalf("DC mkdir working/Beta/draft: status=%d body=%s (want 201/200)", rec2.Code, rec2.Body.String())
	}
}
