Round-4 review returned BLOCKED, and its diagnosis is the sharpest of the four:
my "re-derived by grep" claim was false. The reviewer's grep included `dropped`;
mine had `drop(ped)? every` and missed the bare word — so
MultiCollectionConfiguration.cs:38 ("a 0-weight source is dropped by the
enumerator") never matched. That is the same failure as the previous round, one
level up: I replaced a list of SITES with a list of VERBS I guessed and called it
a class. Fourth consecutive incomplete completeness claim, and again the code twin
of a doc line I had already corrected.
The site is now accurate. The DB default of 1 is still right, but for the reason
decisions.md already gives: a 0 backfill means nothing on a share-of-airtime scale.
The enumerator clamps such a row to the floor, so it rotates rather than vanishing
-- the drop it cited cannot happen since EffectiveWeight replaced the Weight > 0
filter, and A_Non_Positive_Weight_Does_Not_Delete_The_Source pins that.
Method changed, not just the text: instead of guessing which verb a stale claim
might use, enumerate EVERY comment/doc line mentioning weight across the diff and
read them. 41 lines, one false. Both automated passes then produced false
positives on different subjects -- a line-based check flagged EffectiveWeight's
"must not drop..." (the framing verb wraps to the previous line), and a
sentence-aware one flagged ReplacePlaylistItemsHandler's "the item is dropped from
the playlist" (true, and about unknown ORDERS, not weights: PlaylistEnumerator
really has 0 default arms and gates on `enumerator is not null` at :210). Both were
read and cleared rather than counted, which is the only reason this message can say
what it says.
Verification: Build 0 errors; Core.Tests 566; ErsatzTV.Tests 1673; 0 failed; no BOM
on any touched non-generated .cs; decisions-guard exit 0.
Refs #70
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
65 lines
2.8 KiB
C#
65 lines
2.8 KiB
C#
using ErsatzTV.Core.Domain;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
|
|
|
namespace ErsatzTV.Infrastructure.Data.Configurations;
|
|
|
|
public class MultiCollectionConfiguration : IEntityTypeConfiguration<MultiCollection>
|
|
{
|
|
public void Configure(EntityTypeBuilder<MultiCollection> builder)
|
|
{
|
|
builder.ToTable("MultiCollection");
|
|
|
|
builder.Property(mc => mc.Version).IsConcurrencyToken();
|
|
|
|
builder.Property(mc => mc.Name)
|
|
.HasMaxLength(50)
|
|
.HasColumnType("varchar(50)");
|
|
|
|
builder.HasIndex(mc => mc.Name)
|
|
.IsUnique();
|
|
|
|
builder.HasMany(m => m.Collections)
|
|
.WithMany(m => m.MultiCollections)
|
|
.UsingEntity<MultiCollectionItem>(
|
|
j => j.HasOne(mci => mci.Collection)
|
|
.WithMany(c => c.MultiCollectionItems)
|
|
.HasForeignKey(mci => mci.CollectionId)
|
|
.OnDelete(DeleteBehavior.Cascade),
|
|
j => j.HasOne(mci => mci.MultiCollection)
|
|
.WithMany(mc => mc.MultiCollectionItems)
|
|
.HasForeignKey(mci => mci.MultiCollectionId)
|
|
.OnDelete(DeleteBehavior.Cascade),
|
|
j =>
|
|
{
|
|
j.HasKey(mci => new { mci.MultiCollectionId, mci.CollectionId });
|
|
|
|
// default 1 = fair share (#70). Must be a DB default too, or existing rows migrate to 0 --
|
|
// a value that means nothing on a share-of-airtime scale. The enumerator clamps such a
|
|
// row to the floor, so it rotates rather than vanishing; the backfill should still be
|
|
// right at the source.
|
|
j.Property(mci => mci.Weight).HasDefaultValue(1);
|
|
});
|
|
|
|
builder.HasMany(m => m.SmartCollections)
|
|
.WithMany(m => m.MultiCollections)
|
|
.UsingEntity<MultiCollectionSmartItem>(
|
|
j => j.HasOne(mci => mci.SmartCollection)
|
|
.WithMany(c => c.MultiCollectionSmartItems)
|
|
.HasForeignKey(mci => mci.SmartCollectionId)
|
|
.OnDelete(DeleteBehavior.Cascade),
|
|
j => j.HasOne(mci => mci.MultiCollection)
|
|
.WithMany(mc => mc.MultiCollectionSmartItems)
|
|
.HasForeignKey(mci => mci.MultiCollectionId)
|
|
.OnDelete(DeleteBehavior.Cascade),
|
|
j =>
|
|
{
|
|
j.HasKey(mci => new { mci.MultiCollectionId, mci.SmartCollectionId });
|
|
|
|
// mirrors MultiCollectionItem above -- omitting it would silently un-weight
|
|
// every smart-collection member of a multi collection
|
|
j.Property(mci => mci.Weight).HasDefaultValue(1);
|
|
});
|
|
}
|
|
}
|