Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 128 additions & 13 deletions src/v2/lens/inert_carrier.dag
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ fn inert_carrier_rostered_names() -> List<String> {

data empty_inert_carrier_names: List<String> = []


fn list_contains_str(xs: List<String>, target: String) -> Bool {
fold_list(
xs: xs,
Expand All @@ -46,42 +47,156 @@ fn list_contains_str(xs: List<String>, target: String) -> Bool {
)
}

fn count_not_in_roster(names: List<String>, roster: List<String>) -> Int {
// The two populations have OPPOSITE remedies, which is why they are two
// variants and not one located list. UnrosteredInertCarrier: the carrier is
// inert in the live tree and the roster does not admit it -- the repair is to
// give it a live consumer, or (if it is deliberately staged ahead of one) to
// author a roster row with a reason and a dissolution condition.
// StaleInertCarrierRow: the roster admits a carrier that is NO LONGER inert --
// a consumer exists, so the repair is to DELETE the row. Applying either
// remedy to the other population is wrong in both directions: rostering a live
// carrier re-opens the admission the row exists to close, and deleting a row
// for an unrostered carrier removes nothing.
type InertCarrierFinding
= UnrosteredInertCarrier { carrier: String }
| StaleInertCarrierRow { carrier: String }

type InertCarrierPopulations {
unrostered: List<String>
stale_rows: List<String>
}

type InertCarrierRosterVerdict
= InertCarrierRosterClean
| InertCarrierRosterDiverged { findings: List<InertCarrierFinding> }

data empty_inert_carrier_findings: List<InertCarrierFinding> = []


fn names_not_in_roster(names: List<String>, roster: List<String>) -> List<String> {
fold_list(
xs: names,
empty: 0,
cons: fn(count, name) {
if list_contains_str(xs: roster, target: name) { count } else { count + 1 }
empty: empty_inert_carrier_names,
cons: fn(acc, name) {
if list_contains_str(xs: roster, target: name) {
acc
} else {
list_snoc_item(xs: acc, item: name)
}
}
)
}

fn count_stale_roster(roster: List<String>, inert_names: List<String>) -> Int {
fn stale_roster_names(roster: List<String>, inert_names: List<String>) -> List<String> {
fold_list(
xs: roster,
empty: 0,
cons: fn(count, entry) {
if list_contains_str(xs: inert_names, target: entry) { count } else { count + 1 }
empty: empty_inert_carrier_names,
cons: fn(acc, entry) {
if list_contains_str(xs: inert_names, target: entry) {
acc
} else {
list_snoc_item(xs: acc, item: entry)
}
}
)
}

fn count_not_in_roster(names: List<String>, roster: List<String>) -> Int {
length(xs: names_not_in_roster(names: names, roster: roster))
}

fn count_stale_roster(roster: List<String>, inert_names: List<String>) -> Int {
length(xs: stale_roster_names(roster: roster, inert_names: inert_names))
}

fn inert_carrier_findings(names: List<String>, roster: List<String>) -> List<InertCarrierFinding> {
let unrostered = fold_list(
xs: names_not_in_roster(names: names, roster: roster),
empty: empty_inert_carrier_findings,
cons: fn(acc, name) { list_snoc_item(xs: acc, item: UnrosteredInertCarrier { carrier: name }) }
)
fold_list(
xs: stale_roster_names(roster: roster, inert_names: names),
empty: unrostered,
cons: fn(acc, entry) { list_snoc_item(xs: acc, item: StaleInertCarrierRow { carrier: entry }) }
)
}

fn inert_carrier_verdict_from_findings(findings: List<InertCarrierFinding>) -> InertCarrierRosterVerdict {
if is_empty(xs: findings) {
InertCarrierRosterClean
} else {
InertCarrierRosterDiverged { findings: findings }
}
}

fn inert_carrier_roster_verdict(names: List<String>, roster: List<String>) -> InertCarrierRosterVerdict {
inert_carrier_verdict_from_findings(findings: inert_carrier_findings(names: names, roster: roster))
}

fn inert_carrier_live_roster_verdict() -> InertCarrierRosterVerdict {
inert_carrier_roster_verdict(names: inert_carrier_names_live(), roster: inert_carrier_rostered_names())
}

fn inert_carrier_verdict_findings(v: InertCarrierRosterVerdict) -> List<InertCarrierFinding> {
match v {
InertCarrierRosterClean => empty_inert_carrier_findings
InertCarrierRosterDiverged { findings } => findings
}
}

fn inert_carrier_verdict_is_clean(v: InertCarrierRosterVerdict) -> Bool {
is_empty(xs: inert_carrier_verdict_findings(v: v))
}

data empty_inert_carrier_populations: InertCarrierPopulations = InertCarrierPopulations {
unrostered: empty_inert_carrier_names,
stale_rows: empty_inert_carrier_names
}

fn inert_carrier_population_add(acc: InertCarrierPopulations, f: InertCarrierFinding) -> InertCarrierPopulations {
match f {
UnrosteredInertCarrier { carrier } => InertCarrierPopulations {
unrostered: list_snoc_item(xs: acc.unrostered, item: carrier),
stale_rows: acc.stale_rows
}
StaleInertCarrierRow { carrier } => InertCarrierPopulations {
unrostered: acc.unrostered,
stale_rows: list_snoc_item(xs: acc.stale_rows, item: carrier)
}
}
}

fn inert_carrier_populations(v: InertCarrierRosterVerdict) -> InertCarrierPopulations {
fold_list(
xs: inert_carrier_verdict_findings(v: v),
empty: empty_inert_carrier_populations,
cons: fn(acc, f) { inert_carrier_population_add(acc: acc, f: f) }
)
}

fn inert_carrier_unrostered_names(v: InertCarrierRosterVerdict) -> List<String> {
inert_carrier_populations(v: v).unrostered
}

fn inert_carrier_stale_row_names(v: InertCarrierRosterVerdict) -> List<String> {
inert_carrier_populations(v: v).stale_rows
}

fn inert_carrier_clean_holds() -> Bool {
let names = inert_carrier_names_live()
count_not_in_roster(names: names, roster: inert_carrier_rostered_names()) == 0
&& count_stale_roster(roster: inert_carrier_rostered_names(), inert_names: names) == 0
inert_carrier_verdict_is_clean(v: inert_carrier_live_roster_verdict())
}

fn inert_carrier_live_count() -> Int {
length(xs: inert_carrier_names_live())
}

fn inert_carrier_live_unrostered_count() -> Int {
count_not_in_roster(names: inert_carrier_names_live(), roster: inert_carrier_rostered_names())
length(xs: inert_carrier_unrostered_names(v: inert_carrier_live_roster_verdict()))
}

fn inert_carrier_live_stale_roster_count() -> Int {
count_stale_roster(roster: inert_carrier_rostered_names(), inert_names: inert_carrier_names_live())
length(xs: inert_carrier_stale_row_names(v: inert_carrier_live_roster_verdict()))
}

fn inert_carrier_live_declared_count() -> Int {
Expand Down
38 changes: 38 additions & 0 deletions src/v2/lens/inert_carrier_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ import v2.std.text { String }
import v2.lens.inert_carrier {
inert_carrier_clean_holds,
inert_carrier_live_declared_count,
inert_carrier_roster_verdict,
inert_carrier_verdict_is_clean,
inert_carrier_unrostered_names,
inert_carrier_stale_row_names,
list_contains_str,
count_not_in_roster,
count_stale_roster,
empty_inert_carrier_names
Expand All @@ -16,6 +21,7 @@ data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly

data roster_one: List<String> = ["KnownEntry"]
data names_with_unknown: List<String> = ["UnknownEntry"]
data names_known_only: List<String> = ["KnownEntry"]

test fn inert_carrier_no_unrostered_or_stale() -> Bool {
return inert_carrier_clean_holds()
Expand All @@ -32,3 +38,35 @@ test fn count_not_in_roster_detects_unrostered() -> Bool {
test fn count_stale_roster_detects_stale_entry() -> Bool {
return count_stale_roster(roster: roster_one, inert_names: empty_inert_carrier_names) == 1
}

test fn verdict_clean_when_roster_matches_live_inert_names() -> Bool {
return inert_carrier_verdict_is_clean(v: inert_carrier_roster_verdict(names: names_known_only, roster: roster_one))
}

test fn unrostered_population_names_the_carrier_needing_a_row() -> Bool {
let v = inert_carrier_roster_verdict(names: names_with_unknown, roster: empty_inert_carrier_names)
let unrostered = inert_carrier_unrostered_names(v: v)
return inert_carrier_verdict_is_clean(v: v) == false
&& length(xs: unrostered) == 1
&& list_contains_str(xs: unrostered, target: "UnknownEntry")
&& length(xs: inert_carrier_stale_row_names(v: v)) == 0
}

test fn stale_population_names_the_row_needing_deletion() -> Bool {
let v = inert_carrier_roster_verdict(names: empty_inert_carrier_names, roster: roster_one)
let stale = inert_carrier_stale_row_names(v: v)
return inert_carrier_verdict_is_clean(v: v) == false
&& length(xs: stale) == 1
&& list_contains_str(xs: stale, target: "KnownEntry")
&& length(xs: inert_carrier_unrostered_names(v: v)) == 0
}

test fn the_two_populations_are_reported_separately() -> Bool {
let v = inert_carrier_roster_verdict(names: names_with_unknown, roster: roster_one)
let unrostered = inert_carrier_unrostered_names(v: v)
let stale = inert_carrier_stale_row_names(v: v)
return list_contains_str(xs: unrostered, target: "UnknownEntry")
&& (list_contains_str(xs: unrostered, target: "KnownEntry") == false)
&& list_contains_str(xs: stale, target: "KnownEntry")
&& (list_contains_str(xs: stale, target: "UnknownEntry") == false)
}
Loading