Sync work-record index
Some checks failed
Use-case regression gate / usecase-regressions (push) Failing after 6m2s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1370019@bnt-lap001
Assistant-Session: d462dd63-16de-4189-ae70-b9cd6566bf87
This commit is contained in:
tegwick 2026-10-11 23:04:07 +02:00
parent 733c707dc5
commit df18df3377
7 changed files with 96 additions and 19 deletions

View file

@ -23,6 +23,7 @@
| workplan | CSOC-WP-0013 | ready | — | workplans/CSOC-WP-0013-sharing-content-hardening.md |
| workplan | CSOC-WP-0014 | active | — | workplans/CSOC-WP-0014-cohort-transfer-bubble-offramp.md |
| workplan | CSOC-WP-0015 | active | — | workplans/CSOC-WP-0015-communication-runtime-acceptance.md |
| workplan | CSOC-WP-0016 | ready | — | workplans/CSOC-WP-0016-mfa-setup-link.md |
| task | CSOC-WP-0001-T01 | done | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md |
| task | CSOC-WP-0001-T02 | done | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md |
| task | CSOC-WP-0001-T03 | done | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md |
@ -97,6 +98,7 @@
| task | CSOC-WP-0015-T02 | todo | — | workplans/CSOC-WP-0015-communication-runtime-acceptance.md |
| task | CSOC-WP-0015-T03 | wait | — | workplans/CSOC-WP-0015-communication-runtime-acceptance.md |
| task | CSOC-WP-0015-T04 | todo | — | workplans/CSOC-WP-0015-communication-runtime-acceptance.md |
| task | CSOC-WP-0016-T01 | todo | — | workplans/CSOC-WP-0016-mfa-setup-link.md |
| intake | CSOC-IN-0001 | closed | blue | docs/intakes/csoc-residuals.md |
| intake | CSOC-IN-0002 | closed | green | docs/intakes/csoc-residuals.md |
| intake | CSOC-IN-0003 | open | blue | docs/intakes/csoc-residuals.md |

View file

@ -1,4 +1,6 @@
from django.contrib import admin
from django.core.exceptions import ValidationError
from django.db import IntegrityError
from . import pageops
from .models import Space, SpaceMembership
@ -15,7 +17,12 @@ class SpaceAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
with pageops.content_write_lock():
obj.full_clean()
super().save_model(request, obj, form, change)
try:
super().save_model(request, obj, form, change)
except IntegrityError as exc:
raise ValidationError(
{"slug": "This content instance already uses that slug"}
) from exc
list_display = (
"title",

View file

@ -7,7 +7,7 @@ import tempfile
from dataclasses import dataclass, field
from pathlib import Path
from django.db import transaction
from django.db import IntegrityError, transaction
from coulomb_social.apps.members.models import Member
@ -162,12 +162,17 @@ def _import_space_tree(
published = False
try:
with transaction.atomic():
space, created = Space.objects.update_or_create(
tenant_id=tenant_id, slug=space_slug,
defaults={"title": display_title, "description": abstractor,
"visual": visual, "is_active": True,
"content_root": "pages", "default_branch": "main"},
)
try:
space, created = Space.objects.update_or_create(
tenant_id=tenant_id, slug=space_slug,
defaults={"title": display_title, "description": abstractor,
"visual": visual, "is_active": True,
"content_root": "pages", "default_branch": "main"},
)
except IntegrityError as exc:
raise pageops.PageOpsError(
"Content slug belongs to another tenant"
) from exc
report.space_created = created
report.space_updated = not created
for mapped, role in grants:

View file

@ -0,0 +1,49 @@
"""Enforce one content slug per instance.
Forward refuses while any slug, including an inactive row, is stored more than
once. It does not rename, merge, or delete those rows. Reconcile them first,
then migrate again.
Rollback is `manage.py migrate spaces 0002`. That drops
`spaces_space_slug_global_uniq` only. `spaces_space_tenant_slug_uniq` stays,
and no content or membership rows are rewritten. After rollback, application
checks still reject ordinary collisions; a restored legacy duplicate is denied
on read until the rows are reconciled and this migration is applied again.
"""
from django.db import migrations, models
from django.db.models import Count
def refuse_legacy_slug_collisions(apps, schema_editor):
Space = apps.get_model("spaces", "Space")
duplicates = list(
Space.objects.values("slug")
.annotate(n=Count("pk"))
.filter(n__gt=1)
.order_by("slug")
)
if duplicates:
listed = ", ".join(row["slug"] for row in duplicates)
raise RuntimeError(
"Refusing spaces_space_slug_global_uniq: slug-keyed content already "
f"has duplicate rows ({listed}). Reconcile or discontinue those rows "
"before migrating. This migration does not rename, merge, or delete them."
)
class Migration(migrations.Migration):
dependencies = [
("spaces", "0002_space_visual"),
]
operations = [
migrations.RunPython(refuse_legacy_slug_collisions, migrations.RunPython.noop),
migrations.AddConstraint(
model_name="space",
constraint=models.UniqueConstraint(
fields=("slug",),
name="spaces_space_slug_global_uniq",
),
),
]

View file

@ -75,6 +75,13 @@ class Space(models.Model):
fields=["tenant_id", "slug"],
name="spaces_space_tenant_slug_uniq",
),
# Content paths are spaces/<slug>/, shared by every tenant on this
# instance. Inactive rows keep the slug so a later space cannot
# reuse an archived tree.
models.UniqueConstraint(
fields=["slug"],
name="spaces_space_slug_global_uniq",
),
]
indexes = [
models.Index(fields=["tenant_id", "is_active"]),

View file

@ -3,7 +3,7 @@
from __future__ import annotations
from django.core.exceptions import ValidationError
from django.db import transaction
from django.db import IntegrityError, transaction
from django.db.models import Count, Q, QuerySet
from coulomb_social.apps.members.models import Member
@ -111,16 +111,21 @@ def create_space(
if Space.objects.filter(slug=space_slug).exists():
raise pageops.PageOpsError("A space with this slug already exists in this content instance")
space = Space.objects.create(
tenant_id=member.tenant_id,
slug=space_slug,
title=title,
description=abstractor or "",
visual=visual or "",
created_by=member,
content_root="pages",
default_branch="main",
)
try:
space = Space.objects.create(
tenant_id=member.tenant_id,
slug=space_slug,
title=title,
description=abstractor or "",
visual=visual or "",
created_by=member,
content_root="pages",
default_branch="main",
)
except IntegrityError as exc:
raise pageops.PageOpsError(
"A space with this slug already exists in this content instance"
) from exc
SpaceMembership.objects.get_or_create(
space=space,
member=member,

View file

@ -11,6 +11,7 @@ created: "2026-10-11"
updated: "2026-10-11"
flavor: implementation
depends_on: []
state_hub_workstream_id: "bf60ed62-5cbb-5276-80da-6c5dec302a2e"
---
Founder finding F1 from the attended MFA run of 2026-10-11 (user-engine
@ -24,6 +25,7 @@ app.
id: CSOC-WP-0016-T01
status: todo
priority: low
state_hub_task_id: "b8bb27c0-de32-597e-9106-c5657d7ab130"
```
On the signed-in user's session/account details page, add a "Manage authenticator app (optional)"