Declare snapshot-bound direct canvas membership counts in model streams
Foundry Go checks / check (push) Successful in 5m54s
Foundry Go checks / check (pull_request) Successful in 5m45s

This commit is contained in:
2026-11-09 03:36:37 +08:00
parent 789edcc61b
commit ad6ab30b5f
2 changed files with 38 additions and 1 deletions
+14 -1
View File
@@ -18,9 +18,22 @@ func writeCanvasModelStream(ctx context.Context, w http.ResponseWriter, model ca
return
}
view := model.view(nil)
// A count covers direct members only; an empty canvas is explicit too.
counts := map[string]int{}
for _, canvas := range view.Canvases {
counts[canvas.ID] = 0
}
for _, element := range view.Elements {
owner := modelString(element["ownerCanvasId"])
if _, ok := counts[owner]; !ok {
reject(w, 500, "invalid_model_coverage")
return
}
counts[owner]++
}
header := response{"streamVersion": 1, "kind": "header", "sequence": 0, "snapshotToken": token,
"documentFormatVersion": canvasModelFormat, "projectId": model.Root, "canvases": view.Canvases,
"versions": view.Versions, "tombstones": view.Tombstones, "removedCanvasIds": view.Removed, "elementCount": len(view.Elements)}
"versions": view.Versions, "tombstones": view.Tombstones, "removedCanvasIds": view.Removed, "elementCount": len(view.Elements), "canvasElementCounts": counts}
const maxLine = 8 * 1024 * 1024
const maxBytes = 64 * 1024 * 1024
sequence, total := 0, 0
@@ -90,3 +90,27 @@ func TestCanonicalModelStreamCancellationNeverClaimsCompletion(t *testing.T) {
t.Fatal("cancelled stream wrote a tail", len(records))
}
}
func TestCanonicalModelStreamDeclaresDirectScopeCountsIncludingEmptyCanvases(t *testing.T) {
model := modelTestDocument()
empty, nested := modelTestID(41), modelTestID(42)
model.Canvases[empty] = modelCanvas{ID: empty, Parent: &modelParent{CanvasID: model.Root, EntryElementID: "frame-empty"}}
model.Canvases[nested] = modelCanvas{ID: nested, Parent: &modelParent{CanvasID: model.Root, EntryElementID: "frame-nested"}}
model.Versions[empty], model.Versions[nested] = 1, 1
model.Elements["frame-empty"] = modelTestNode("frame-empty", model.Root)
model.Elements["frame-nested"] = modelTestNode("frame-nested", model.Root)
model.Elements["nested-node"] = modelTestNode("nested-node", nested)
writer := httptest.NewRecorder()
writeCanvasModelStream(context.Background(), writer, model)
records := streamRecords(t, writer)
if !modelEqual(records[0]["canvasElementCounts"], map[string]int{model.Root: 3, empty: 0, nested: 1}) {
t.Fatal("scope counts must count direct members, preserve empty scopes and match the captured snapshot")
}
bad := modelTestDocument()
bad.Elements["a"]["ownerCanvasId"] = "foreign"
failed := httptest.NewRecorder()
writeCanvasModelStream(context.Background(), failed, bad)
if failed.Code != 500 || failed.Flushed {
t.Fatal("invalid owner must fail before publishing a scope certificate")
}
}