docs(ops): redline evidence batch without capability release

Record SWBOOT L1–L4 (no real repo write), FAV ObserveShadow gates and
observation-window prerequisites, D7 Track E ID-only checklist, and stronger
PI narrative fallback negatives while keeping all redline flags off.
This commit is contained in:
WeiCHEN
2026-09-22 21:26:27 +08:00
parent 364ed7f1a3
commit bc873f4400
25 changed files with 720 additions and 1 deletions
+78 -1
View File
@@ -123,16 +123,22 @@ func TestResolveChangeReport_FlagOnMalformedFullFallback(t *testing.T) {
t.Cleanup(docrevision.ResetPIChangeReportNarrativeForTest)
fromSHA, toSHA, ruleRisk, impacts, diff := sampleDiff(t)
digest := docrevision.NarrativeInputDigest(fromSHA, toSHA, ruleRisk, impacts, diff.Hunks)
cases := []struct {
name string
raw string
}{
{"bad json", `{not-json`},
{"bad schema version", `{"schema_version":99,"schema_kind":"change_report_narrative_v1","input_digest":"x","summary":["a"]}`},
{"wrong schema kind", `{"schema_version":1,"schema_kind":"other_v1","input_digest":"` + digest + `","from_sha":"` + fromSHA + `","to_sha":"` + toSHA + `","summary":["PI only"]}`},
{"digest mismatch", mustNarrativeJSON(t, fromSHA, toSHA, "deadbeef", []string{"ok"})},
{"from_sha mismatch", mustNarrativeJSONWithSHAs(t, "wrong-from", toSHA, digest, []string{"PI only"})},
{"to_sha mismatch", mustNarrativeJSONWithSHAs(t, fromSHA, "wrong-to", digest, []string{"PI only"})},
{"timeout envelope", `{"result_v1":{"outcome":"error","error_code":"TIMEOUT"},"narrative":{"schema_version":1,"schema_kind":"change_report_narrative_v1"}}`},
{"top-level error_code", `{"schema_version":1,"schema_kind":"change_report_narrative_v1","input_digest":"` + digest + `","from_sha":"` + fromSHA + `","to_sha":"` + toSHA + `","error_code":"RUNNER_FAILED","summary":["PI only"]}`},
{"partial flag", `{"schema_version":1,"schema_kind":"change_report_narrative_v1","input_digest":"x","partial":true,"summary":["a"]}`},
{"empty summary", mustNarrativeJSON(t, fromSHA, toSHA, docrevision.NarrativeInputDigest(fromSHA, toSHA, ruleRisk, impacts, diff.Hunks), nil)},
{"empty summary", mustNarrativeJSON(t, fromSHA, toSHA, digest, nil)},
{"empty raw", ""},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
@@ -154,11 +160,19 @@ func TestResolveChangeReport_FlagOnMalformedFullFallback(t *testing.T) {
t.Fatalf("mixed narrative field leaked: %q", s)
}
}
if rep.DeterministicFacts["narrative_applied"] == true {
t.Fatal("fallback must not claim narrative_applied")
}
})
}
}
func mustNarrativeJSON(t *testing.T, fromSHA, toSHA, digest string, summary []string) string {
t.Helper()
return mustNarrativeJSONWithSHAs(t, fromSHA, toSHA, digest, summary)
}
func mustNarrativeJSONWithSHAs(t *testing.T, fromSHA, toSHA, digest string, summary []string) string {
t.Helper()
raw, err := json.Marshal(map[string]any{
"schema_version": 1,
@@ -174,6 +188,43 @@ func mustNarrativeJSON(t *testing.T, fromSHA, toSHA, digest string, summary []st
return string(raw)
}
// TestResolveChangeReport_AuthorizedFlipPathKeepsFlagOffDefault documents the
// pre-authorization contract: default remains off; when a future owner flips the
// flag for a controlled window, malformed PI output still full-falls-back.
func TestResolveChangeReport_AuthorizedFlipPathKeepsFlagOffDefault(t *testing.T) {
docrevision.ResetPIChangeReportNarrativeForTest()
t.Cleanup(docrevision.ResetPIChangeReportNarrativeForTest)
if docrevision.PIChangeReportNarrativeEnabled() {
t.Fatal("PI_CHANGE_REPORT_NARRATIVE must remain off until separately authorized")
}
fromSHA, toSHA, ruleRisk, impacts, diff := sampleDiff(t)
digest := docrevision.NarrativeInputDigest(fromSHA, toSHA, ruleRisk, impacts, diff.Hunks)
piRaw := mustNarrativeJSON(t, fromSHA, toSHA, digest, []string{"should stay ignored while off"})
offRep, err := docrevision.ResolveChangeReport(piRaw, fromSHA, toSHA, ruleRisk, impacts, diff)
if err != nil {
t.Fatal(err)
}
if offRep.AnalysisStatus != docrevision.AnalysisFallback {
t.Fatalf("default-off must ignore PI narrative, got %s", offRep.AnalysisStatus)
}
docrevision.SetPIChangeReportNarrativeForTest(true)
onBad, err := docrevision.ResolveChangeReport(`{"schema_version":1,"schema_kind":"change_report_narrative_v1"}`, fromSHA, toSHA, ruleRisk, impacts, diff)
if err != nil {
t.Fatal(err)
}
if onBad.AnalysisStatus != docrevision.AnalysisFallback {
t.Fatalf("authorized-on malformed must still fallback, got %s", onBad.AnalysisStatus)
}
docrevision.SetPIChangeReportNarrativeForTest(false)
if docrevision.PIChangeReportNarrativeEnabled() {
t.Fatal("test toggle must restore off before exit")
}
}
func TestCreateAgentCandidate_FlagOffIgnoresNarrativeEnrichment(t *testing.T) {
docrevision.SetPIChangeReportNarrativeForTest(false)
t.Cleanup(docrevision.ResetPIChangeReportNarrativeForTest)
@@ -289,6 +340,32 @@ func TestCreateAgentCandidate_FlagOnFetcherErrorFallsBack(t *testing.T) {
}
}
func TestCreateAgentCandidate_FlagOnEmptyFetcherBodyFallsBack(t *testing.T) {
docrevision.SetPIChangeReportNarrativeForTest(true)
t.Cleanup(docrevision.ResetPIChangeReportNarrativeForTest)
svc := docrevision.NewService(nil)
svc.NarrativeFetcher = func(_ context.Context, _ docrevision.NarrativeFetchSpec) (string, error) {
return " ", nil
}
ctx := context.Background()
st, err := svc.OpenTemplateVersion(ctx, "doc_flag_on_empty", "# base\n\nbody\n", docrevision.ActorSnapshot{DisplayName: "t"}, 1, "")
if err != nil {
t.Fatal(err)
}
cand, rep, err := svc.CreateAgentCandidate(ctx, docrevision.AgentCandidateRequest{
DocID: "doc_flag_on_empty", RunID: "r-empty", InputSnapshotID: st.HeadSnapshotID,
OutputMarkdown: "# base\n\nbody changed\n",
ActorKind: docrevision.ActorAgent,
})
if err != nil {
t.Fatalf("empty fetcher body must full-fallback without error, got %v", err)
}
if cand == nil || rep == nil || rep.AnalysisStatus != docrevision.AnalysisFallback {
t.Fatalf("want fallback candidate, got cand=%v rep=%+v", cand, rep)
}
}
func TestNarrativeModelInput_IncludesClippedChangeText(t *testing.T) {
long := strings.Repeat("甲", 280)
spec := docrevision.NarrativeFetchSpec{