A removal of a replacement names both fingerprints; the two-texts refusal names the places and the way out
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -215,6 +215,11 @@ func (p Proposal) glanceAsk() oc.Ask {
|
|||||||
}
|
}
|
||||||
fmt.Fprintf(&d, "Proposed through the claude-code module on %s at %s UTC. %s has the fingerprint %s.",
|
fmt.Fprintf(&d, "Proposed through the claude-code module on %s at %s UTC. %s has the fingerprint %s.",
|
||||||
p.From, p.At.UTC().Format("15:04 on 2 Jan"), removes, print)
|
p.From, p.At.UTC().Format("15:04 on 2 Jan"), removes, print)
|
||||||
|
if p.Over != "" && p.Digest != p.Over {
|
||||||
|
// A replacement is removed with the registered text it stands over: both fingerprints, the replacement's
|
||||||
|
// being the text sessions read.
|
||||||
|
fmt.Fprintf(&d, " The replacement sessions read, which it also removes, has the fingerprint %s.", p.Fingerprint())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if whole {
|
if whole {
|
||||||
d.WriteString("The text:\n" + shown + "\n")
|
d.WriteString("The text:\n" + shown + "\n")
|
||||||
@@ -1352,25 +1357,33 @@ func registeredSection(p Paths, scope string, nodes []string, name string) (stri
|
|||||||
_ = readJSON(p.config(), &items)
|
_ = readJSON(p.config(), &items)
|
||||||
c := ConfigOf(Taken(items))
|
c := ConfigOf(Taken(items))
|
||||||
c.Terminal, _ = terminalText(p)
|
c.Terminal, _ = terminalText(p)
|
||||||
layers := [][]Item{c.Mesh, c.Terminal}
|
type place struct {
|
||||||
|
items []Item
|
||||||
|
says string
|
||||||
|
}
|
||||||
|
places := []place{{c.Mesh, "registered for the mesh (unregister it with claude_code_instructions_unregister, scope mesh, name " + name + ")"},
|
||||||
|
{c.Terminal, "set at the controller's terminal (its instructions setting)"}}
|
||||||
if scope == ScopeNode {
|
if scope == ScopeNode {
|
||||||
layers = [][]Item{c.Node, c.Terminal}
|
places = []place{{c.Node, "registered for this node (unregister it with claude_code_instructions_unregister, scope node, name " + name + ")"},
|
||||||
|
{c.Terminal, "set at the controller's terminal (its instructions setting)"}}
|
||||||
if !contains(nodes, p.Node) {
|
if !contains(nodes, p.Node) {
|
||||||
layers = [][]Item{c.Terminal}
|
places = places[1:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
digest := ""
|
digest := ""
|
||||||
for _, layer := range layers {
|
var holding []string
|
||||||
for _, it := range layer {
|
for _, pl := range places {
|
||||||
|
for _, it := range pl.items {
|
||||||
if it.Kind != KindInstructions || it.Name != name {
|
if it.Kind != KindInstructions || it.Name != name {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
d := textDigest(it.Files[name+".md"])
|
d := textDigest(it.Files[name+".md"])
|
||||||
if digest != "" && d != digest {
|
if digest != "" && d != digest {
|
||||||
return "", fmt.Errorf("the section %q is registered with different texts (for the mesh and at the controller's terminal); "+
|
return "", fmt.Errorf("the section %q is registered with different texts: %s and %s; an approval is bound to one text, "+
|
||||||
"remove one of them first", name)
|
"so unregister one of them first", name, strings.Join(holding, ", "), pl.says)
|
||||||
}
|
}
|
||||||
digest = d
|
digest = d
|
||||||
|
holding = append(holding, pl.says)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return digest, nil
|
return digest, nil
|
||||||
|
|||||||
@@ -190,7 +190,9 @@ func TestRegisteredSectionEdgeCases(t *testing.T) {
|
|||||||
writeFile(t, p.Settings, string(raw))
|
writeFile(t, p.Settings, string(raw))
|
||||||
store, r := &memProposals{m: map[string]json.RawMessage{}}, newRouter()
|
store, r := &memProposals{m: map[string]json.RawMessage{}}, newRouter()
|
||||||
in := ProposeInput{Scope: ScopeMesh, Name: name, Text: "A third text.\n"}
|
in := ProposeInput{Scope: ScopeMesh, Name: name, Text: "A third text.\n"}
|
||||||
if _, err := Propose(p, in, store, r, t0); err == nil || !strings.Contains(err.Error(), "different texts") {
|
if _, err := Propose(p, in, store, r, t0); err == nil || !strings.Contains(err.Error(), "different texts") ||
|
||||||
|
!strings.Contains(err.Error(), "claude_code_instructions_unregister, scope mesh, name "+name) ||
|
||||||
|
!strings.Contains(err.Error(), "set at the controller's terminal") {
|
||||||
t.Fatalf("a name registered with two texts was proposed over: %v", err)
|
t.Fatalf("a name registered with two texts was proposed over: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := Propose(p, ProposeInput{Scope: ScopeMesh, Name: name, Remove: true}, store, r, t0); err == nil {
|
if _, err := Propose(p, ProposeInput{Scope: ScopeMesh, Name: name, Remove: true}, store, r, t0); err == nil {
|
||||||
@@ -223,11 +225,11 @@ func TestRegisteredSectionEdgeCases(t *testing.T) {
|
|||||||
if got := renderedInstructions(t, p); strings.Contains(got, "The old words.") || strings.Contains(got, "The new words.") {
|
if got := renderedInstructions(t, p); strings.Contains(got, "The old words.") || strings.Contains(got, "The new words.") {
|
||||||
t.Errorf("a text is left:\n%s", got)
|
t.Errorf("a text is left:\n%s", got)
|
||||||
}
|
}
|
||||||
// The ask names the registered text's fingerprint, not the replacement's.
|
// The ask names both fingerprints: the registered text's, and the replacement's that sessions read.
|
||||||
d := r.published[rid].Details
|
d := r.published[rid].Details
|
||||||
if !strings.Contains(d, "The registered text it removes has the fingerprint "+fingerprintOf(textDigest(registeredOld))) ||
|
if !strings.Contains(d, "The registered text it removes has the fingerprint "+fingerprintOf(textDigest(registeredOld))) ||
|
||||||
strings.Contains(d, fingerprintOf(textDigest(registeredNew))) {
|
!strings.Contains(d, "has the fingerprint "+fingerprintOf(textDigest(registeredNew))) {
|
||||||
t.Errorf("the removal names the wrong fingerprint: %q", d)
|
t.Errorf("the removal does not name both fingerprints: %q", d)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run("TestAChangedRegisteredTextOutlivesItsApproval", func(t *testing.T) {
|
t.Run("TestAChangedRegisteredTextOutlivesItsApproval", func(t *testing.T) {
|
||||||
@@ -248,9 +250,13 @@ func TestRegisteredSectionEdgeCases(t *testing.T) {
|
|||||||
raw, _ := json.Marshal(map[string]Item{"mesh.instructions." + name: {Kind: KindInstructions, Name: name,
|
raw, _ := json.Marshal(map[string]Item{"mesh.instructions." + name: {Kind: KindInstructions, Name: name,
|
||||||
Scope: ScopeMesh, Files: one(name, "A later registered text.\n"), By: "g14"}})
|
Scope: ScopeMesh, Files: one(name, "A later registered text.\n"), By: "g14"}})
|
||||||
writeFile(t, p.config(), string(raw))
|
writeFile(t, p.config(), string(raw))
|
||||||
if got := renderedInstructions(t, p); !strings.Contains(got, "A later registered text.") {
|
got := renderedInstructions(t, p)
|
||||||
|
if !strings.Contains(got, "A later registered text.") {
|
||||||
t.Errorf("the changed registered text was swallowed by the old approval:\n%s", got)
|
t.Errorf("the changed registered text was swallowed by the old approval:\n%s", got)
|
||||||
}
|
}
|
||||||
|
if !strings.Contains(got, "The new words.") || !strings.Contains(got, "## Instructions the operator approved") {
|
||||||
|
t.Errorf("the approved replacement does not render among the approved sections:\n%s", got)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
t.Run("TestARemovalOfARemovedSectionIsRefused", func(t *testing.T) {
|
t.Run("TestARemovalOfARemovedSectionIsRefused", func(t *testing.T) {
|
||||||
p, _ := node(t, "g14")
|
p, _ := node(t, "g14")
|
||||||
|
|||||||
Reference in New Issue
Block a user