2518 lines
119 KiB
JSON
2518 lines
119 KiB
JSON
[
|
||
{
|
||
"id": "A-lock-arbiter",
|
||
"why": "the lock bank-apply takes is the same flock a RUN holds; a pin that holds it with LockProject only proves LockProject conflicts with itself",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/store/store.go",
|
||
"find": "\tf, err := acquireLock(dbPath + \".lock\")",
|
||
"replace": "\tf, err := acquireLock(dbPath + \".lock-not-the-run-lock\")"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "B-report-mitigations",
|
||
"why": "canonical_rewrite and preexisting_problems are the two published fields the pack's own named risks are mitigated by",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\trep.CanonicalRewrite = rep.CanonicalRewriteDelta || rep.CanonicalRewriteRejects",
|
||
"replace": "\trep.CanonicalRewrite = false"
|
||
},
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\t\tPreexistingProblems: orEmpty(res.Preexisting),",
|
||
"replace": "\t\tPreexistingProblems: []string{},"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "C-refusal-table-total",
|
||
"why": "a refusal class with no exit number falls into the catch-all 19; the totality gate must enumerate the classes from the SOURCE, constants included",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/refusal.go",
|
||
"find": "\tRefusalDecisionsRejected RefusalClass = \"decisions_rejected\"",
|
||
"replace": "\tRefusalDecisionsRejected RefusalClass = \"decisions_rejected\"\n\n\t// RefusalPlanted is a mutation: a class with no number in refusalExit.\n\tRefusalPlanted RefusalClass = \"planted_class\""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "D-decline-normalizes",
|
||
"why": "the REPLACEMENT half of a decline must match the surface the way the matcher does — an approval written in the simplified form has to fall to a decline written in the traditional one",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "func dropTerms(f *seed.File, src string) []seed.Term {\n\tnk := text.NormalizeSourceKey(src)",
|
||
"replace": "func dropTerms(f *seed.File, src string) []seed.Term {\n\tnk := src"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "E1-ruby-deep-copy",
|
||
"why": "withRubyAliases must copy the alias slices deeply; AttachRubyAliasesToManual appends in place and would reach back into the seed rows the before/after comparison reads again",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\t\te.Aliases = append([]store.GlossaryAlias(nil), e.Aliases...)",
|
||
"replace": "\t\t_ = e.Aliases"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "E2-promotion-note",
|
||
"why": "a promotion carries the owner's note into the delta row",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\tif d.Note != \"\" {\n\t\tt.Note = d.Note\n\t}",
|
||
"replace": "\tif false {\n\t\tt.Note = d.Note\n\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "E3-unreadable-is-not-undecided",
|
||
"why": "an UNREADABLE decision file must stay a loud error; only ABSENT means «nobody has decided anything yet» (the declared-path era is retired, the distinction that survives is absent-vs-unreadable)",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/mining.go",
|
||
"find": "\tdefault:\n\t\treturn false, fmt.Errorf(\"pipeline: %s is not readable: %w\", path, err)\n\t}",
|
||
"replace": "\tdefault:\n\t\treturn false, nil\n\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "F-artifact-paths-absolute",
|
||
"why": "the published artifact paths are absolute; a consumer runs in another working directory, so a relative one names a different file",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/status.go",
|
||
"find": "\t\tMinedDelta: absPath(r.Book.MinedDelta),",
|
||
"replace": "\t\tMinedDelta: r.Book.MinedDelta,"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "G-byte-gate",
|
||
"why": "the second write gate is the BYTES. UNREACHABLE behind the first: *Touched is set only when a decision changed the document, and `next` is the render of the CHANGED document, so bytes-equal implies nothing-changed implies !*Touched. Kept as depth against a coarser future *Touched and pinned as a function contract (TestChangedDocIsTheSecondFence...), which no source mutation of the CALL can reach.",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\tdelta = res.DeltaBytes != nil && res.DeltaTouched &&\n\t\tchangedDoc(st.deltaRaw, res.DeltaBytes, emptyDelta(res.Delta))",
|
||
"replace": "\tdelta = res.DeltaBytes != nil && res.DeltaTouched"
|
||
}
|
||
],
|
||
"expect": "survives"
|
||
},
|
||
{
|
||
"id": "H-decisions-travel-with-the-book",
|
||
"why": "the decision files default beside the BOOK, not beside project_db: they are the user's data and must travel with the book directory in a backup or an export",
|
||
"package": "./internal/config/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/book.go",
|
||
"find": "\tb.MinedDelta = filepath.Join(dir, b.BookID+MinedDeltaSuffix)",
|
||
"replace": "\tb.MinedDelta = filepath.Join(filepath.Dir(b.ProjectDB), b.BookID+MinedDeltaSuffix)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "I-normalize-text",
|
||
"why": "the document the door writes is normalized, which is what keeps a lawful note with a leading newline writable at all",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/seed/normalize.go",
|
||
"find": "func normText(s string) string { return strings.TrimSpace(s) }",
|
||
"replace": "func normText(s string) string { return strings.TrimLeft(s, \"\") }"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "J-render-gate",
|
||
"why": "the render PROVES its bytes read back as the same document; without the equality half it only proves they parse",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\tif reflect.DeepEqual(back, doc) {\n\t\treturn b, nil\n\t}",
|
||
"replace": "\tif reflect.DeepEqual(back, doc) || true {\n\t\treturn b, nil\n\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "K-decision-text-trimmed",
|
||
"why": "the door trims the free text it accepts, the same rule it already applies to src/sense/dst",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\t\td.Kind, d.Note = strings.TrimSpace(d.Kind), strings.TrimSpace(d.Note)",
|
||
"replace": "\t\td.Kind = strings.TrimSpace(d.Kind)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "L-book-id-is-a-path-element",
|
||
"why": "book_id names four files; a separator in it walks the whole set out of the book's directory",
|
||
"package": "./internal/config/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/book.go",
|
||
"find": "\t} else if strings.ContainsAny(b.BookID, `/\\`) || b.BookID == \".\" || b.BookID == \"..\" {",
|
||
"replace": "\t} else if false {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "M-owned-paths-distinct",
|
||
"why": "two config keys on one path means one document silently overwrites the other",
|
||
"package": "./internal/config/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/book.go",
|
||
"find": "\t\t\tif owned[i].path == \"\" || owned[i].path != owned[j].path {\n\t\t\t\tcontinue\n\t\t\t}",
|
||
"replace": "\t\t\tif true {\n\t\t\t\tcontinue\n\t\t\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "N-flag-presence",
|
||
"why": "the flag guards key on the flag being PRESENT, not on its value being non-empty",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "cmd/tmctl/invocation.go",
|
||
"find": "\tif given[\"decisions\"] {",
|
||
"replace": "\tif *decisions != \"\" {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "O-reversed-window",
|
||
"why": "a chapter window that ends before it begins is written, loads, and fires nowhere",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\tif key.Until != 0 && key.Since > key.Until {",
|
||
"replace": "\tif false {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "P-alias-judged-on-the-set",
|
||
"why": "an inert decline is judged AFTER the fold, on the result of the whole call: the term that owns the alias may be approved by another decision of the same set (anchor re-pointed when refuseInertDeclines gained its ApplyInput argument; the attacked property — the ORDER of the two phases — is unchanged)",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\tfoldAccepted(in, rs, &res)\n\trefuseInertDeclines(in, rs, &res)",
|
||
"replace": "\trefuseInertDeclines(in, rs, &res)\n\tfoldAccepted(in, rs, &res)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "Q-note-not-erased-by-omission",
|
||
"why": "a repeat decision that carries no note keeps the note the owner wrote, in BOTH files",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\t\tif note == \"\" {\n\t\t\tnext.Note = r.Note\n\t\t}",
|
||
"replace": "\t\tif false {\n\t\t\tnext.Note = r.Note\n\t\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "R-decisions-cap",
|
||
"why": "the decision document is the one input a USER sizes; uncapped, the engine dies of memory and the platform reads that as a successful run",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\tif len(raw) > maxDecisionsBytes {",
|
||
"replace": "\tif false {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "S-stop-writes-nothing",
|
||
"why": "a SIGTERM between the decision and the write must leave the files untouched",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\tif err := ctx.Err(); err != nil {\n\t\treturn finishReport(verdict, outcomeStopped, book, st, res, writtenFiles{}), err\n\t}",
|
||
"replace": "\tif err := ctx.Err(); err != nil && false {\n\t\treturn finishReport(verdict, outcomeStopped, book, st, res, writtenFiles{}), err\n\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "T-problems-by-subject",
|
||
"why": "a pre-existing fault is recognised per SUBJECT; joined into one string, fixing one term makes every other term's fault look new",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\t\tif errors.As(err, &sp) {\n\t\t\tproblems = append(problems, sp.Problems...)",
|
||
"replace": "\t\tif errors.As(err, &sp) && false {\n\t\t\tproblems = append(problems, sp.Problems...)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "U-signature-honesty",
|
||
"why": "a call that leaves surfaces of the signature map undecided must not read as «done»",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\t\tst.Surfaces++\n\t\tif !handled[nk] {\n\t\t\tst.Undecided++\n\t\t}",
|
||
"replace": "\t\tst.Surfaces++\n\t\tif !handled[nk] && false {\n\t\t\tst.Undecided++\n\t\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "V-manifest-artifacts",
|
||
"why": "the artifact envelope reaches the surface the consumer actually calls",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/manifest.go",
|
||
"find": "\t\tChunksTotal: len(chunks), Artifacts: r.artifacts(),",
|
||
"replace": "\t\tChunksTotal: len(chunks),"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "W-decision-count-cap",
|
||
"why": "the COUNT of decisions is what holds the call inside a caller's timeout; the byte cap admits ~29 000 minimal declines and five minutes of work",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\tif n := len(doc.Decisions); n > maxDecisions {",
|
||
"replace": "\tif n := len(doc.Decisions); false {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "Y-subject-has-no-rendering",
|
||
"why": "a fault's subject is the term's IDENTITY; embedding the rendering makes a fault look new the moment the door changes that term's dst — and gender has no channel through which to fix it",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memseed.go",
|
||
"find": "\t\t\t\tSubject: subjectOf(\"gender\", e.Src, e.Sense, e.SinceCh, e.UntilCh),",
|
||
"replace": "\t\t\t\tSubject: fmt.Sprintf(\"%s\\u2192%s: gender %q\", e.Src, e.Dst, e.Gender),"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "Z-signature-unreadable",
|
||
"why": "a signature map that cannot be parsed must not report as «nothing left undecided»",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\t\t// «everything is decided», which is the one answer this field must never give by accident.\n\t\treturn SignatureState{Map: absPath(path), Unreadable: true}\n\t}",
|
||
"replace": "\t\t// «everything is decided», which is the one answer this field must never give by accident.\n\t\treturn SignatureState{Map: absPath(path)}\n\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "AB-alias-escape",
|
||
"why": "a decline is judged by what the surface DOES after the call; the «it was a term of its own» escape let through a decline that leaves the surface firing as another term's alias",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\t\tif owner, held := aliasOwner(res.Delta, r.key.Src); held {",
|
||
"replace": "\t\tdroppedARow := false\n\t\tfor _, a := range res.Accepted {\n\t\t\tif a.Index == i {\n\t\t\t\tdroppedARow = len(a.Replaced) > 0\n\t\t\t}\n\t\t}\n\t\tif owner, held := aliasOwner(res.Delta, r.key.Src); held && !droppedARow {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "AC-alias-owner-status",
|
||
"why": "only a SIGNED row excludes its surfaces from proposals, so declining the alias of a status:auto row is not inert — and row 199's first format mine is exactly that state",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\t\tif st := strings.TrimSpace(t.Status); st != \"\" && st != \"approved\" {",
|
||
"replace": "\t\tif st := strings.TrimSpace(t.Status); st != \"\" && st != \"approved\" && false {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "AD-loader-partial-set",
|
||
"why": "the loader hands back the entries it built even when it refuses; without them the checks below it cannot see a document that does not load, and repairing loadability reads as introducing everything the blindness was hiding",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memseed.go",
|
||
"find": "\t\t\t\tfmt.Sprintf(\"term %q: a %s term must have a non-empty dst (an empty one is silently inert; only status=auto may lack a dst)\", t.Src, status))",
|
||
"replace": "\t\t\t\tfmt.Sprintf(\"term %q: a %s term must have a non-empty dst (an empty one is silently inert; only status=auto may lack a dst)\", t.Src, status))\n\t\t\tcontinue"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "AE-positionless-subject",
|
||
"why": "the three «record N has no identity» messages key on a POSITION, which moves when an earlier record is removed; the explicit positionless subject is what keeps a shifted position from reading as a new fault",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/problems.go",
|
||
"find": "func (p *problemList) addKeyed(subject, text string) {\n\t*p = append(*p, Problem{Subject: subject, Text: text})\n}",
|
||
"replace": "func (p *problemList) addKeyed(subject, text string) {\n\t_ = subject\n\t*p = append(*p, Problem{Subject: text, Text: text})\n}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "AF-keys-file-reason-covers-all",
|
||
"why": "the reason a refusal gives must describe the command that receives it; a hand-written list left `bank-apply` — the verb this pack added — undescribed by its own refusal",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "cmd/tmctl/invocation.go",
|
||
"find": "The $0 read commands (report/status/export/build/manifest/seed-lint/bank-apply) must not demand provider keys at all (D20.4)",
|
||
"replace": "The $0 read commands (report/status/export/build/manifest/seed-lint) must not demand provider keys at all (D20.4)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "AG-stopped-report",
|
||
"why": "a call stopped by a signal must not PRINT that it applied — not in mode, not in changed, and not in the accepted list, which is the field a consumer iterates",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\t\trep.Mode, rep.Changed, rep.Accepted = \"stopped\", false, []membank.AcceptedDecision{}",
|
||
"replace": "\t\trep.Mode, rep.Changed = \"apply\", true"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "AH-signature-read-error",
|
||
"why": "a signature map that exists but cannot be READ must not report as «nothing left undecided»",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\t\tif errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn SignatureState{} // no run has reached the bank boundary: nothing to count against\n\t\t}",
|
||
"replace": "\t\treturn SignatureState{}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "AI-refused-warns-nothing",
|
||
"why": "canonical_rewrite warns about a mutation that is about to happen; a refused call performs none",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\t\trep.Mode, rep.Changed = \"refused\", false\n\t\trep.Signature = signatureState(book, st.seed.Terms, docsFromDisk(st))",
|
||
"replace": "\t\trep.Mode, rep.Changed = \"refused\", false\n\t\twarn()\n\t\trep.Signature = signatureState(book, st.seed.Terms, docsFromDisk(st))"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "AJ-seed-alias-decline",
|
||
"why": "a decline of a seed ALIAS is inert only while the delta has no row of its own for that surface; when it does, the decline drops it and repairs the collision the report is listing (anchor re-pointed when the refusal gained its second carve-out; the attacked property is unchanged)",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "held &&\n\t\t\t!deltaHoldsSurface(in.Delta, r.key.Src) && !rejectsHoldSurface(in.Rejects, r.key.Src) {",
|
||
"replace": "held && !rejectsHoldSurface(in.Rejects, r.key.Src) {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX1-stop-memory-not-recorded",
|
||
"why": "a stop that does not RECORD what it presented re-stops on the same map forever — the flag stops paying once per novelty",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/mining.go",
|
||
"find": "\tif merr := r.Store.MarkStopPresented(r.Book.BookID, presentedSurfaces(mined)); merr != nil {",
|
||
"replace": "\tif merr := r.Store.MarkStopPresented(r.Book.BookID, nil); merr != nil {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX2-old-stop-semantics",
|
||
"why": "the pre-D39.144 formula — stop on ANY non-empty delta — is the exact regression §4.11 says no test guarded; the flag-model chain must redden on it",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/mining.go",
|
||
"find": "\t\tstopping = hasUnpresentedCluster(mined, presented)",
|
||
"replace": "\t\tstopping = len(mined) > 0 && len(presented) >= 0"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX3-memory-by-representative-only",
|
||
"why": "a memory keyed on the representative alone re-stops when a cluster's first-ranked member changes to an alias of the same entity",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/mining.go",
|
||
"find": "\tfor _, a := range t.Aliases {\n\t\tif nk := text.NormalizeSourceKey(a); nk != \"\" {\n\t\t\tout = append(out, nk)\n\t\t}\n\t}\n\treturn out\n}\n\n// hasUnpresentedCluster",
|
||
"replace": "\t_ = t.Aliases\n\treturn out\n}\n\n// hasUnpresentedCluster"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX4-auto-wire-gated-on-the-flag",
|
||
"why": "§4.3: a raised flag on a NON-stopping run must not switch the auto wire off — the unsigned rows must still ride to the editor",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/mining.go",
|
||
"find": "\t\tif err := r.writeAutoBank(ctx, mined, proposals, ownerHandled(unsignedEngineSurfaces(seed), rejects)); err != nil {\n\t\t\treturn false, err\n\t\t}",
|
||
"replace": "\t\tif !r.VerifyBank {\n\t\t\tif err := r.writeAutoBank(ctx, mined, proposals, ownerHandled(unsignedEngineSurfaces(seed), rejects)); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX5-normalize-one-trigger",
|
||
"why": "the canonical form trims the WHOLE whitespace class, not the one trigger (leading newline) the emitter defect made famous",
|
||
"package": "./internal/seed/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/seed/normalize.go",
|
||
"find": "func normText(s string) string { return strings.TrimSpace(s) }",
|
||
"replace": "func normText(s string) string { return strings.TrimLeft(s, \"\\n\") }"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX6-subject-collapses-to-class",
|
||
"why": "a fault subject without identity lets any pre-existing fault of a class excuse every INTRODUCED fault of that class",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/problems.go",
|
||
"find": "\treturn fmt.Sprintf(\"%s|%s|%s|%d|%d\", class, src, sense, since, until)",
|
||
"replace": "\treturn class"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX7-subject-loses-the-window",
|
||
"why": "a fault subject without the chapter window masks a new fault on the SAME term in ANOTHER window",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/problems.go",
|
||
"find": "\treturn fmt.Sprintf(\"%s|%s|%s|%d|%d\", class, src, sense, since, until)",
|
||
"replace": "\treturn fmt.Sprintf(\"%s|%s|%s\", class, src, sense)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX8-report-paths-relative",
|
||
"why": "the bank-apply report's file paths must be absolute — the consumer runs in its own working directory (the status report pins the same guarantee separately)",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\tif abs, err := filepath.Abs(p); err == nil {\n\t\treturn abs\n\t}\n\treturn p",
|
||
"replace": "\treturn p"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX9-byte-cap-boundary",
|
||
"why": "a document of exactly the byte cap is lawful; > tightened to >= refuses it",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\tif len(raw) > maxDecisionsBytes {",
|
||
"replace": "\tif len(raw) >= maxDecisionsBytes {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX10-count-cap-boundary",
|
||
"why": "a document of exactly the count cap is lawful; > tightened to >= refuses it",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\tif n := len(doc.Decisions); n > maxDecisions {",
|
||
"replace": "\tif n := len(doc.Decisions); n >= maxDecisions {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX12-absolute-paths-not-cleaned",
|
||
"why": "an uncleaned absolute path is a second spelling of a guarded path; the acceptance walked through exactly this and reproduced the data-loss blocker",
|
||
"package": "./internal/config/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/book.go",
|
||
"find": "\t\t\treturn filepath.Clean(p)",
|
||
"replace": "\t\t\treturn p"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX13-retired-keys-honoured",
|
||
"why": "a declared decision-path key must fail naming the cure, never silently resolve to the convention while the operator believes the declared path is in force",
|
||
"package": "./internal/config/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/book.go",
|
||
"find": "\tif b.RetiredMinedDelta != \"\" || b.RetiredMinedRejects != \"\" {",
|
||
"replace": "\tif false && (b.RetiredMinedDelta != \"\" || b.RetiredMinedRejects != \"\") {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX14-map-truncated-in-place",
|
||
"why": "the signature map is read by the other side of the seam; os.WriteFile truncates first and a live reader gets a half-written map",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/mining.go",
|
||
"find": "\tif err := writeFileAtomic(r.signatureMapPath(), mapBytes); err != nil {",
|
||
"replace": "\tif err := os.WriteFile(r.signatureMapPath(), mapBytes, 0o644); err != nil {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX15-envelope-dropped",
|
||
"why": "the map's seam envelope (version + content id) is 17-seam-inbound-law п.3; without it two maps are indistinguishable without a diff",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\tm := seed.SignatureMap{Version: seed.SignatureMapVersion, ID: id, File: content}",
|
||
"replace": "\tm := seed.SignatureMap{File: content}\n\t_ = id"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX16-interleaved-commit",
|
||
"why": "§4.8: both documents are STAGED before either rename; committing the first before staging the second re-opens «half landed» for failures staging would catch with zero bytes moved",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\tif rejectsChanged {\n\t\tif rejectsStage, err = stageFileAtomic(book.MinedRejects, res.RejectBytes); err != nil {\n\t\t\tif deltaStage != nil {\n\t\t\t\tdeltaStage.abort()\n\t\t\t}\n\t\t\treturn wrote, err\n\t\t}\n\t}",
|
||
"replace": "\tif deltaStage != nil {\n\t\tif err := deltaStage.commit(); err != nil {\n\t\t\treturn wrote, err\n\t\t}\n\t\twrote.delta = true\n\t\tdeltaStage = nil\n\t}\n\tif rejectsChanged {\n\t\tif rejectsStage, err = stageFileAtomic(book.MinedRejects, res.RejectBytes); err != nil {\n\t\t\treturn wrote, err\n\t\t}\n\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX17-dir-sync-skipped",
|
||
"why": "the decision files are the user's words: either the directory entries are flushed or the report says durability is unproven — silence is neither",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\tif err := syncDir(filepath.Dir(book.MinedDelta)); err != nil {\n\t\treturn wrote, fmt.Errorf(\"the files are renamed but their directory entries are not proven durable (a host crash could still lose them): %w\", err)\n\t}",
|
||
"replace": "\t_ = syncDir"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX18-write-incomplete-unmapped",
|
||
"why": "a refusal class without a number falls to exit 19 and the consumer loses the one thing the class buys — «re-send the same document»",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "cmd/tmctl/main.go",
|
||
"find": "\tpipeline.RefusalDecisionsRejected: exitDecisionsRejected,\n\tpipeline.RefusalWriteIncomplete: exitWriteIncomplete,",
|
||
"replace": "\tpipeline.RefusalDecisionsRejected: exitDecisionsRejected,"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX19-cap-report-dropped",
|
||
"why": "§4.7: every refusal of the decisions class prints a report, the caps included — the contract's two carriers must not diverge again",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\t\t\treturn capRefusalReport(book, err), err",
|
||
"replace": "\t\t\treturn BankDecisionsReport{}, err"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX20-write-failed-success-shape",
|
||
"why": "the acceptance's repro: EXIT=1 with a success-shaped report over a half-written pair; the write-failed outcome must never print «apply»",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\t\trep.Mode, rep.Changed = \"write_incomplete\", files.delta || files.rejects",
|
||
"replace": "\t\trep.Mode, rep.Changed = \"apply\", true"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX11-window-boundary",
|
||
"why": "a single-chapter window (since == until) is a lawful term of one chapter; > tightened to >= refuses it as a reversal",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\tif key.Until != 0 && key.Since > key.Until {",
|
||
"replace": "\tif key.Until != 0 && key.Since >= key.Until {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX21-dry-run-silently-paid",
|
||
"why": "`tmctl translate --dry-run` used to parse cleanly and run a PAID translation — the flag's silent version inverts the one promise (--dry-run = spends nothing) the caller relies on",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "cmd/tmctl/invocation.go",
|
||
"find": "\tif given[\"dry-run\"] && cmd != \"bank-apply\" && cmd != \"redrive\" {",
|
||
"replace": "\tif false && given[\"dry-run\"] && cmd != \"bank-apply\" && cmd != \"redrive\" {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX22-retry-never-reproves-durability",
|
||
"why": "the retry the write-incomplete class prescribes lands on the byte-no-op branch; without a directory sync there, the one thing exit 15 warned about is never re-proven and the retry answers 0",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\t\tif err := syncDir(filepath.Dir(book.MinedDelta)); err != nil {\n\t\t\treturn finishReport(verdict, outcomeWriteFailed, book, st, res, writtenFiles{}),\n\t\t\t\trefuse(RefusalWriteIncomplete, fmt.Errorf(\"nothing was written by this call, but the directory holding the decision files still cannot be flushed — their durability is unproven: %w\", err))\n\t\t}",
|
||
"replace": "\t\t_ = syncDir"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX23-map-write-failure-downgraded",
|
||
"why": "the map-before-memory ORDER is load-bearing: a run that proceeds past a failed map write stops pointing the owner at a file that is not there and marks the clusters presented — no later flag ever stops on them again (acceptance planting, survived three candidate packages)",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/mining.go",
|
||
"find": "\tif err := writeFileAtomic(r.signatureMapPath(), mapBytes); err != nil {\n\t\treturn false, fmt.Errorf(\"pipeline: the bank-mining stop write signature map %s: %w\", r.signatureMapPath(), err)\n\t}",
|
||
"replace": "\tif err := writeFileAtomic(r.signatureMapPath(), mapBytes); err != nil {\n\t\tr.Log.WarnContext(ctx, \"pipeline: the bank-mining stop write signature map failed\", \"err\", err)\n\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FX24-write-failed-signature-from-intent",
|
||
"why": "the write-failed report must measure the signature against the DISK: fed the call's own result, a class-15 report whose write landed nothing prints undecided:0 — a success-shaped block on the one outcome the honesty work was done for (panel finding, reproduced)",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\t\t// The POST-state, re-read from disk: for an outcome that touched the world the report describes\n\t\t// the files as they now are, never the bytes the call intended.\n\t\trep.Signature = signatureState(book, st.seed.Terms, docsReRead(book))",
|
||
"replace": "\t\t// The POST-state, re-read from disk: for an outcome that touched the world the report describes\n\t\t// the files as they now are, never the bytes the call intended.\n\t\trep.Signature = signatureState(book, st.seed.Terms, docsFromResult(st, res))"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH1-system-join",
|
||
"why": "an endpoint that carries ONE system message must receive the memory-bank injection INSIDE that message; without the join the glossary is dropped by the provider at HTTP 200 and no gate can see it",
|
||
"package": "./internal/llm/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/llm/httpllm.go",
|
||
"find": "\tif mode != SystemMessagesSingle {",
|
||
"replace": "\tif true {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH2-system-axis-from-yaml",
|
||
"why": "the declared quirk has to survive the trip from models.yaml to the resolved Capability; dropped there, the join never runs and the loss is silent again",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/models.go",
|
||
"find": "\tdefault:\n\t\tc.SystemMessages = llm.SystemMessagesMode(cfg.SystemMessages)\n\t}",
|
||
"replace": "\tdefault:\n\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH3-gap-marker",
|
||
"why": "a unit that ships text with a member chunk MISSING must say so in the text a human reads; without the marker the reader gets a seamless concatenation with a hole and no seam",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "cmd/tmctl/render.go",
|
||
"find": "\tm := fmt.Sprintf(\"[⚠ TEXT MISSING — %d source %s of this unit could not be translated and %s NOT in the text below\",",
|
||
"replace": "\tm := fmt.Sprintf(\"[%d %s %s\","
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH4-dropped-members-counted",
|
||
"why": "the incompleteness fact is carried by DroppedMembers, not inferred from a flag reason; stop counting it and both renderers go back to guessing, which is how the reader was told a member drop was a cosmetic clean-up",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/export.go",
|
||
"find": "\tce.DroppedMembers = len(drops)",
|
||
"replace": "\tce.DroppedMembers = 0"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH5-decline-converges",
|
||
"why": "a decline already on the record is a decision being RE-SENT, not one being made; without this carve-out the door refuses the identical document forever and a worker that retries splits the state",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": " && !rejectsHoldSurface(in.Rejects, r.key.Src) {",
|
||
"replace": " {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH6-rejects-rename-first",
|
||
"why": "the delta is the document the seed-conflict refusal READS, so it must not be the one that lands first: a decline interrupted after a delta-first rename leaves a state no predicate can tell from an inert decline, and the re-send is refused forever",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankdecisions.go",
|
||
"find": "\tif rejectsStage != nil {\n\t\tif err := rejectsStage.commit(); err != nil {\n\t\t\tif deltaStage != nil {\n\t\t\t\tdeltaStage.abort()\n\t\t\t}\n\t\t\treturn wrote, err\n\t\t}\n\t\twrote.rejects = true\n\t}\n\tif deltaStage != nil {\n\t\tif err := deltaStage.commit(); err != nil {\n\t\t\treturn wrote, err\n\t\t}\n\t\twrote.delta = true\n\t}",
|
||
"replace": "\tif deltaStage != nil {\n\t\tif err := deltaStage.commit(); err != nil {\n\t\t\tif rejectsStage != nil {\n\t\t\t\trejectsStage.abort()\n\t\t\t}\n\t\t\treturn wrote, err\n\t\t}\n\t\twrote.delta = true\n\t}\n\tif rejectsStage != nil {\n\t\tif err := rejectsStage.commit(); err != nil {\n\t\t\treturn wrote, err\n\t\t}\n\t\twrote.rejects = true\n\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH7-drop-reason-is-the-holes-own",
|
||
"why": "the marker must name why the MEMBER dropped, not the unit's flag reason: a unit whose edit flagged for a cosmetic strip AND lost a member would otherwise tell the reader a clean-up ate a chunk of the book — the same false claim the pack removes, moved into the prose",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "cmd/tmctl/render.go",
|
||
"find": "gapMarker(ce.DroppedMembers, ce.DroppedReason)",
|
||
"replace": "gapMarker(ce.DroppedMembers, ce.FlagReason)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH8-draft-only-has-no-members",
|
||
"why": "a draft-only pipeline makes every chunk a SINGLETON unit whose own draft row is its final row, so the member-drop rule reads the unit's own flag as a lost member; without the guard a cosmetically stripped chunk that lost NOTHING is announced as incomplete — a marker that misinforms, which the order forbids as firmly as the silence it replaces",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/export.go",
|
||
"find": "\tif r.finalStageWave() == waveEdit {",
|
||
"replace": "\tif true {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH9-shipped-gemini-declaration",
|
||
"why": "the two lines in configs/models.yaml are the ONLY thing that makes the system-message join reach the real endpoint; everything else about the fix is exercised against a synthetic fixture provider, and deleting them used to leave the whole module green",
|
||
"package": "./internal/config/",
|
||
"edits": [
|
||
{
|
||
"file": "configs/models.yaml",
|
||
"find": " capabilities:\n system_messages: single\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH10-translate-empty-text-guard",
|
||
"why": "renderTranslate's non-empty-text guards are what stop the gap marker pointing at text that does not exist; the code calls them load-bearing and nothing pinned them",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "cmd/tmctl/render.go",
|
||
"find": "\t\tcase ch.DroppedMembers > 0 && ch.FinalText != \"\":",
|
||
"replace": "\t\tcase ch.DroppedMembers > 0:"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH11-explicit-multi-costs-nothing",
|
||
"why": "writing the DEFAULT out loud must not put a key in the capability the snapshot carries — otherwise a line that changes no byte on the wire re-buys the book",
|
||
"package": "./internal/config/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/models.go",
|
||
"find": "\tcase \"multi\":\n\t\tc.SystemMessages = llm.SystemMessagesMulti",
|
||
"replace": "\tcase \"multi\":\n\t\tc.SystemMessages = llm.SystemMessagesMode(\"multi\")"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH12-declined-never-enters-the-bank",
|
||
"why": "the rejects-first rename order leaves the delta row on disk so an interrupted decline can converge; without this filter that window is one in which a PAID run injects a term the owner explicitly declined",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/mining.go",
|
||
"find": "\t\t\tif rejects[text.NormalizeSourceKey(e.Src)] {",
|
||
"replace": "\t\t\tif false {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "SH13-inert-decline-second-door",
|
||
"why": "the ALIAS door refuses an inert decline for its own good reason, but a decline ALREADY on the record is a decision being re-sent; unnarrowed it refused the standing ledger forever and, the layer being all-or-nothing, discarded the lawful decisions sent beside it",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\t\tif rejectsHoldSurface(in.Rejects, r.key.Src) {\n\t\t\tcontinue\n\t\t}\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC1-book-filter-store",
|
||
"why": "CheckpointUsageForBook's `WHERE j.book_id = ?` is the only thing keeping another book's checkpoints out of the consent number when two books share a project database; removing it left every store and money test green (backlog row 197, ФЧ-1 — reproduced by the acceptance), because no fixture had two books at one position",
|
||
"package": "./internal/store/",
|
||
"run": "TestCheckpointUsageForBookIsScopedToTheBook",
|
||
"edits": [
|
||
{
|
||
"file": "internal/store/ledger.go",
|
||
"find": "\t\tWHERE j.book_id = ?\n\t\tORDER BY c.rowid",
|
||
"replace": "\t\tWHERE j.book_id = ? OR 1 = 1\n\t\tORDER BY c.rowid"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC1-book-filter-pipeline",
|
||
"why": "the same planting judged where the money is published: another book's calls at the same positions, ten times the price, must not overshoot this book's rows into «quoted from history» or move its projected book cost",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestAnotherBooksMoneyNeverEntersTheConsentNumber",
|
||
"edits": [
|
||
{
|
||
"file": "internal/store/ledger.go",
|
||
"find": "\t\tWHERE j.book_id = ?\n\t\tORDER BY c.rowid",
|
||
"replace": "\t\tWHERE j.book_id = ? OR 1 = 1\n\t\tORDER BY c.rowid"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC1-cell-key",
|
||
"why": "the repricer's cell is the POSITION (chapter AND chunk); keyed by chapter alone it pools the neighbours' calls and the newest-first walk eats the neighbour's money — invisible while every money fixture had one chunk per chapter (backlog row 197, ФЧ-1)",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestEveryChunkOfAChapterIsRePricedFromItsOwnCalls",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reprice.go",
|
||
"find": "\t\tkey := chunkKey{cu.Chapter, cu.ChunkIdx}",
|
||
"replace": "\t\tkey := chunkKey{cu.Chapter, 0}"
|
||
},
|
||
{
|
||
"file": "internal/pipeline/reprice.go",
|
||
"find": "\tcalls := rp.cells[chunkKey{cs.Chapter, cs.ChunkIdx}][cs.Stage]",
|
||
"replace": "\tcalls := rp.cells[chunkKey{cs.Chapter, 0}][cs.Stage]"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC1-unpriced-not-disclosed",
|
||
"why": "a call carried at its billed figure (no usable usage) must mark the row as quoted from history; without the mark the amount stays right and every disclosure of «part of this sum is old money» — consent text, status --json, CLI — goes silent (backlog row 197, ФЧ-1 / ФЧ-4)",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestABilledDecodeRowIsDisclosedAsOldMoneyEndToEnd|TestRepricerCountsOnlyTheCurrentGenerationOfCheckpoints",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reprice.go",
|
||
"find": "\t\tif !calls[i].priced {\n\t\t\tfromHistory = true\n\t\t}\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC5-carry-unbounded",
|
||
"why": "the volume grant admits units an earlier run started and never shipped OUTSIDE the grant, and that carry must be bounded BY the grant; unbounded, a run that drafted a whole book hands every unit to the next purchase and --max-units stops bounding anything (measured on a fixture: a grant of one paid for five units)",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheCarryIsBoundedByTheGrant",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "\t\tif s.stop.Carried >= r.MaxUnits {\n\t\t\ts.stop.LeftFresh++\n\t\t\tcontinue\n\t\t}\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC5-model-axis-configured-slot",
|
||
"why": "the re-payment prices a stored call at the model its stage RESOLVES to (label routing applied), not at the configured `model:` key; reading the configured slot prices a labelled book's re-payment at a model the run never calls, and no other test in the tree tells the two slots apart",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheModelAxisReadsTheRESOLVEDSlotNotTheConfiguredOne",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reprice.go",
|
||
"find": "\t\tif escalation && st.ResolvedHop != \"\" {\n\t\t\treturn st.ResolvedHop, true\n\t\t}\n\t\treturn st.ResolvedModel, st.ResolvedModel != \"\"",
|
||
"replace": "\t\tif escalation && st.EscalateTo != \"\" {\n\t\t\treturn st.EscalateTo, true\n\t\t}\n\t\treturn st.Model, st.Model != \"\""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC6-reconcile-fresh-branch",
|
||
"why": "reconcile's docstring claims EVERY branch keeps Carried inside Delivered, and granted() = Delivered - Carried + Reworked depends on it; the fresh branch reverted to `Delivered > 0` drives the grant arithmetic negative and prints «0 NEW unit(s) delivered» beside «1 of the new ones had been started by an earlier run» — a sentence that cannot be true",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestReconcileKeepsContainmentOnTheFreshBranch",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "\t\tcase class == unitFresh && s.stop.Delivered > s.stop.Carried:",
|
||
"replace": "\t\tcase class == unitFresh && s.stop.Delivered > 0:"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC6-capped-refusal-borrows-book-basis",
|
||
"why": "the --accept-rebill=<usd> refusal quotes THIS run's figure, so it must carry THIS run's basis; borrowing the book's tells a caller sizing their cap that more units are an upper estimate than the number beside it covers. Its twin, the threshold refusal's scoped clause, was pinned from the start; this branch was not",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheScopedClauseOfTheRefusalCarriesItsOwnBasis",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/rebill.go",
|
||
"find": "\t\t\tproj.USD, proj.Rows, projectionBasis(proj), r.AcceptRebill.CapUSD, r.AcceptRebill.CapUSD)",
|
||
"replace": "\t\t\tproj.USD, proj.Rows, projectionBasis(book), r.AcceptRebill.CapUSD, r.AcceptRebill.CapUSD)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC6-model-caveat-printed-at-zero",
|
||
"why": "a caveat that prints when its count is zero puts «0 of the N unit(s) were bought from a model their stage no longer resolves to» into EVERY consent text; a reader who learns to skip it skips it when it means something. The old-money twin has had this negative pin since it was written",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestProjectionBasisNamesWhatTheAmountIsMadeOf",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/rebill.go",
|
||
"find": "\tif p.ModelMovedRows > 0 {",
|
||
"replace": "\tif p.ModelMovedRows >= 0 {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC6-escalation-flag-store",
|
||
"why": "the re-pricing reads the escalation flag through CheckpointUsageForBook to know that a hop call's «today» is the stage's current escalate_to; dropping the column from the SELECT survives the store's own battery and only the pipeline's goes red — the same one-sided seam the book filter is pinned on both sides for",
|
||
"package": "./internal/store/",
|
||
"run": "TestCheckpointUsageCarriesTheEscalationFlag",
|
||
"edits": [
|
||
{
|
||
"file": "internal/store/ledger.go",
|
||
"find": "\t\t c.escalation\n\t\tFROM checkpoints c JOIN jobs j ON j.id = c.job_id",
|
||
"replace": "\t\t 0\n\t\tFROM checkpoints c JOIN jobs j ON j.id = c.job_id"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC7-volume-stop-silent-outside-grant",
|
||
"why": "a run that finished units an earlier run began delivered MORE than its grant, and the stop line is the only channel that says why; judged by the remainder alone the report goes silent in exactly the case with the largest discrepancy",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestARunThatWorkedOutsideItsGrantSaysSo",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "func (s *volumeScope) bound() bool { return s != nil && (s.stop.Left() > 0 || s.stop.Carried > 0) }",
|
||
"replace": "func (s *volumeScope) bound() bool { return s != nil && s.stop.Left() > 0 }"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC7-reconcile-free-branch",
|
||
"why": "the second fall-through of reconcile must keep Carried inside Delivered too; the guard removed there drives granted() negative on a book with one carried unit and one free unit that flags on resume",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestReconcileKeepsCarriedInsideDelivered",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "\t\tcase s.stop.Delivered > s.stop.Carried:\n\t\t\ts.stop.Delivered--\n\t\tcase s.stop.Carried > 0:\n\t\t\ts.stop.Delivered--\n\t\t\ts.stop.Carried--\n",
|
||
"replace": "\t\tcase s.stop.Delivered > 0:\n\t\t\ts.stop.Delivered--\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC7-zero-usage-row-silent-after-a-move",
|
||
"why": "a $0 row with no usage on file cannot be re-priced once its stage resolves elsewhere — there are no tokens to price at the new model; publishing a bare $0 with no caveat is the silent under-quote D39.150 п.1 forbids",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestRepriceCheckpointFallsBackToTheBilledAmount",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reprice.go",
|
||
"find": "\t\t\ttoday, ok := r.currentModelFor(cu.Stage, cu.Escalation)\n\t\t\treturn 0, !ok || today == cu.ModelRequested, false",
|
||
"replace": "\t\t\treturn 0, true, false"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC7-scoped-clause-without-basis",
|
||
"why": "the threshold refusal prints the BOOK's figure and THIS run's slice; each travels with the basis of the projection it came from, because which of the slice's units are an upper estimate is not something the book's basis states for them",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheScopedClauseOfTheRefusalCarriesItsOwnBasis",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/rebill.go",
|
||
"find": "\t\t\tproj.Rows, proj.USD, projectionBasis(proj), scopedRepin)",
|
||
"replace": "\t\t\tproj.Rows, proj.USD, scopedRepin)"
|
||
},
|
||
{
|
||
"file": "internal/pipeline/rebill.go",
|
||
"find": "would re-pay %d of them, ~$%.6f (%s)%s — but the threshold",
|
||
"replace": "would re-pay %d of them, ~$%.6f%s — but the threshold"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC7-overshoot-claims-a-model-move",
|
||
"why": "the revert/overshoot branch quotes a row at what it was BILLED, which is priced at no model's current table; counting it among the units priced across a model move inflates the caveat with rows the caveat does not describe",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestRepricerCountsOnlyTheCurrentGenerationOfCheckpoints",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reprice.go",
|
||
"find": "\t\treturn cs.CostUSD, true, false\n\t}\n\tif residue := cs.CostUSD - accounted; residue > residueEpsilonUSD {",
|
||
"replace": "\t\treturn cs.CostUSD, true, moved\n\t}\n\tif residue := cs.CostUSD - accounted; residue > residueEpsilonUSD {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC8-free-call-dropped-from-a-paid-generation",
|
||
"why": "a call that cost NOTHING can neither complete a row's cost nor overshoot it, so a walk that stops on money drops it — and with it the price that call carries today. A $0 primary whose PAID escalation hop alone accounts for the row (a local model with a cloud fallback) is then quoted at half what the re-run buys, with no caveat: the silent under-quote D39.150 п.1 forbids",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestRepricerCountsOnlyTheCurrentGenerationOfCheckpoints",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reprice.go",
|
||
"find": "\t\tfree := calls[i].then <= residueEpsilonUSD\n\t\tif accounted >= cs.CostUSD-residueEpsilonUSD && !free {",
|
||
"replace": "\t\tfree := calls[i].then <= residueEpsilonUSD\n\t\t_ = free\n\t\tif accounted >= cs.CostUSD-residueEpsilonUSD {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC8-unestablished-zero-row-published-as-free",
|
||
"why": "a $0 row whose newest call on file belongs to an older generation cannot be caught by the overshoot test — no walk overshoots $0 — so without this it is published as a bare $0 with no caveat; a `skipped` row is genuinely free, any other is one whose generation could not be established",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestRepricerCountsOnlyTheCurrentGenerationOfCheckpoints",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reprice.go",
|
||
"find": "\tif taken == 0 && len(calls) > 0 && cs.Disposition != string(DispSkipped) {\n\t\tfromHistory = true\n\t}\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC8-log-fork-at-the-end-of-the-book",
|
||
"why": "the run log takes the same fork as the operator line: a run that reached the end of the book did NOT stop short of it, and saying so of every bounded run makes the sentence worthless exactly where the grant behaved unusually",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheRunLogSaysWhichKindOfVolumeStopItWas",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "\t\tif scope.stop.Left() == 0 {\n\t\t\tmsg = \"the run reached the end of the book under a VOLUME ceiling that held nothing back; it is reported because units an earlier run began were finished outside this grant\"\n\t\t}\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "FC8-empty-cell-disclosed-as-unestablished",
|
||
"why": "the «generation could not be established» mark is for a $0 row whose calls belong to somebody else, NOT for a row with no call at all — that one is free by construction; without the guard every such row inflates the count of units the operator is told could not be re-priced",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestRepricerCountsOnlyTheCurrentGenerationOfCheckpoints",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reprice.go",
|
||
"find": "\tif taken == 0 && len(calls) > 0 && cs.Disposition != string(DispSkipped) {",
|
||
"replace": "\tif taken == 0 && cs.Disposition != string(DispSkipped) {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB1-head-always-end-of-book",
|
||
"why": "the stop line's two openings are a fork, and only the NEW opening was held: a fork that reaches the end-of-book wording unconditionally passed the whole tree, and in a run whose grant really did cut it short it printed «reached the END of the book … Still in the book: 1 unit(s) NEVER delivered» — the book is finished and a unit of it was never delivered, in one sentence",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheStopLineSaysTheGrantHeldWorkBackWhenItDid",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "\tif v.Left() == 0 {\n\t\thead = \"reached the END of the book",
|
||
"replace": "\tif v.Left() >= 0 {\n\t\thead = \"reached the END of the book"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB2-head-keyed-on-the-carry",
|
||
"why": "the same fork asked about the wrong quantity. Which opening applies is the REMAINDER — did the grant hold work back — not the CARRY, which is why the report is attached at all. Keyed on the carry the fork is right on every state the tree exercised and wrong on the mixed one the carry itself made reachable: work carried AND work held back",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheStopLineSaysTheGrantHeldWorkBackWhenItDid",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "\tif v.Left() == 0 {\n\t\thead = \"reached the END of the book",
|
||
"replace": "\tif v.Carried > 0 {\n\t\thead = \"reached the END of the book"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB3-bound-border-drops-a-single-carry",
|
||
"why": "bound() reports a run that did work OUTSIDE its grant, and the smallest such run is ONE interrupted unit finished at the end of the book. A `> 1` border drops exactly that one: the run delivers a unit it never paid a slot for and returns no report at all — the silent limit D39.165 §1б names. The existing carry test finishes TWO units and survives the border",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestOneCarriedUnitIsStillWorkOutsideTheGrant",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "return s != nil && (s.stop.Left() > 0 || s.stop.Carried > 0) }",
|
||
"replace": "return s != nil && (s.stop.Left() > 0 || s.stop.Carried > 1) }"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB4-cut-tag-drops-the-embedded-data",
|
||
"why": "the cut tag rides inside every unit id, and a component dropped from it is invisible by construction — the id still looks like an id while it now points at different text. The embedded language data decides where boundaries fall (CJK numerals, sentence terminators), so without it an injection.txt edit re-cuts the whole book and re-mints nothing. Found by planting: removing it left the ENTIRE battery green, and this pack's point 3 chose the Go render over the data precisely because that component is load-bearing",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheCutTagActuallyCarriesTheEngineData",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/manifest.go",
|
||
"find": "\t\tChunker: chunkerVersion, Segmentation: r.segmentationSnapshot(), ShippingWave: r.shippingWaveTag(),\n\t\tLangpack: r.packVersion(), Embedded: lang.EmbeddedVersion(), Norm: text.NormVersion(),",
|
||
"replace": "\t\tChunker: chunkerVersion, Segmentation: r.segmentationSnapshot(), ShippingWave: r.shippingWaveTag(),\n\t\tLangpack: r.packVersion(), Embedded: \"\", Norm: text.NormVersion(),"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB5-target-screen-never-sees-the-target",
|
||
"why": "the target-language screen must be handed the target's DECLARED scripts; given none it abstains, so the verdict row 46 exists for is never reached. Re-anchored: the assembly of the input moved into one builder (WB33 guards that), so this entry now attacks the screen's own call",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheRunnerHandsTheScreenItsData",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/disposition.go",
|
||
"find": "if scr := langscreen.Screen(out, in.TargetScripts); scr.Verdict == langscreen.OffTarget {",
|
||
"replace": "if scr := langscreen.Screen(out, nil); scr.Verdict == langscreen.OffTarget {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB6-off-target-flag-not-escalatable",
|
||
"why": "D39.93 п.2 refused to reuse FlagCJKArtifact precisely so the new flag would need an EXPLICIT entry in escalatable(). Without it a caught off-target chunk is silently LOST instead of re-attacked on another model — the failure the whitelist exists to prevent, and the one the design was warned about before the code was written",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestAnOffTargetCompletionIsFlaggedAndEscalated",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/disposition.go",
|
||
"find": "\tcase FlagCJKArtifact, FlagOffTargetLang, FlagExcisionSuspect, FlagLoopDegenerate,",
|
||
"replace": "\tcase FlagCJKArtifact, FlagExcisionSuspect, FlagLoopDegenerate,"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB7-bank-role-exemption-narrows-to-one-role",
|
||
"why": "the exemption is the role SET: a bank role answers a term table, whose letters are engine identifiers and source terms, so BOTH the echo rule and the target screen fire on every healthy batch. It was `role == roleTerminologist` for as long as no shipping config ran the classifier; row 140 runs it, so the regression goes live with it",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheRunnerHandsTheScreenItsData",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/terminologist.go",
|
||
"find": "\treturn role == roleTerminologist || role == roleClassifier",
|
||
"replace": "\treturn role == roleTerminologist"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB8-latin-residue-runs-on-a-latin-target",
|
||
"why": "the Latin-residue detector reads a run of Latin words as an untranslated leak — true for a Cyrillic target, inverted for a Latin-written one, where it drops every chunk of clean target prose. The guard was declared in a doccomment two layers up for years while standing only on the repair path",
|
||
"package": "./internal/checks/",
|
||
"run": "TestTheLatinResidueClassIsGatedOnTheTargetsOwnScript",
|
||
"edits": [
|
||
{
|
||
"file": "internal/checks/sanitizer.go",
|
||
"find": "\tif c.TargetScriptNonLatin() {\n\t\tif det := detectLatinInsertion(glossMasked); det != \"\" {",
|
||
"replace": "\tif true {\n\t\tif det := detectLatinInsertion(glossMasked); det != \"\" {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB9-contour-configured-and-inert",
|
||
"why": "both bank roles run INSIDE the bank-mining stop, which returns before building a single candidate without a contrast artifact. The loader refuses the unset key; without that refusal a fully budgeted contour is configured and never executes, the class this loader refuses everywhere else",
|
||
"package": "./internal/config/",
|
||
"run": "TestABankContourThatCanNeverFireIsRefused",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/pipeline.go",
|
||
"find": "\t\tif p.Mining.ContrastPath == \"\" {\n\t\t\tbad(\"gates.terminology is enabled but `mining.contrast_path` is not set",
|
||
"replace": "\t\tif false {\n\t\t\tbad(\"gates.terminology is enabled but `mining.contrast_path` is not set"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB10-missing-contrast-costs-a-wave",
|
||
"why": "the run opens the contrast artifact at the bank-mining stop, AFTER the whole draft wave is bought. The write-path preflight is what turns «a deployment forgot the artifact» from a wave's money into a free refusal naming the path",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheContourRefusesAWriteRunItCannotExecute",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/runner.go",
|
||
"find": "\t\tif err := pipe.CheckMiningContrast(); err != nil {\n\t\t\treturn nil, refuse(RefusalBadConfig, err)\n\t\t}",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB11-nil-pack-contour-never-runs",
|
||
"why": "the OTHER condition of the same early return, and the one a config loader structurally cannot see: a book with no langpack_root, or one whose pair has no catalog directory, gets a nil pack and the stop returns before any candidate exists. The gate is known to the pipeline and the pack to the book; only the runner holds both",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheContourRefusesAWriteRunItCannotExecute",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/runner.go",
|
||
"find": "\tif forWrite && r.Pipeline.Gates.Terminology.Enabled && r.pack == nil {",
|
||
"replace": "\tif false && r.Pipeline.Gates.Terminology.Enabled && r.pack == nil {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB12-two-orders-for-one-term",
|
||
"why": "the law block binds a canon to its SOURCE, and one surface legitimately carries several signed senses (the bank's key is (src, sense, since, until)). Deduping on the bare src drops a signature silently while the translator's block still renders both — the regression this entry used to enshrine before the rule was corrected",
|
||
"package": "./internal/membank/",
|
||
"run": "TestTheLawBlockGivesOneOrderPerSourceTerm",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\t\tkey := src + \"\\x00\" + dst",
|
||
"replace": "\t\tkey := src"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB13-placeholder-refusal-arrives-after-a-paid-wave",
|
||
"why": "Render refuses an unknown placeholder per stage per chunk MID-RUN, so a prompt pack carrying a retired marker fails on the first call of that stage — for an editor prompt, after the whole draft wave is bought (measured on the {{genre}} retirement). The load-time scan makes the same refusal free. 27 eval/ prompt files still carry {{genre}}",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestRenderRejectsUnknownPlaceholder",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/render.go",
|
||
"find": "\tif err := CheckPlaceholders(canon); err != nil {\n\t\treturn nil, fmt.Errorf(\"pipeline: prompt %s: %w\", path, err)\n\t}",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB14-corpus-softened-until-the-number-looked-good",
|
||
"why": "a FIXTURE mutation, and the first this catalogue carries. The 12.87x margin rests on ONE healthy specimen; zeroing its source runes left the whole battery green while REPORTING A BETTER NUMBER than the corpus ever had, because the margin test asserts a floor and a floor is not a measurement. Found by planting into data, which is the half of the method that was missing",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheCorpusStillHoldsItsHardestSpecimens",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/testdata/offtarget-corpus.json",
|
||
"find": "\"source_script_runes\": 109,\n \"total_runes\": 9352,",
|
||
"replace": "\"source_script_runes\": 0,\n \"total_runes\": 9352,"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB15-screen-floor-slides-inside-its-interval",
|
||
"why": "a threshold ratified as a CONTRACT (D39.92 п.1а) was pinned only to an INTERVAL — 0.45 is still inside the corpus's empty band — so a slide re-verdicted a resumed chunk under a threshold nobody re-billed for. Version is derived from the constants, so THIS edit moves the snapshot and the golden catches it. ⚠ THAT IS THE WHOLE OF WHAT THIS ENTRY PROVES: the golden sees a slide, and it CANNOT see a literal that stops tracking the constants — under `literal + slide` the string is byte-identical, the golden does not move and this entry survives. The derivation itself is WB36's, in the langscreen package. An earlier `why` here claimed «the snapshot moves by construction» and read as a guarantee against both",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestGoldenDeterminism",
|
||
"edits": [
|
||
{
|
||
"file": "internal/langscreen/langscreen.go",
|
||
"find": "const OnTargetFloor = 0.50",
|
||
"replace": "const OnTargetFloor = 0.45"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB16-validator-blesses-what-the-renderer-refuses",
|
||
"why": "the load-time gate and the renderer must accept the SAME set. The validator's own copy of that set is gone (it now renders), so this entry attacks what replaced it: a gate that swallows the renderer's unknown-name refusal blesses every word and the pack dies mid-run, after the wave",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheValidatorAndTheRendererAcceptTheSameSet",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/render.go",
|
||
"find": "\tif _, err := render(tpl, renderVals(RenderVars{Book: &config.Book{}})); err != nil {",
|
||
"replace": "\tif _, err := render(tpl, renderVals(RenderVars{Book: &config.Book{}})); err != nil && !strings.Contains(err.Error(), \"unknown placeholder\") {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB17-priority-rank-loses-its-disposition-axis",
|
||
"why": "priorityRank orders by DISPOSITION and by STATUS, and every fixture correlated them (an auto row is always ambiguous), so dropping the disposition bit passed everything. The state that separates them is two SIGNED rows where one was matched by a collision-prone key — and since row 134 that state decides WHICH of two lawful orders the editor is given",
|
||
"package": "./internal/membank/",
|
||
"run": "TestTheBudgetKeepsTheTrustworthyMatchFirst",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\tif p.Disp != Confirmed {\n\t\trank |= 1 << 2\n\t}",
|
||
"replace": "\tif false {\n\t\trank |= 1 << 2\n\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB18-banknote-buys-what-nobody-reads",
|
||
"why": "the banknote channel's only consumer is the bank-mining stop; a book that cannot reach it still pays for the term table the pair's prompt asks for on every draft call. Not a refusal — the run is correct and the slice does its own job — but an operator must be told what is being bought",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheBanknoteChannelSaysWhenNobodyWillReadIt",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/runner.go",
|
||
"find": "\tif forWrite && r.Pipeline.Gates.Banknote.Enabled && (r.pack == nil || r.Pipeline.Mining.ContrastPath == \"\") {",
|
||
"replace": "\tif false && r.Pipeline.Gates.Banknote.Enabled && (r.pack == nil || r.Pipeline.Mining.ContrastPath == \"\") {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB19-a-prompt-path-routes-around-the-load-gate",
|
||
"why": "the load-time placeholder gate covers FOUR paths — a stage, a repair class, and each bank role — and «the check stands once and covers all of them» rested on the funnel's SHAPE, not on any pin. Every one of the four could be routed around it with the whole battery green; the cost is the refusal returning mid-run, after the wave that stage sits behind is bought",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestEveryPromptLoadPathRefusesAnUnrenderableTemplate",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/render.go",
|
||
"find": "\tif err := CheckPlaceholders(canon); err != nil {\n\t\treturn nil, fmt.Errorf(\"pipeline: prompt %s: %w\", path, err)\n\t}",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB20-law-block-drops-a-second-signature",
|
||
"why": "the law block's dedup is about SIGNATURES, not about the surface. Keying it on the bare src discards a signed canon whenever one source term carries two — 青山 the surname and 青山 the direction, which the bank's (src, sense, …) key exists to permit — silently, while the translator's block still rendered both, so the two wires disagreed. A live regression of the dofix, found by an adversarial probe",
|
||
"package": "./internal/membank/",
|
||
"run": "TestTheLawBlockGivesOneOrderPerSourceTerm",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\t\tif p.entry.status != \"approved\" && signedSrc[src] {\n\t\t\tcontinue // an unsigned rendering yields to the signed canon of the same surface\n\t\t}",
|
||
"replace": "\t\tif seen[src] {\n\t\t\tcontinue\n\t\t}\n\t\tseen[src] = true"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB21-bank-models-are-not-reachable-models",
|
||
"why": "buildClients pre-builds ReachableModels and CheckKeys demands their keys, both at OPEN time. With the bank roles missing from that list a terminologist or classifier model without a key passes the whole preflight and kills the run after the draft wave is bought",
|
||
"package": "./internal/config/",
|
||
"run": "TestABankModelIsAReachableModel",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/pipeline.go",
|
||
"find": "\tif p.Gates.Terminology.Enabled {\n\t\tif m := p.Gates.Terminology.Model; m != \"\" {",
|
||
"replace": "\tif false && p.Gates.Terminology.Enabled {\n\t\tif m := p.Gates.Terminology.Model; m != \"\" {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB22-sticky-carry-recomputes-the-trust",
|
||
"why": "a carry has no firing key of its own, so recomputing the match-trust from the ROW re-trusts a doubtful match — and since row 134 that hands the model a gender directive for an entity that may not be on the page. Invisible where src IS the firing key, which is every fixture that existed; the separating state is a Han src with a short phonetic ALIAS",
|
||
"package": "./internal/membank/",
|
||
"run": "TestAStickyCarryKeepsTheTrustOfTheKeyThatFiredIt",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "Disp: carried.Disp, KeyTrusted: carried.KeyTrusted}",
|
||
"replace": "Disp: carried.Disp, KeyTrusted: keyTrusted(e, text.NormalizeSourceKey(e.src))}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB24-sticky-window-narrows",
|
||
"why": "scene inertia carries the previous TWO chunks; at one, a term named in chunk N is gone by N+2 and the injection silently narrows. Survived the first round's plantings and was carried as a finding before it was closed",
|
||
"package": "./internal/membank/",
|
||
"run": "TestTheStickyWindowIsTwoChunksDeep",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "const StickyDepth = 2",
|
||
"replace": "const StickyDepth = 1"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB25-label-sweep-quietly-stops-covering-a-role",
|
||
"why": "the sweep walked only what it FOUND, never what the ledger RECORDS, so dropping a role from it orphaned that role's entry and unpinned its prompt with every test green. The classifier line was added by the pack that made it ship, and removing it again cost nothing",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestPromptLabelsPinTheirBytes",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/promptlabel_test.go",
|
||
"find": "\t\t\t\t{\"classifier\", g.ClassifyPromptPath},\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB26-sticky-records-vanish-from-the-law-block",
|
||
"why": "the editor's block claims «every injected record with a rendering», and a term carried by scene inertia into a pronominal chunk is exactly where the editor most needs to know what the book calls it. Excluding carries dropped them from the law with the whole tree green, golden included",
|
||
"package": "./internal/membank/",
|
||
"run": "TestAStickyRecordIsStillLawForTheEditor",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\tvar lines []string\n\tseen := map[string]bool{}\n\tfor _, p := range injected {\n\t\tif !p.valid() {\n\t\t\tcontinue\n\t\t}",
|
||
"replace": "\tvar lines []string\n\tseen := map[string]bool{}\n\tfor _, p := range injected {\n\t\tif !p.valid() || p.Sticky {\n\t\t\tcontinue\n\t\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB27-the-stop-sentence-undercounts-what-was-billed",
|
||
"why": "the first number an operator reads is «%d paying output unit(s)», and dropping the flagged units out of it under-reports what the run was billed for. The struct's arithmetic was pinned; the SENTENCE, which is what reaches a human, was pinned nowhere",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheStopSentenceCountsEveryUnitTheRunPaidFor",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "\t\tv.MaxUnits, v.Paid()+v.Flagged, v.Delivered, v.Reworked)",
|
||
"replace": "\t\tv.MaxUnits, v.Paid(), v.Delivered, v.Reworked)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB28-a-free-unit-that-flagged-is-billed",
|
||
"why": "reconcile's default branch exists so a unit that rode along at $0 and then flagged is not counted as paid; without it the run invents a charge and reports money spent on nothing that was never spent",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestReconcileLeavesUnpaidAndReworkedUnitsAlone",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "\t\tdefault:\n\t\t\tcontinue // it was never counted as paid (a free unit that flagged on resume); nothing to move",
|
||
"replace": "\t\tdefault:"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB29-a-flagged-rework-is-counted-twice",
|
||
"why": "a re-made unit that flags must LEAVE the rework count as it enters the flagged one; keeping both double-counts the grant and over-reports the paying units by one",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestReconcileLeavesUnpaidAndReworkedUnitsAlone",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "\t\tcase s.stop.Reworked > 0:\n\t\t\ts.stop.Reworked--",
|
||
"replace": "\t\tcase s.stop.Reworked > 0:"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB30-offtarget-severity-ranked",
|
||
"why": "a flag the engine raises must be RANKED, or it becomes the most benign reason in the chapter passport and a chapter in the wrong language reports `length` as its worst problem",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/status.go",
|
||
"find": "\tFlagCJKArtifact: 1,\n\tFlagOffTargetLang: 1,\n",
|
||
"replace": "\tFlagCJKArtifact: 1,\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB31-cjk-target-unscreened",
|
||
"why": "a CJK target must be screened for the LANGUAGE of the answer; putting the screen back under the echo gate leaves ja/zh/ko books judged by nothing",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/disposition.go",
|
||
"find": "\t\tif !in.NonProseReply {\n",
|
||
"replace": "\t\tif !in.NonProseReply && !isCJKTarget(in.TargetLang) {\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB32-echo-rule-for-cjk-target",
|
||
"why": "the ECHO rule must stay OFF for a CJK target — asking «is the output in the source's script» of a →ja book flags every correct chapter",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/disposition.go",
|
||
"find": "\t\t\tif !isCJKTarget(in.TargetLang) {\n\t\t\t\tif share := sourceScriptShare(out, in.SourceScripts); share > cjkEchoThreshold {",
|
||
"replace": "\t\t\tif true {\n\t\t\t\tif share := sourceScriptShare(out, in.SourceScripts); share > cjkEchoThreshold {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB33-classify-input-loses-target-scripts",
|
||
"why": "every live classify() call must carry the target's scripts; the builder exists because the second call site forgot them once already",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/chunkrun.go",
|
||
"find": "\t\tTargetScripts: lang.LangScripts(r.Book.TargetLang),\n",
|
||
"replace": "\t\tTargetScripts: nil,\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB34-unlabelled-preflight-skips-gates",
|
||
"why": "the UNLABELLED preflight — the shipping default — must demand the keys of the models the GATES call, or the run buys the draft wave and dies at the gate",
|
||
"package": "./internal/config/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/models.go",
|
||
"find": "\tfor _, mdl := range pipe.gateModels() {\n\t\tneeded[mdl] = struct{}{}\n\t}\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB35-classifier-model-demanded-when-off",
|
||
"why": "a gate that is OFF must not make a book hold a key it never uses; the classifier model is reachable only when the classify phase is on",
|
||
"package": "./internal/config/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/pipeline.go",
|
||
"find": "\t\tif p.Gates.Terminology.ClassifyTypes {\n\t\t\tif m := p.Gates.Terminology.ClassifierModel(); m != \"\" {",
|
||
"replace": "\t\tif true {\n\t\t\tif m := p.Gates.Terminology.ClassifierModel(); m != \"\" {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB36-langscreen-version-literal",
|
||
"why": "the screen's version must be DERIVED from its constants. ⚠ TWO edits, and both are the entry: the literal ALONE is harmless (it prints what the derivation prints) and the slide alone moves the derived string honestly. Only together do they reproduce the finding — the floor slides 0.50→0.45 while the version stays byte-identical, so a resumed chunk is re-verdicted under a threshold nobody re-billed for. An earlier version of this entry carried the SLIDE ONLY under this name, and passed for a pin it was not: it reddened the boundary fixture, never the derivation",
|
||
"package": "./internal/langscreen/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/langscreen/langscreen.go",
|
||
"find": "var Version = fmt.Sprintf(\"langscreen-v1-target-script-share+floor%.2f+min%d\", OnTargetFloor, MinLetters)",
|
||
"replace": "var Version = fmt.Sprint(\"langscreen-v1-target-script-share+floor0.50+min200\")"
|
||
},
|
||
{
|
||
"file": "internal/langscreen/langscreen.go",
|
||
"find": "const OnTargetFloor = 0.50",
|
||
"replace": "const OnTargetFloor = 0.45"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB37-langscreen-floor-subprecision",
|
||
"why": "the version's floor field must be able to EXPRESS the floor: a slide inside the last printed decimal moves no snapshot at all",
|
||
"package": "./internal/langscreen/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/langscreen/langscreen.go",
|
||
"find": "const OnTargetFloor = 0.50",
|
||
"replace": "const OnTargetFloor = 0.504"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB38-langscreen-boundary-flip",
|
||
"why": "«below the floor is off target» is the rule; a comparison that quietly becomes «at or below» changes verdicts and moves no constant",
|
||
"package": "./internal/langscreen/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/langscreen/langscreen.go",
|
||
"find": "\tif share < OnTargetFloor {",
|
||
"replace": "\tif share <= OnTargetFloor {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB39-load-gate-scans-system-only",
|
||
"why": "the load gate must scan the WHOLE prompt file: a retired marker in the user tail or a few-shot block otherwise loads clean and fails inside Render, after the wave",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/render.go",
|
||
"find": "\tif err := CheckPlaceholders(canon); err != nil {",
|
||
"replace": "\tif err := CheckPlaceholders(t.System); err != nil {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB40-sticky-carry-disp-recomputed",
|
||
"why": "a sticky carry has no firing key of its own, so BOTH halves are inherited; recomputing the disposition from the row's own surface is the D16.2 upgrade in the other half's coat",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "Disp: carried.Disp, KeyTrusted: carried.KeyTrusted}",
|
||
"replace": "Disp: dispositionFor(e, text.NormalizeSourceKey(e.src)), KeyTrusted: carried.KeyTrusted}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB41-signed-set-keyed-on-disposition",
|
||
"why": "signature is a STATUS, not a confidence: a signed row that fired on a doubtful key is still the canon others yield to",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\t\tif p.valid() && p.entry.status == \"approved\" && strings.TrimSpace(p.entry.dst) != \"\" {",
|
||
"replace": "\t\tif p.valid() && p.Disp == Confirmed && strings.TrimSpace(p.entry.dst) != \"\" {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB42-only-draft-yields-to-canon",
|
||
"why": "what yields to a signed canon is every UNSIGNED status, `auto` included — `auto` is what the miner writes, i.e. the row the rule exists to subordinate",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\t\tif p.entry.status != \"approved\" && signedSrc[src] {",
|
||
"replace": "\t\tif p.entry.status == \"draft\" && signedSrc[src] {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB46-runner-reachable-stage-only",
|
||
"why": "the runner's eager client map must cover the models a GATE calls; a miss there is not a fallback, it is the run dying after the draft wave is paid for",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/runner.go",
|
||
"find": "\treturn r.Pipeline.ReachableModels()\n",
|
||
"replace": "\tvar out []string\n\tfor _, st := range r.Pipeline.Stages {\n\t\tout = append(out, st.ResolvedModel)\n\t}\n\treturn out\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB47-flagged-clause-prints-rework",
|
||
"why": "the operator sentence's FLAGGED count must be the flagged count: it printed the rework count with the whole tree green, because both fixtures had them equal",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/volume.go",
|
||
"find": "re-attacks a flag)\", v.Flagged)",
|
||
"replace": "re-attacks a flag)\", v.Reworked)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB48-mined-rows-admitted-to-base-bank",
|
||
"why": "the DRAFT wave selects over the base bank (Source:mined excluded) — that is what makes «one re-payment» honest at the WIRE level and not only in the version hash",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/bankmaterialize.go",
|
||
"find": "\t\tif row.Source == \"mined\" {\n\t\t\thasMined = true\n\t\t\tcontinue\n\t\t}",
|
||
"replace": "\t\tif row.Source == \"mined\" {\n\t\t\thasMined = true\n\t\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB43-law-block-single-pass",
|
||
"why": "the law block must not depend on the input ORDER: a single pass that records signatures as it goes keeps whichever row arrived first, and passes every fixture because Select sorts the signed row to the front in production",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\tsignedSrc := map[string]bool{}\n\tfor _, p := range injected {\n\t\tif p.valid() && p.entry.status == \"approved\" && strings.TrimSpace(p.entry.dst) != \"\" {\n\t\t\tsignedSrc[strings.TrimSpace(p.entry.src)] = true\n\t\t}\n\t}\n",
|
||
"replace": "\tsignedSrc := map[string]bool{}\n"
|
||
},
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\t\tif p.entry.status != \"approved\" && signedSrc[src] {\n\t\t\tcontinue // an unsigned rendering yields to the signed canon of the same surface\n\t\t}",
|
||
"replace": "\t\tif p.entry.status == \"approved\" && strings.TrimSpace(p.entry.dst) != \"\" {\n\t\t\tsignedSrc[src] = true\n\t\t}\n\t\tif p.entry.status != \"approved\" && signedSrc[src] {\n\t\t\tcontinue // an unsigned rendering yields to the signed canon of the same surface\n\t\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB44-corpus-second-hardest-softened",
|
||
"why": "the corpus ledger must pin the POPULATION, not one extremum per axis: every hard specimen but the worst could otherwise be softened with every test green",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/testdata/offtarget-corpus.json",
|
||
"find": " \"id\": \"ca9277ac34ae\",\n \"label\": \"healthy\",\n \"source_script_runes\": 42,",
|
||
"replace": " \"id\": \"ca9277ac34ae\",\n \"label\": \"healthy\",\n \"source_script_runes\": 0,"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB45-corpus-offtarget-side-drifts",
|
||
"why": "the empty band the 0.50 floor sits in has TWO sides: the off-target extremum was compared constant-to-constant, so the data could drift to 0.49 with every corpus test green and the floor would sit on top of a specimen",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/testdata/offtarget-corpus.json",
|
||
"find": " \"id\": \"33affac80ec5\",\n \"label\": \"off_target\",\n \"source_script_runes\": 0,\n \"total_runes\": 5990,\n \"letters\": 4690,\n \"target_script_letters\": 0,",
|
||
"replace": " \"id\": \"33affac80ec5\",\n \"label\": \"off_target\",\n \"source_script_runes\": 0,\n \"total_runes\": 5990,\n \"letters\": 4690,\n \"target_script_letters\": 2300,"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB49-empty-canon-swallows-the-term",
|
||
"why": "a signed row with NO rendering orders nothing, so nothing may yield to it — otherwise the unsigned rendering is dropped in favour of a row that prints no line and the term leaves the law block entirely",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\t\tif p.valid() && p.entry.status == \"approved\" && strings.TrimSpace(p.entry.dst) != \"\" {",
|
||
"replace": "\t\tif p.valid() && p.entry.status == \"approved\" {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB50-signed-set-untrimmed-src",
|
||
"why": "the signature set and the lookup must normalize the surface the same way; recorded untrimmed and looked up trimmed, the set silently stops matching and every unsigned row of that surface becomes law again",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\t\t\tsignedSrc[strings.TrimSpace(p.entry.src)] = true",
|
||
"replace": "\t\t\tsignedSrc[p.entry.src] = true"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB51-flag-reason-declared-elsewhere",
|
||
"why": "every FlagReason the engine declares must be RANKED; the exhaustiveness test used to read one file, so a reason declared anywhere else fell to the unknown bucket while the test still said «every declared reason is ranked»",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/status.go",
|
||
"find": "const severityUnknown = 8\n",
|
||
"replace": "const severityUnknown = 8\n\n// planted\nconst FlagPlantedElsewhere FlagReason = \"planted_elsewhere\"\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB52-builder-hardcodes-the-target",
|
||
"why": "the classify input's target must come from the BOOK; a hard-coded target makes every book judged as the shipping pair, and no runner fixture translates into anything but Russian, so nothing else can see it",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/chunkrun.go",
|
||
"find": "\t\tTargetLang: r.Book.TargetLang,\n",
|
||
"replace": "\t\tTargetLang: \"ru\",\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB53-builder-hardcodes-target-scripts",
|
||
"why": "the target's scripts must come from the BOOK's target: hard-coded, a →ja book is screened against Cyrillic and every correct chapter is off-target",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/chunkrun.go",
|
||
"find": "\t\tTargetScripts: lang.LangScripts(r.Book.TargetLang),\n",
|
||
"replace": "\t\tTargetScripts: lang.LangScripts(\"ru\"),\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB54-builder-hardcodes-source-scripts",
|
||
"why": "the source's scripts must come from the RUN's compiled checkers: hard-coded to zh, the echo rule measures the wrong script for every other source language",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/chunkrun.go",
|
||
"find": "\t\tSourceScripts: r.checkers.SourceScripts(),\n",
|
||
"replace": "\t\tSourceScripts: lang.LangScripts(\"zh\"),\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB56-labelled-preflight-skips-gates",
|
||
"why": "the LABELLED branch of CheckKeys must demand the keys of the models the gates call: it was pinned only by the reachable LIST, which is exactly the thing «a pin on the list is not a pin on the preflight» rejects",
|
||
"package": "./internal/config/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/models.go",
|
||
"find": "\t\tfor _, mdl := range pipe.ReachableModels() {\n\t\t\tneeded[mdl] = struct{}{}\n\t\t}\n\t\treturn m.checkKeysFor(needed)",
|
||
"replace": "\t\tfor _, st := range pipe.Stages {\n\t\t\tneeded[st.ResolvedModel] = struct{}{}\n\t\t}\n\t\treturn m.checkKeysFor(needed)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB57-banknote-warning-loses-the-pack-arm",
|
||
"why": "the banknote warning fires when EITHER mining input is missing; keyed on the contrast artifact alone, a book with a pack and no contrast pays for a term table nobody reads and is told nothing",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/runner.go",
|
||
"find": "(r.pack == nil || r.Pipeline.Mining.ContrastPath == \"\")",
|
||
"replace": "(r.Pipeline.Mining.ContrastPath == \"\")"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB58-banknote-warning-loses-the-contrast-arm",
|
||
"why": "the mirror arm: keyed on the pack alone, a book with a contrast artifact and no langpack pays for the same unread table in silence",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/runner.go",
|
||
"find": "(r.pack == nil || r.Pipeline.Mining.ContrastPath == \"\")",
|
||
"replace": "(r.pack == nil)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB59-banknote-warning-fires-on-a-read-open",
|
||
"why": "a $0 read path buys nothing, so warning there teaches an operator to ignore the line on the run where it costs money",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/runner.go",
|
||
"find": "\tif forWrite && r.Pipeline.Gates.Banknote.Enabled && (",
|
||
"replace": "\tif r.Pipeline.Gates.Banknote.Enabled && ("
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB60-volume-report-decided-after-reconcile",
|
||
"why": "the volume report is decided BEFORE reconcile trues the counters up: decided after, a run whose only work outside its grant was a carried unit that came back FLAGGED has Carried==0 and reports nothing at all — the one run that most needs the disclosure goes silent. ⚠ Run-filtered: this planting also strips the report from the DRAFT-ONLY path, which three neighbouring tests catch for a different reason (they lose the report entirely, not out of order). Unfiltered it would go red without proving anything about this pin. WB64 is the faithful both-paths form",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "\tif scope.bound() {\n\t\tres.Volume = &scope.stop\n",
|
||
"replace": "\tif scope.bound() {\n"
|
||
},
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "\tscope.reconcile(res.Chunks)\n\tr.Log.InfoContext(ctx, \"book run finished\", \"book\"",
|
||
"replace": "\tscope.reconcile(res.Chunks)\n\tif scope.bound() {\n\t\tres.Volume = &scope.stop\n\t}\n\tr.Log.InfoContext(ctx, \"book run finished\", \"book\""
|
||
}
|
||
],
|
||
"run": "TestTheVolumeReportIsAskedBeforeTheCountersAreTruedUp"
|
||
},
|
||
{
|
||
"id": "WB55-corpus-provenance-swapped",
|
||
"why": "the corpus digest must cover the ADDRESS a specimen was taken from, not only its counts: a corpus whose numbers are right and whose provenance is wrong is unreproducible in the one way that matters",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/testdata/offtarget-corpus.json",
|
||
"find": "\"provenance\": \"probe-4axes/arms/backups/20260902T075308Z.db#draft\",\n \"head\": \"Рассечение камня",
|
||
"replace": "\"provenance\": \"planted/not-the-address-it-came-from.db#draft\",\n \"head\": \"Рассечение камня"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB61-builder-hardcodes-the-fixtures-own-pair",
|
||
"why": "a hard-code to the FIXTURE'S OWN pair is the hole a value-comparing test cannot see: the earlier pin asserted the builder's output against values chosen for one book, so it caught a hard-code to the shipping pair and would have sailed past a hard-code to the pair the test itself uses. Only «two books must answer differently» is unsatisfiable by any constant. ⚠ Run-filtered on purpose: a hard-code to `ja` also breaks twenty ru fixtures, so an unfiltered entry would go red without proving anything about THIS pin. The dangerous hard-code is the one to the SHIPPING pair (WB52), which nothing else sees",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/chunkrun.go",
|
||
"find": "\t\tTargetLang: r.Book.TargetLang,\n",
|
||
"replace": "\t\tTargetLang: \"ja\",\n"
|
||
}
|
||
],
|
||
"run": "TestClassifyInputForLeavesNoAxisUnset"
|
||
},
|
||
{
|
||
"id": "WB62-innocent-const-must-not-be-accused",
|
||
"expect": "survives",
|
||
"why": "THE BOUNDARY OF TestEveryFlagReasonIsRanked, recorded because the test used to cross it. An ordinary untyped string constant sitting in the FlagReason block is NOT a flag — Go types it as untyped string, inheriting nothing — and the walk must ignore it. An earlier version carried the previous spec's type forward and failed the test with a message accusing a documentation URL of being an unranked flag. A test that accuses the innocent is not enforcing its own sentence, so this planting MUST survive",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestEveryFlagReasonIsRanked",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/disposition.go",
|
||
"find": "\tFlagSanitizerStripped FlagReason = \"sanitizer_stripped\"\n",
|
||
"replace": "\tFlagSanitizerStripped FlagReason = \"sanitizer_stripped\"\n\n\t// not a flag: a documentation pointer that happens to live in this block\n\tflagReasonDocURL = \"https://example.invalid/flags\"\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB63-run-compiles-a-constant-source",
|
||
"why": "the run's declared SOURCE scripts must come from the book. This is the WRITER of the axis whose reader was pinned one commit earlier — pinning the reader alone left the whole axis decided by an unguarded line, and a constant here gives a ko→ru or ja→ru book the wrong declared source while the echo detector measures a script the book does not use",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheRunCompilesTheBooksOwnSourceScripts",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/runner.go",
|
||
"find": "\t\tr.checkers.SetSourceScripts(lang.LangScripts(r.Book.SourceLang))\n",
|
||
"replace": "\t\tr.checkers.SetSourceScripts(lang.LangScripts(\"ja\"))\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB64-volume-report-after-reconcile-on-both-paths",
|
||
"why": "the FAITHFUL form of the ordering defect: the decision moved after reconcile on BOTH the draft-only and the editor path, so no neighbour loses its report for an unrelated reason. Only a fixture whose single unit is carried AND flagged can tell the two orders apart, and until this entry existed the draft-only path had none",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestTheVolumeReportIsAskedBefore",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "\tif scope.bound() {\n\t\tres.Volume = &scope.stop\n",
|
||
"replace": "\tif scope.bound() {\n"
|
||
},
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "\t\tscope.reconcile(res.Chunks)\n\t\tr.Log.InfoContext(ctx, \"book run finished (draft-only)\"",
|
||
"replace": "\t\tscope.reconcile(res.Chunks)\n\t\tif scope.bound() {\n\t\t\tres.Volume = &scope.stop\n\t\t}\n\t\tr.Log.InfoContext(ctx, \"book run finished (draft-only)\""
|
||
},
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "\tscope.reconcile(res.Chunks)\n\tr.Log.InfoContext(ctx, \"book run finished\", \"book\"",
|
||
"replace": "\tscope.reconcile(res.Chunks)\n\tif scope.bound() {\n\t\tres.Volume = &scope.stop\n\t}\n\tr.Log.InfoContext(ctx, \"book run finished\", \"book\""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB65-labelled-preflight-skips-the-hop",
|
||
"why": "a labelled run CALLS its escalation hop, and BuildClient never refuses an empty key — it only becomes a header. A preflight blind to the hop lets the book open, buy the draft wave and 401 at the escalation: the same late failure as the gates, one field over",
|
||
"package": "./internal/config/",
|
||
"run": "TestTheLABELLEDPreflightDemandsEveryCallersKeyToo",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/pipeline.go",
|
||
"find": "\t\tadd(st.ResolvedHop)\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB66-preflight-demands-the-configured-not-the-resolved-model",
|
||
"why": "routing is what a labelled book is FOR: the model in the yaml may not be the model that answers. A preflight that demands the CONFIGURED model passes a book whose RESOLVED model has no key, and the refusal moves from open time to the first draft call",
|
||
"package": "./internal/config/",
|
||
"run": "TestTheLABELLEDPreflightDemandsEveryCallersKeyToo",
|
||
"edits": [
|
||
{
|
||
"file": "internal/config/pipeline.go",
|
||
"find": "\t\tadd(st.ResolvedModel)\n",
|
||
"replace": "\t\tadd(st.Model)\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WB67-flag-reason-in-the-conversion-spelling",
|
||
"why": "`X = FlagReason(\"…\")` is as ordinary a declaration as `X FlagReason = \"…\"`, and a walk that reads only the spec's type is blind to it — exhibited as a pair, the typed spelling caught and the conversion spelling not",
|
||
"package": "./internal/pipeline/",
|
||
"run": "TestEveryFlagReasonIsRanked",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/status.go",
|
||
"find": "const severityUnknown = 8\n",
|
||
"replace": "const severityUnknown = 8\n\n// planted\nconst FlagPlantedConv = FlagReason(\"planted_conv\")\n"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WF-length-bound",
|
||
"why": "row 271: a bank value rides verbatim inside the SYSTEM message of every paid call, so its length is a fence and not a nicety — lifting the bound lets one term become a document inside the block",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/wirefence.go",
|
||
"find": "\tif n := utf8.RuneCountInString(s); n > WireFieldMaxRunes {",
|
||
"replace": "\tif n := utf8.RuneCountInString(s); n > WireFieldMaxRunes && false {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WF-control-ban",
|
||
"why": "row 271: a line feed in `dst` ENDS the line of the mapping and writes new lines into the system block — the ban on line-ending/reordering runes is the whole of the fix, and it must not be liftable while the battery stays green",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/wirefence.go",
|
||
"find": "\tcase unicode.IsControl(r):",
|
||
"replace": "\tcase unicode.IsControl(r) && false:"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WF-render-backstop",
|
||
"why": "the fence's LAST point: door and seed loader make it unreachable today, so only a planting can say whether the renderer still holds it for a writer added later",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\t\tif WireUnfitRow(p.entry.src, p.entry.dst) {\n\t\t\tcontinue\n\t\t}\n\t\tline := p.entry.src + \" → \" + p.entry.dst",
|
||
"replace": "\t\tline := p.entry.src + \" → \" + p.entry.dst"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WF-door-refusal",
|
||
"why": "row 271: the user door is where a person finds out their correction cannot ride on the wire — without the refusal the term is accepted and then silently absent from every request",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/decisions.go",
|
||
"find": "\tif why := WireUnfitJoined(d.Src, d.Dst); why != \"\" {\n\t\treturn termKey{}, fmt.Errorf(\"%s\", why)\n\t}\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WF-seed-refusal",
|
||
"why": "an operator's seed file is theirs to fix: dropping such a row on the way to the wire would leave a term they believe is in force absent from every paid call, with nothing said",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memseed.go",
|
||
"find": "\t\tif reasons := WireUnfitReasons(t.Src, t.Dst); len(reasons) > 0 {",
|
||
"replace": "\t\tif reasons := WireUnfitReasons(t.Src, t.Dst); false && len(reasons) > 0 {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "WF-version-fold-scope",
|
||
"why": "the fence changes the WIRE for a book holding an unfit row, and a wire change the snapshot cannot see is a silent re-payment outside the consent contour (the editor-unverified/neuter class, a third time)",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memory.go",
|
||
"find": "\t\tif WireUnfitRow(r.Src, r.Dst) {\n\t\t\thasUnfit = true\n\t\t}",
|
||
"replace": "\t\tif WireUnfitRow(r.Src, r.Dst) {\n\t\t\t_ = r\n\t\t}"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-latch-is-a-cancel",
|
||
"why": "row 277, THE NAMED ACCEPTANCE PLANTING: it restores the PRE-PACK world in one act — no waiting for headroom, and a refusal that cancels the wave — because that pair is what killed the calls already admitted and made a book produce nothing at any price (measured live 04.09, reproduced twice). ⚠ THE FIRST VERSION OF THIS ENTRY ADDED ONLY THE cancel() AND SURVIVED, and the reason is worth keeping: with the wait in place a refusal does not become terminal until the sky is empty, so by the time the latch fires there is nothing left in flight for a cancel to kill. The defect needs both halves; so does the planting that reproduces it.",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/stagerun.go",
|
||
"find": "\t\tif !settleCannotHelp(scope, committed, estimate, ceiling) {",
|
||
"replace": "\t\tif false && !settleCannotHelp(scope, committed, estimate, ceiling) {"
|
||
},
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "\t\t\tr.events.ceilingReached(halt)\n\t\t\tlatchOnce.Do(func() { close(latched) })\n\t\t\treturn",
|
||
"replace": "\t\t\tr.events.ceilingReached(halt)\n\t\t\tlatchOnce.Do(func() { close(latched) })\n\t\t\tcancel()\n\t\t\treturn"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-wait-for-settle",
|
||
"why": "a refusal is not final while another call still holds a reservation: settle returns estimate-cost, so the headroom is still moving and re-asking is what turns a dead run into a delivered book",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/stagerun.go",
|
||
"find": "\t\tif !settleCannotHelp(scope, committed, estimate, ceiling) {",
|
||
"replace": "\t\tif false && !settleCannotHelp(scope, committed, estimate, ceiling) {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-reserve-under-the-gate",
|
||
"why": "the admission and the in-flight counter must be ONE critical section: split, a worker that has committed its reservation but not yet recorded itself lets a refused sibling read zero in flight and declare the book finished while money is about to come back. ⚠ CATALOGUED AS A SURVIVOR, AND «SURVIVED» HERE DOES NOT MEAN «THE GUARANTEE HOLDS» — it means the tooling cannot ask the question. Reproducing the race needs the two critical sections interleaved on demand, which takes a hook in the scheduler this repository does not have; a sleep-based «proof» would pin a duration rather than the invariant. Read this green as «unverifiable by this instrument», never as a pin.",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reservegate.go",
|
||
"find": "\tg.mu.Lock()\n\tdefer g.mu.Unlock()\n\tresv, verdict, err := s.Reserve(bookID, estimate, c)",
|
||
"replace": "\tresv, verdict, err := s.Reserve(bookID, estimate, c)\n\tg.mu.Lock()\n\tdefer g.mu.Unlock()"
|
||
}
|
||
],
|
||
"expect": "survives"
|
||
},
|
||
{
|
||
"id": "MS-cancelled-wait-is-not-money",
|
||
"why": "a wait ended by ctx cancellation is NOT a money stop: reported as one, a run somebody stopped publishes a ceiling event with a shortfall and the platform tells a person to add money that would change nothing",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reservegate.go",
|
||
"find": "\tcase <-ctx.Done():\n\t\treturn waitAborted",
|
||
"replace": "\tcase <-ctx.Done():\n\t\treturn waitNothingInFlight"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-draft-stop-does-not-edit",
|
||
"why": "a money stop in the DRAFT wave must not start the edit wave: an unstarted member is found in draftByKey holding the zero value, so the editor is paid to edit a unit with a hole and then ships it",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "\t\tr.reportEvicted(ctx, \"draft\")\n\t\treturn r.moneyStoppedResult(ctx, chunks, drafted, draftResults, editWave), err",
|
||
"replace": "\t\tr.reportEvicted(ctx, \"draft\")\n\t\t_ = drafted"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-shortfall-on-the-wire",
|
||
"why": "row 278: the missing amount died in the stderr of a transient unit — without it on the ceiling frame a buyer is told the run stopped and nothing about what would restart it",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/events.go",
|
||
"find": "\te.emit(runevents.TypeCeiling, runevents.Ceiling{Halted: true, Scope: halt.Scope, ShortfallMicroUSD: halt.ShortfallMicroUSD})",
|
||
"replace": "\te.emit(runevents.TypeCeiling, runevents.Ceiling{Halted: true, Scope: halt.Scope})"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-stream-version-bump",
|
||
"why": "the seam rule: a frame that gained a field must say so, or two streams differing in content claim one version — the constant's own comment records this exact miss, made once already",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/runevents/runevents.go",
|
||
"find": "const StreamVersion = \"1.3\"",
|
||
"replace": "const StreamVersion = \"1.2\""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-volume-ledger-on-a-money-stop",
|
||
"why": "VolumeStop's seven counters are a PLAN; a spend stop leaves them counting units that were admitted and never done — Delivered over-counts, LeftFresh under-counts, and at Left()==0 the run announces it reached the end of the book. ⚠ ITS FIRST PIN WAS VACUOUS and this entry SURVIVED it: the fixture granted no volume at all, so res.Volume was nil whatever the code did. Only a run that HAS a grant can have one wrongly attached.",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "func (r *Runner) noteMoneyStop(ctx context.Context, res *BookResult) {\n\tres.Volume = nil",
|
||
"replace": "func (r *Runner) noteMoneyStop(ctx context.Context, res *BookResult) {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-step-max-ignores-retries",
|
||
"why": "row 278: maxTokensForAttempt DOUBLES the budget on every regeneration and a refused RETRY does not degrade — a ceiling sized for attempt 0 admits a unit's first call and refuses its remedy on every resume forever",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\t\tfor attempt := 0; attempt <= p.maxRegen; attempt++ {",
|
||
"replace": "\t\tfor attempt := 0; attempt <= 0; attempt++ {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-executor-sizing-shared",
|
||
"why": "reader and writer of one arithmetic: the projection reproduces the executor's output budget, and a projection that sized calls its own way would drift from the reservations the run actually makes, invisibly",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\t\tbase := r.baseMaxTokensFor(sp.st, sizing)",
|
||
"replace": "\t\tbase := sizing"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-structure-provenance",
|
||
"why": "an order phrased in chapters against a DETECTED cut is an order against a guess; collapsing the three values hides which one the reader has",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/chunk/ingest.go",
|
||
"find": "\tif formatDeclared {\n\t\treturn StructureDeclared\n\t}\n\treturn StructureDetected",
|
||
"replace": "\treturn StructureDeclared"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-price-reaches-status",
|
||
"why": "the surface a buyer's platform reads before deciding must answer the price question too — a projection that only the manifest carries leaves status blind exactly where the money decision is made",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/status.go",
|
||
"find": "\trep.Price, rep.Structure = r.readModelPrice(withText)",
|
||
"replace": "\t_ = withText"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-price-fallback-path",
|
||
"why": "the manifest is an ACCELERATOR, and an accelerator that changes the ANSWER is a second source of truth: without the fallback a book with no current sidecar reports no price at all, silently, on the surface a buyer's platform reads before deciding",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/manifest.go",
|
||
"find": "\tfull, err := withText()\n\tif err != nil || len(full) == 0 {\n\t\treturn nil, \"\"\n\t}\n\t_, bp := r.projectBook(r.pricePlanFor(), r.outputUnits(full))\n\treturn bp, r.cutStructure",
|
||
"replace": "\treturn nil, \"\""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-reservation-released-on-marshal-failure",
|
||
"why": "a reservation left behind is headroom the book paid for and cannot use, and since the stop now PUBLISHES the shortfall a leak makes the engine ask a person for more money than it needs. ⚠ CATALOGUED AS A SURVIVOR, and the argument is that the branch is UNREACHABLE rather than untested: it fires only if json.Marshal fails on llm.Usage, a struct of ints, which the encoding/json contract does not allow. No test can red it without faking the standard library, and the repair is kept because the money path must be correct on the paths nobody can reach as well as on the ones they can.",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/stagerun.go",
|
||
"find": "\t\tr.releaseReservation(ctx, resv)\n\t\tr.setJobStatus(ctx, job.ID, \"failed\")\n\t\treturn att, err\n\t}\n\tatt.cumCost, att.runCost = cost, cost",
|
||
"replace": "\t\treturn att, err\n\t}\n\tatt.cumCost, att.runCost = cost, cost"
|
||
}
|
||
],
|
||
"expect": "survives"
|
||
},
|
||
{
|
||
"id": "MS-two-error-slots",
|
||
"why": "a ceiling no longer cancels, so a run can latch on money and THEN break: sharing one slot lets whichever came first speak for both, and a first-wins ceiling makes a BROKEN run depart exit 4, which the platform records as `paused`",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "\t\t\tmu.Lock()\n\t\t\tif haltErr == nil {\n\t\t\t\thaltErr = err\n\t\t\t}\n\t\t\tmu.Unlock()",
|
||
"replace": "\t\t\tmu.Lock()\n\t\t\tif firstErr == nil {\n\t\t\t\tfirstErr = err\n\t\t\t}\n\t\t\tmu.Unlock()"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-crash-outranks-the-wave-error",
|
||
"why": "a crashed process is not a pause and is not a graceful stop: routed behind the wave's own error it departs as the sibling's ceiling (exit 4) or cancellation (exit 5), and its stack is discarded",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/waverun.go",
|
||
"find": "\tif panicErr != nil {",
|
||
"replace": "\tif firstErr != nil {\n\t\treturn firstErr\n\t}\n\tif panicErr != nil {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-fewshot-toggle-respected",
|
||
"why": "the projection must ask the EXECUTOR'S question (SystemFor + fewShotEnabled), not add the template's fields up: the shipped c1 editor has few_shot OFF while its template still carries the block, so summing it over-charges every edit call of every book on that arm — invisibly, because a price 20% too high looks exactly like a price",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\t\t\tsp.tplTokens = EstimateTokens(tpl.SystemFor(fewShotEnabled(st))) + EstimateTokens(tpl.User)",
|
||
"replace": "\t\t\tsp.tplTokens = EstimateTokens(tpl.System) + EstimateTokens(tpl.FewShot) + EstimateTokens(tpl.User)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-source-rides-every-stage-that-asks",
|
||
"why": "the executor renders EVERY stage with RenderVars{Text, Draft}, and the shipped editor is BILINGUAL (D30.1) — dropping the source from a later stage's prompt under-states a unit's bill by roughly a sixth, in the direction that lets a platform sell a book for less than it costs",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\tif sp.carriesSource && !inputIsSource {",
|
||
"replace": "\tif false && sp.carriesSource && !inputIsSource {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-source-double-charged",
|
||
"why": "the FIRST stage's input IS the source, so adding it again double-charges the draft call — the mirror error of dropping it, and it would raise the minimum purchase a platform demands",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\tif sp.carriesSource && !inputIsSource {",
|
||
"replace": "\tif sp.carriesSource {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-wait-counter",
|
||
"why": "a test can only see the WAITING MECHANISM through a fact it leaves behind: without the counter the delivering-ceiling test asserts an outcome the run can reach without ever waiting — which is exactly how it passed on a fixture whose ceiling never refused anything",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reservegate.go",
|
||
"find": "\t\tg.mu.Lock()\n\t\tg.waits++\n\t\tg.mu.Unlock()\n\t\treturn waitSettled",
|
||
"replace": "\t\treturn waitSettled"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-draft-priced-per-unit-not-per-chunk",
|
||
"why": "the wave driver fans the DRAFT over chunks and the EDIT over units: pricing the draft per unit charges the template and the injection once where the executor pays them per member, and sizes the largest single reservation from the whole unit instead of from one call — the number a platform sets its minimum purchase by",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\tfor _, m := range u.Members {\n\t\tdraftTokens += p.walkDraftCalls(m, func(sp stagePrice, srcTok, in, out int, inIsSource bool) {",
|
||
"replace": "\tfor _, m := range u.Members[:1] {\n\t\tm.Text = src\n\t\tdraftTokens += p.walkDraftCalls(m, func(sp stagePrice, srcTok, in, out int, inIsSource bool) {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-optional-call-queues-for-headroom",
|
||
"why": "an optional call that queued for the last dollars turns «do not start anything new» into «the optional spends what the mandatory needed» — and the escalation hop holds escMu while it waits, blocking every other worker's escalation. The rule lives in the gate precisely so a test can watch it happen",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/reservegate.go",
|
||
"find": "\tif !mandatory {",
|
||
"replace": "\tif false && !mandatory {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-terminal-branch-order",
|
||
"why": "the money ledger is attached whenever a ceiling was reached, and above the signature stop and the cancellation that branch swallows both: a bank-stop reports `failed` at exit 3 and a caught SIGTERM reports `failed` at exit 5. Two channels contradicting each other about one run is what this vocabulary exists to prevent — and re-ordering case arms is the edit a tidy-up makes without noticing",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/events.go",
|
||
"find": "\tcase errors.As(err, &sigStop):",
|
||
"replace": "\tcase err != nil && e.ceilingSaid:\n\t\te.emit(runevents.TypeFinished, runevents.Finished{Outcome: runevents.OutcomeFailed, Money: e.moneyLedger()})\n\tcase errors.As(err, &sigStop):"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-book-once-charge",
|
||
"why": "row 278: the terminology consolidation reads the WHOLE book's drafts once, so charging it per unit under-prices a short book exactly where the error hurts — and it is conditional on the gate AND the contrast key, the pair whose second half a deployment loses silently",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\tusd := g.Terminology.BudgetUSD",
|
||
"replace": "\tusd := 0.0"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-book-once-charged-per-unit",
|
||
"why": "the once-per-book charge added inside the unit loop is the very under-pricing inversion the field exists to prevent, only backwards: a long book would pay it a hundred times",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\t\tbp.ExpectedUSD += p.ExpectedUSD\n\t\tif step := r.stepMaxForUnit(plan, u, p); step > bp.StepMaxUSD {",
|
||
"replace": "\t\tbp.ExpectedUSD += p.ExpectedUSD + bp.BookOnceUSD\n\t\tif step := r.stepMaxForUnit(plan, u, p); step > bp.StepMaxUSD {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "MS-ceiling-frame-idempotent",
|
||
"why": "under several workers one stop is refused several times; a `ceiling` frame per refusal makes a reader count refusals where it means to count stops",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/events.go",
|
||
"find": "\tif already {\n\t\treturn\n\t}",
|
||
"replace": "\t_ = already"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "PP-no-translator-stage-completion",
|
||
"why": "a pipeline whose first stage is not a translator has that stage DOING the translating: its completion is what the pair's fertility says a source of this shape produces, not the source's own token count. ⚠ THIS ENTRY SURVIVED ONCE AND THE SURVIVAL WAS THE FINDING: walkDraftCalls returned a draft size even when NO draft stage ran, so the fallback this mutation edits was DEAD CODE — a mutation cannot change a branch nothing reaches. The branch is live now, and the entry is what made it visible.",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\t\tin, out = up.PromptTokens, p.expectedDraftTokens(dense, sparse)",
|
||
"replace": "\t\tin, out = up.PromptTokens, up.PromptTokens"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "DF-money-follows-the-ceiling-not-the-outcome",
|
||
"why": "acceptance F6/V2-4, found by BOTH verifiers independently: `Finished.money` follows «a ceiling was REACHED», not «the outcome word is ceiling» — the contract file said the latter, and a consumer in another zone building on either reading gets a different bug (money on `stopped`/`failed` is real; `ceiling` without seeded counters carries none)",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/events.go",
|
||
"find": "\tif !e.ceilingSaid || e.waves == nil {",
|
||
"replace": "\tif e.waves == nil {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "DF-old-sidecar-must-not-silence-the-price",
|
||
"why": "acceptance V2-3: `price` and `structure` are ADDITIVE so the document version deliberately did not move for them — a sidecar from the previous build passes version, counters and key, comes back «current» carrying no price, and the fallback the code itself calls the invariant never runs. The book then reports NO price at all, silently, on the surface a buyer's platform reads before deciding",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/manifest.go",
|
||
"find": "\tif m := r.loadManifest(); m != nil && m.Price != nil && m.Structure != \"\" {",
|
||
"replace": "\tif m := r.loadManifest(); m != nil {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "DF-engine-written-document-must-not-kill-the-run",
|
||
"why": "acceptance F8, widened: the mined delta AND the auto-bank are written by this engine from MODEL OUTPUT, and refusing such a document aborts a PAID run over our own answer while asking a person to hand-edit a file nobody authored. The operator's own seed keeps the refusal — that one is theirs to fix",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memseed.go",
|
||
"find": "\t\t\tif engineWritten {",
|
||
"replace": "\t\t\tif false && engineWritten {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "DF-operator-seed-keeps-its-refusal",
|
||
"why": "the mirror of the split: dropping a row from the OPERATOR's seed would leave a term they believe is in force silently absent from every request — the refusal is what tells them",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memseed.go",
|
||
"find": "func ParseBankSeed(name string, raw []byte) (BankSeed, error) {\n\treturn parseBankSeed(name, raw, false)",
|
||
"replace": "func ParseBankSeed(name string, raw []byte) (BankSeed, error) {\n\treturn parseBankSeed(name, raw, true)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "DF-classifier-budget-only-when-it-runs",
|
||
"why": "acceptance V2-5, and it is a class rather than a slip: `classify_types` gates the classifier PHASE, and the loader requires its budget be non-zero ONLY when that toggle is on — so charging the budget unconditionally bills a book for a pass that cannot happen ($1.00 of $2.00 on the shipped arm). ⚠ THE TEST OF THIS FUNCTION PINNED THE WRONG NUMBER: a gate defending the defect, which no review that reads green can catch",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\tif g.Terminology.ClassifyTypes {\n\t\tusd += g.Terminology.ClassifyBudgetUSD\n\t}",
|
||
"replace": "\tusd += g.Terminology.ClassifyBudgetUSD"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "DF-input-identity-is-stated-not-counted",
|
||
"why": "acceptance V2-8: two token counts can coincide without being the same text — a pair whose fertility sits near 1.0 makes a draft the size of its source — and then a later stage that DOES receive the source stops being charged for it. Identity is a fact the caller has and the arithmetic does not",
|
||
"package": "./internal/pipeline/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/pipeline/priceprojection.go",
|
||
"find": "\tif sp.carriesSource && !inputIsSource {",
|
||
"replace": "\tif sp.carriesSource && inputTokens != sourceTokens {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "DF-declared-means-every-boundary",
|
||
"why": "acceptance V2-7: asking only whether a form feed appeared called a fifty-chapter header-matched cut `declared` on the strength of one stray \\f — forty-nine guesses reported as the file's own word, and a consumer offering an order in chapters trusts the wrong thing",
|
||
"package": "./internal/chunk/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/chunk/ingest.go",
|
||
"find": "structureOf(chapters, len(parts) > 1 && len(chapters) == len(parts))",
|
||
"replace": "structureOf(chapters, len(parts) > 1)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "DF-book-level-figure-is-a-forecast",
|
||
"why": "acceptance F3: the book-level part of the price is a BOUND the run will not exceed, and calling it money `paid once` in the same breath as the expected total makes a short book read as dearer per chapter than a long one — a wrong conclusion drawn from our sentence rather than from the number",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "cmd/tmctl/render.go",
|
||
"find": "fmt.Fprintf(w, \"expected cost: $%.6f for the whole book (%d source chars)\\n\", p.ExpectedUSD, p.SourceChars)",
|
||
"replace": "fmt.Fprintf(w, \"expected cost: $%.6f for the whole book (%d source chars; $%.6f of it is book-level and paid once)\\n\", p.ExpectedUSD, p.SourceChars, p.BookOnceUSD)"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "DF-no-book-level-spend-says-nothing",
|
||
"why": "acceptance F3, the other half: a configuration with no terminology phase prices no book-level spend, and printing a $0.000000 ceiling invents a bound on passes that never run",
|
||
"package": "./cmd/tmctl/",
|
||
"edits": [
|
||
{
|
||
"file": "cmd/tmctl/render.go",
|
||
"find": "\t\tif p.BookOnceUSD > 0 {",
|
||
"replace": "\t\tif true {"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "DF-a-dropped-row-is-not-silent",
|
||
"why": "the authorship split trades a dead paid run for a dropped row — and a drop nobody can read is the worse half of that trade: a mined term vanishes from every request and an operator asking why has nothing to answer with",
|
||
"package": "./internal/membank/",
|
||
"edits": [
|
||
{
|
||
"file": "internal/membank/memseed.go",
|
||
"find": "\t\t\t\tbs.Dropped = append(bs.Dropped, t.Src)\n",
|
||
"replace": ""
|
||
}
|
||
]
|
||
}
|
||
]
|