Explain a debt refusal with facts about the item
Reasons are the auditable explanation of a pure decision, so one that describes the architecture rots the moment the architecture moves. The operational refusal asserted that manual interventions were recorded by no event type: true when written, false the day OperatorInterventionRecorded landed, and still printed under every refusal after that. It now reports the counts and the thresholds they missed. Why a count is zero is not this function's business, since no intervention happening, none being recorded, and none being migrated all read the same from here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVbaKucEYBjMqVeUgJUsc1
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// Runs the debt projection over a captured event log and prints one row per
|
||||
// item, so two builds can be compared on identical input. The point of the
|
||||
// comparison is the signature fix: cross-task incidents must collapse into one
|
||||
// item while genuinely different failures stay separate.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"orchestra/internal/domain"
|
||||
"orchestra/internal/operations"
|
||||
"orchestra/internal/store"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b, err := os.ReadFile(os.Args[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var events []domain.Event
|
||||
if err := json.Unmarshal(b, &events); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ledger := store.ProjectDebt(events)
|
||||
eligible := map[string]operations.DebtCandidate{}
|
||||
for _, c := range operations.EligibleDebt(ledger) {
|
||||
eligible[c.Item.ID] = c
|
||||
}
|
||||
rows := make([]map[string]any, 0, len(ledger.Items))
|
||||
for _, item := range ledger.Items {
|
||||
tasks := map[string]bool{}
|
||||
intensity := 0
|
||||
for _, o := range item.Observations {
|
||||
if o.TaskID != "" {
|
||||
tasks[o.TaskID] = true
|
||||
}
|
||||
intensity += o.Repeats
|
||||
}
|
||||
row := map[string]any{
|
||||
"signature": item.ID, "class": string(item.Class),
|
||||
"recurrence": len(item.Observations), "intensity": intensity,
|
||||
"tasks": len(tasks), "eligible": false, "reasons": []string{},
|
||||
}
|
||||
check := operations.CheckDebtEligibility(item)
|
||||
row["eligible"] = check.Eligible
|
||||
row["reasons"] = check.Reasons
|
||||
_ = eligible
|
||||
rows = append(rows, row)
|
||||
}
|
||||
sort.Slice(rows, func(i, j int) bool { return rows[i]["signature"].(string) < rows[j]["signature"].(string) })
|
||||
out, _ := json.MarshalIndent(map[string]any{"items": rows, "gaps": ledger.Gaps}, "", " ")
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
@@ -43,9 +43,17 @@ func CheckDebtEligibility(item domain.DebtItem) DebtCheck {
|
||||
if len(why) > 0 {
|
||||
return DebtCheck{true, why}
|
||||
}
|
||||
// Reasons state facts about this item and nothing about the
|
||||
// architecture around it. The second line here used to say manual
|
||||
// interventions were recorded by no event type, which was true when it
|
||||
// was written and false the moment OperatorInterventionRecorded
|
||||
// landed. A decision that is right for a reason that has become a lie
|
||||
// cannot be audited, and why a count is zero is not this function's
|
||||
// business: no intervention happened, none was recorded, or none was
|
||||
// migrated all read the same from here.
|
||||
return DebtCheck{false, []string{
|
||||
fmt.Sprintf("needs 3 occurrences across 2 tasks, or 1 manual intervention; has %d across %d tasks with %d interventions", recurrence, tasks, manual),
|
||||
"manual interventions are not recorded by any event type, so that count reads 0 on every current log",
|
||||
fmt.Sprintf("breadth threshold not met: %d occurrences across %d tasks, needs 3 across 2", recurrence, tasks),
|
||||
fmt.Sprintf("manual intervention threshold not met: %d recorded, needs 1", manual),
|
||||
}}
|
||||
case domain.DebtStructural:
|
||||
if recurrence >= 3 {
|
||||
|
||||
@@ -62,7 +62,17 @@ func TestDebtRefusalNamesTheMissingEvidence(t *testing.T) {
|
||||
t.Fatalf("want a refusal with reasons, got %+v", check)
|
||||
}
|
||||
joined := strings.Join(check.Reasons, " ")
|
||||
if !strings.Contains(joined, "manual interventions are not recorded") {
|
||||
t.Fatalf("the refusal must say the intervention count is structurally zero: %v", check.Reasons)
|
||||
// Every reason is a fact about this item. The old text asserted that no
|
||||
// event type recorded manual interventions, which stopped being true the
|
||||
// day one did, leaving a correct decision explained by a lie.
|
||||
for _, want := range []string{"1 occurrences across 1 tasks", "0 recorded, needs 1"} {
|
||||
if !strings.Contains(joined, want) {
|
||||
t.Fatalf("the refusal does not state %q: %v", want, check.Reasons)
|
||||
}
|
||||
}
|
||||
for _, forbidden := range []string{"event type", "every current log"} {
|
||||
if strings.Contains(joined, forbidden) {
|
||||
t.Fatalf("a reason describes the architecture instead of the item: %v", check.Reasons)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user