fix(api): default hall=facts source_type to internal (brain-gardener#7)
The unsourced-check fix (source_type: internal) only covered claudewatcher's writes. 41 residual findings on the audit's next run were manually-authored hall=facts entries written via brain_write/ capture -- also first-party observations, just a different write path, with no way to mark them internal short of hand-editing every entry. writeHallNote now defaults source_type to internal whenever hall == "facts" and the caller didn't set it explicitly. An explicit source_type: external (now threaded through the /write HTTP endpoint) opts a genuinely citation-needing entry back out.
This commit is contained in:
@@ -51,12 +51,13 @@ type queryRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type writeRequest struct {
|
type writeRequest struct {
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Filename string `json:"filename,omitempty"`
|
Filename string `json:"filename,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
Domain string `json:"domain,omitempty"`
|
Domain string `json:"domain,omitempty"`
|
||||||
Wing string `json:"wing,omitempty"`
|
Wing string `json:"wing,omitempty"`
|
||||||
Hall string `json:"hall,omitempty"`
|
Hall string `json:"hall,omitempty"`
|
||||||
|
SourceType string `json:"source_type,omitempty"` // "external" opts a hall=facts entry out of the internal default
|
||||||
}
|
}
|
||||||
|
|
||||||
type ingestRequest struct {
|
type ingestRequest struct {
|
||||||
@@ -166,8 +167,16 @@ func writeHallNote(brainDir string, opts WriteNoteOptions) (string, error) {
|
|||||||
if opts.Domain != "" {
|
if opts.Domain != "" {
|
||||||
fmt.Fprintf(&fm, "domain: %s\n", opts.Domain)
|
fmt.Fprintf(&fm, "domain: %s\n", opts.Domain)
|
||||||
}
|
}
|
||||||
if opts.SourceType != "" {
|
sourceType := opts.SourceType
|
||||||
fmt.Fprintf(&fm, "source_type: %s\n", opts.SourceType)
|
if sourceType == "" && opts.Hall == "facts" {
|
||||||
|
// Most hall=facts entries are first-party (an eval/benchmark the
|
||||||
|
// writer ran itself), not external claims — default to internal and
|
||||||
|
// require an explicit source_type: external opt-out for the rare
|
||||||
|
// citation-needing entry (brain-gardener#7).
|
||||||
|
sourceType = "internal"
|
||||||
|
}
|
||||||
|
if sourceType != "" {
|
||||||
|
fmt.Fprintf(&fm, "source_type: %s\n", sourceType)
|
||||||
}
|
}
|
||||||
fm.WriteString("---\n")
|
fm.WriteString("---\n")
|
||||||
|
|
||||||
@@ -232,12 +241,13 @@ func (h *Handler) Write(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
relPath, err := WriteNote(h.brainDir, WriteNoteOptions{
|
relPath, err := WriteNote(h.brainDir, WriteNoteOptions{
|
||||||
Content: req.Content,
|
Content: req.Content,
|
||||||
Filename: req.Filename,
|
Filename: req.Filename,
|
||||||
Type: req.Type,
|
Type: req.Type,
|
||||||
Domain: req.Domain,
|
Domain: req.Domain,
|
||||||
Wing: req.Wing,
|
Wing: req.Wing,
|
||||||
Hall: req.Hall,
|
Hall: req.Hall,
|
||||||
|
SourceType: req.SourceType,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("write failed", "err", err)
|
h.logger.Error("write failed", "err", err)
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ func TestWriteNote_HallRouteIncludesSourceTypeWhenSet(t *testing.T) {
|
|||||||
assert.Contains(t, string(got), "wing: claude-sessions")
|
assert.Contains(t, string(got), "wing: claude-sessions")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteNote_HallRouteOmitsSourceTypeWhenUnset(t *testing.T) {
|
func TestWriteNote_HallFactsDefaultsSourceTypeInternalWhenUnset(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
|
|
||||||
rel, err := api.WriteNote(dir, api.WriteNoteOptions{
|
rel, err := api.WriteNote(dir, api.WriteNoteOptions{
|
||||||
@@ -147,6 +147,40 @@ func TestWriteNote_HallRouteOmitsSourceTypeWhenUnset(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
got, err := os.ReadFile(filepath.Join(dir, filepath.FromSlash(rel)))
|
||||||
|
require.NoError(t, err)
|
||||||
|
// Most hall=facts entries are first-party (an eval/benchmark the agent ran
|
||||||
|
// itself), not external claims — default to internal, require explicit
|
||||||
|
// opt-out for the rare case that does need a citation (brain-gardener#7).
|
||||||
|
assert.Contains(t, string(got), "source_type: internal")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteNote_HallFactsPreservesExplicitExternalSourceType(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
|
||||||
|
rel, err := api.WriteNote(dir, api.WriteNoteOptions{
|
||||||
|
Content: "vendor pricing claim, needs a citation.\n",
|
||||||
|
Wing: "agentsquad",
|
||||||
|
Hall: "facts",
|
||||||
|
SourceType: "external",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
got, err := os.ReadFile(filepath.Join(dir, filepath.FromSlash(rel)))
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Contains(t, string(got), "source_type: external")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteNote_HallRouteOmitsSourceTypeForNonFactsHalls(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
|
||||||
|
rel, err := api.WriteNote(dir, api.WriteNoteOptions{
|
||||||
|
Content: "a decision record.\n",
|
||||||
|
Wing: "agentsquad",
|
||||||
|
Hall: "decisions",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
got, err := os.ReadFile(filepath.Join(dir, filepath.FromSlash(rel)))
|
got, err := os.ReadFile(filepath.Join(dir, filepath.FromSlash(rel)))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.NotContains(t, string(got), "source_type")
|
assert.NotContains(t, string(got), "source_type")
|
||||||
|
|||||||
Reference in New Issue
Block a user