update
This commit is contained in:
@@ -74,7 +74,7 @@ async def _ziele_bilden(ctx: llm.Kontext) -> None:
|
||||
for a in rest:
|
||||
db.update("atome", "id", a["id"], ziel_id=ziel_id)
|
||||
|
||||
await asyncio.gather(*(eine_gruppe(s, g) for s, g in gruppen.items()))
|
||||
await llm.alle(eine_gruppe(s, g) for s, g in gruppen.items())
|
||||
|
||||
|
||||
# ── Zyklen brechen ────────────────────────────────────────────────────────────
|
||||
@@ -220,8 +220,11 @@ def _bausteine_schneiden(ctx: llm.Kontext) -> None:
|
||||
kleine = sorted([k for k, g in gruppen.items() if len(g) < BAUSTEIN_MIN_ATOME],
|
||||
key=lambda k: len(gruppen[k]))
|
||||
for k in kleine:
|
||||
passende = [p for p in gruppen if p != k and p[1] == k[1]
|
||||
and len(gruppen[p]) + len(gruppen[k]) <= BAUSTEIN_MAX_ATOME]
|
||||
# nur Level-Gleichheit als Schranke — die MAX-Grenze fiel weg, weil der
|
||||
# Split große Gruppen ohnehin bandkonform zerlegt. Sonst blieb eine
|
||||
# kleine Gruppe ohne passenden Partner als Unter-Band-Baustein liegen,
|
||||
# den messen dann als unreparierbaren band-Befund meldete.
|
||||
passende = [p for p in gruppen if p != k and p[1] == k[1]]
|
||||
if not passende:
|
||||
continue
|
||||
eigener = gruppen_rang(gruppen[k])
|
||||
@@ -249,9 +252,15 @@ def _bausteine_schneiden(ctx: llm.Kontext) -> None:
|
||||
z = ziele.get(ziel_id, {})
|
||||
titel = z.get("titel") or z.get("text", "Baustein") # Kurztitel; Zieltext nur Fallback
|
||||
n_teile = -(-len(gruppe) // BAUSTEIN_MAX_ATOME)
|
||||
groesse = -(-len(gruppe) // n_teile)
|
||||
# gleichverteilt statt ceil-Scheiben: der letzte Teil war sonst der Rest
|
||||
# (43→8,8,8,8,8,3 verletzt das Band). divmod → 43→8,7,7,7,7,7; mit
|
||||
# MIN≤MAX/2 liegt jeder Teil bei n_teile≥2 beweisbar im Band.
|
||||
basis, rest_teile = divmod(len(gruppe), n_teile)
|
||||
start = 0
|
||||
for teil in range(n_teile):
|
||||
teil_ids = ordnung[teil * groesse:(teil + 1) * groesse]
|
||||
gr = basis + (1 if teil < rest_teile else 0)
|
||||
teil_ids = ordnung[start:start + gr]
|
||||
start += gr
|
||||
if not teil_ids:
|
||||
continue
|
||||
b_titel = titel if n_teile == 1 else f"{titel} (Teil {teil + 1})"
|
||||
@@ -473,14 +482,13 @@ def messen(ctx: llm.Kontext) -> list[dict]:
|
||||
je_baustein: dict = defaultdict(list)
|
||||
for a in atome:
|
||||
je_baustein[a["baustein_id"]].append(a)
|
||||
# Band-Unterschreitung nur, wo ein Merge MÖGLICH gewesen wäre (kombiniert
|
||||
# ≤ Band) — dieselbe Bedingung wie im Schnitt; eine unerfüllbare Messlatte
|
||||
# pendelt nur die Note (Lektion 75).
|
||||
# Band-Unterschreitung nur, wo der Schnitt einen Merge-Partner HÄTTE (gleiches
|
||||
# Level, anderer Baustein) — der Schnitt mergt jetzt ohne MAX-Schranke und
|
||||
# re-splittet bandkonform, also ist genau das die erfüllbare Messlatte. Eine
|
||||
# einsame Unter-Band-Gruppe ohne Level-Partner meldet nichts (Lektion 75).
|
||||
for b in bausteine:
|
||||
n = len(je_baustein[b["id"]])
|
||||
partner = any(bb["id"] != b["id"] and bb["level"] == b["level"]
|
||||
and len(je_baustein[bb["id"]]) + n <= BAUSTEIN_MAX_ATOME
|
||||
for bb in bausteine)
|
||||
partner = any(bb["id"] != b["id"] and bb["level"] == b["level"] for bb in bausteine)
|
||||
if n > BAUSTEIN_MAX_ATOME or (n < BAUSTEIN_MIN_ATOME and partner):
|
||||
befunde.append({"art": "band", "item": str(b["id"]),
|
||||
"detail": f"{b['titel']}: {n} Atome"})
|
||||
|
||||
Reference in New Issue
Block a user