Tighten RPI handoffs and exercise them on a Go gate repair (#1124)

## What

Clarify the existing RPI and Implement skills so delegated work
preserves consumer input selection, carries a short check list, uses
task-only runtime dispatch, and leaves final subject evidence to the
integrating caller. Exact identity, required checks, affected evidence
handling, and fresh independent judgment remain required.

Exercise the revised guidance on one real Go defect: learning-file read
errors now fail the gate with the affected path, while genuinely deleted
files retain their existing skip behavior. Routing, learning roots,
exclusions, and frontmatter rules are preserved.

## Why

The prior repair run finished successfully but repeatedly loaded context
and assembled overlapping evidence. This change refines existing skill
instructions and their architecture/projections, then tests observable
behavior with a bounded coding task. It adds no scheduler, skill,
schema, or benchmark framework; one trial does not establish general
token savings.

## How I tested

- Existing skill contract checks pass before and after; generated
projections are current.
- Go regression is RED for unreadable learning paths under both roots;
repaired tests and deletion controls pass.
- Combined Go build/race-shuffle coverage tests, coverage floor,
complexity, and local aggregate pass. Exact-source worker lint and hook
vet results are reused.
- All 52 selected gates pass. Authoritative CI passed after one
unchanged rerun of a timeout-test fixture failure; the original failure
and uncertain cause remain retained. No test tolerance or source change
was used to obtain green.
- Fresh author-distinct Codex/OpenAI validation passed every criterion
and all 13 changed paths at `dd7714ea4eee2f6525656fb70c2ac8b264a39a03`;
no actionable findings or unchecked acceptance.

## Checklist

- [x] Go build and tests pass
- [x] No secrets or credentials added
- [x] Changed skill output boundary documented in architecture and
generated copies
This commit is contained in:
Bo
2026-09-10 09:51:08 -04:00
committed by GitHub
parent 8a9a01a70a
commit 9eb4aed225
13 changed files with 200 additions and 103 deletions
+4 -1
View File
@@ -141,7 +141,10 @@ func runLearningCoherence(ctx context.Context, rc gates.RunContext) (ports.GateV
}
data, err := os.ReadFile(filepath.Join(rc.RepoRoot, f))
if err != nil {
continue // deleted
if os.IsNotExist(err) {
continue // deleted
}
return ports.GateVerdict{Status: ports.GateStatusFail, Reason: fmt.Sprintf("read learning %s: %v", f, err)}, nil
}
if !bytes.HasPrefix(data, []byte("---")) {
missing = append(missing, f)
@@ -182,6 +182,51 @@ func TestRunLearningCoherence_ChecksCanonicalAoRoot(t *testing.T) {
}
}
func TestRunLearningCoherence_ReadFailureBlocks(t *testing.T) {
check, ok := gates.Default.Get("learning.coherence")
if !ok {
t.Fatal("learning.coherence is not registered")
}
for _, rel := range []string{".agents/ao/learnings/bad.md", ".agents/learnings/bad.md"} {
t.Run(rel, func(t *testing.T) {
root := t.TempDir()
// A directory reliably makes ReadFile fail without permission assumptions.
if err := os.MkdirAll(filepath.Join(root, rel), 0o755); err != nil {
t.Fatal(err)
}
verdict, err := runLearningCoherence(context.Background(), gates.RunContext{
RepoRoot: root, Mode: gates.Fast, ChangedFiles: []string{rel},
})
if err != nil {
t.Fatalf("runLearningCoherence: %v", err)
}
if verdict.Status != ports.GateStatusFail {
t.Fatalf("status = %s, want FAIL for unreadable learning %q", verdict.Status, rel)
}
if !strings.Contains(verdict.Reason, rel) {
t.Fatalf("reason = %q, want unreadable learning path %q", verdict.Reason, rel)
}
report := gates.Report{Results: []gates.CheckResult{{Check: check, Verdict: verdict}}}
if got := report.ExitCode(); got != 1 {
t.Fatalf("Report.ExitCode() = %d, want 1 for unreadable learning", got)
}
})
}
}
func TestRunLearningCoherence_DeletedFileSkipped(t *testing.T) {
for _, rel := range []string{".agents/ao/learnings/deleted.md", ".agents/learnings/deleted.md"} {
t.Run(rel, func(t *testing.T) {
verdict, err := runLearningCoherence(context.Background(), gates.RunContext{
RepoRoot: t.TempDir(), Mode: gates.Fast, ChangedFiles: []string{rel},
})
if err != nil || verdict.Status != ports.GateStatusPass {
t.Fatalf("deleted learning = %+v, error = %v; want PASS", verdict, err)
}
})
}
}
// equalSetChecks reports whether a and b hold the same elements (order-independent).
func equalSetChecks(a, b []string) bool {
if len(a) != len(b) {