[object Object]

← back to Cli Printing Press

feat(cli): flag empty defaultSyncResources at dogfood time (#1633)

042a78d494058fb5d80000bba1b1cfc379e1d2b2 · 2026-05-18 12:24:41 -0700 · Trevin Chow

* feat(cli): flag empty defaultSyncResources at dogfood time

When a spec exposes no bulk-list endpoint (only parameterized detail pages and
required-query searches, e.g. Allrecipes), the profiler correctly produces an
empty SyncableResources slice, but the generator still emits `sync` as a
runtime no-op alongside store-dependent novel commands (cookbook, pantry,
top-rated, ...). The CLI ships with no advertised path to populate the store.

Add a dogfood pipeline_check signal that detects the empty-list emission of
defaultSyncResources() in the generated sync.go and surfaces it as WARN so the
gap is visible at shipcheck time. Also emit a one-line runtime hint (stderr
in human mode, sync_warning JSON event in agent mode) when the structural
precondition holds, so callers see "no bulk-list endpoints in spec; populate
the store via single-fetch commands" instead of a silent total_records:0.

Closes #1156

* fix(cli): always emit sync_file_emitted in pipeline_check JSON

Greptile flagged a JSON-tag asymmetry on PipelineResult: SyncFileEmitted
carried `omitempty` but SyncResourcesPresent did not, so when sync.go is
absent a downstream consumer sees `sync_resources_present: false` with no
sync_file_emitted signal, which incorrectly reads as "should have resources
but does not." Drop the `omitempty` so both fields always appear together
and consumers can disambiguate the three real states:

  sync_file_emitted=false, sync_resources_present=false  no sync surface
  sync_file_emitted=true,  sync_resources_present=true   healthy
  sync_file_emitted=true,  sync_resources_present=false  empty (issue #1156)

Files touched

Diff

commit 042a78d494058fb5d80000bba1b1cfc379e1d2b2
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Mon May 18 12:24:41 2026 -0700

    feat(cli): flag empty defaultSyncResources at dogfood time (#1633)
    
    * feat(cli): flag empty defaultSyncResources at dogfood time
    
    When a spec exposes no bulk-list endpoint (only parameterized detail pages and
    required-query searches, e.g. Allrecipes), the profiler correctly produces an
    empty SyncableResources slice, but the generator still emits `sync` as a
    runtime no-op alongside store-dependent novel commands (cookbook, pantry,
    top-rated, ...). The CLI ships with no advertised path to populate the store.
    
    Add a dogfood pipeline_check signal that detects the empty-list emission of
    defaultSyncResources() in the generated sync.go and surfaces it as WARN so the
    gap is visible at shipcheck time. Also emit a one-line runtime hint (stderr
    in human mode, sync_warning JSON event in agent mode) when the structural
    precondition holds, so callers see "no bulk-list endpoints in spec; populate
    the store via single-fetch commands" instead of a silent total_records:0.
    
    Closes #1156
    
    * fix(cli): always emit sync_file_emitted in pipeline_check JSON
    
    Greptile flagged a JSON-tag asymmetry on PipelineResult: SyncFileEmitted
    carried `omitempty` but SyncResourcesPresent did not, so when sync.go is
    absent a downstream consumer sees `sync_resources_present: false` with no
    sync_file_emitted signal, which incorrectly reads as "should have resources
    but does not." Drop the `omitempty` so both fields always appear together
    and consumers can disambiguate the three real states:
    
      sync_file_emitted=false, sync_resources_present=false  no sync surface
      sync_file_emitted=true,  sync_resources_present=true   healthy
      sync_file_emitted=true,  sync_resources_present=false  empty (issue #1156)
---
 internal/generator/sync_param_passthrough_test.go  |  88 +++++++++++++++
 internal/generator/templates/sync.go.tmpl          |  16 +++
 internal/pipeline/dogfood.go                       |  60 +++++++++-
 internal/pipeline/dogfood_test.go                  | 124 ++++++++++++++++++++-
 .../fail-path-auth-dead.json                       |   4 +-
 .../expected/dogfood-verdict-matrix/pass.json      |   4 +-
 .../dogfood-verdict-matrix/warn-priority.json      |   4 +-
 .../expected/generate-golden-api/dogfood.json      |   4 +-
 8 files changed, 295 insertions(+), 9 deletions(-)

diff --git a/internal/generator/sync_param_passthrough_test.go b/internal/generator/sync_param_passthrough_test.go
index 44433b25..48e2283b 100644
--- a/internal/generator/sync_param_passthrough_test.go
+++ b/internal/generator/sync_param_passthrough_test.go
@@ -233,3 +233,91 @@ func TestGenerateSyncDependentErrorNotSilent(t *testing.T) {
 	assert.Contains(t, syncSrc, "syncErrorJSON(dep.Name, parentID, err)",
 		"dependent-resource non-warning error must emit a sync_error JSON event with the parent ID")
 }
+
+// noBulkListSpec mirrors the Allrecipes shape (issue #1156): a resource whose
+// only GET endpoints are a parameterized detail page and a search with a
+// required query param. Neither qualifies as a syncable list endpoint, so
+// the generator's profile lands SyncableResources empty.
+func noBulkListSpec(name string) *spec.APISpec {
+	apiSpec := minimalSpec(name)
+	apiSpec.Resources = map[string]spec.Resource{
+		"recipes": {
+			Description: "Recipes",
+			Endpoints: map[string]spec.Endpoint{
+				"get": {
+					Method: "GET",
+					Path:   "/recipe/{recipe_id}/{slug}",
+					Params: []spec.Param{
+						{Name: "recipe_id", PathParam: true, Required: true, Type: "string"},
+						{Name: "slug", PathParam: true, Required: true, Type: "string"},
+					},
+					Response: spec.ResponseDef{Type: "object", Item: "Recipe"},
+				},
+				"search": {
+					Method: "GET",
+					Path:   "/search",
+					Params: []spec.Param{
+						{Name: "q", Required: true, Type: "string"},
+					},
+					Response: spec.ResponseDef{Type: "array"},
+				},
+			},
+		},
+	}
+	return apiSpec
+}
+
+// TestGenerateSyncEmitsEmptyHintWhenNoBulkList covers issue #1156. When a spec
+// has no bulk-list endpoint (only parameterized detail pages and required-
+// query searches), defaultSyncResources renders empty and the runtime sync
+// command is a no-op. The template must emit a clear hint so users and agents
+// understand the silence and can find the population path (single-fetch
+// commands writing to the store).
+func TestGenerateSyncEmitsEmptyHintWhenNoBulkList(t *testing.T) {
+	t.Parallel()
+
+	apiSpec := noBulkListSpec("nobulk")
+	outputDir := filepath.Join(t.TempDir(), naming.CLI(apiSpec.Name))
+	require.NoError(t, New(apiSpec, outputDir).Generate())
+
+	syncGo, err := os.ReadFile(filepath.Join(outputDir, "internal", "cli", "sync.go"))
+	require.NoError(t, err)
+	syncSrc := string(syncGo)
+
+	// Sanity: the structural precondition matches Allrecipes shape with both
+	// syncable and dependent slices empty, so defaultSyncResources renders
+	// with an empty body.
+	assert.Regexp(t,
+		`func defaultSyncResources\(\) \[\]string \{\s*return \[\]string\{\}\s*\}`,
+		syncSrc,
+		"defaultSyncResources should be empty for a spec with no bulk-list endpoints",
+	)
+
+	// The runtime hint surfaces in both modes so JSON-driven agents and human
+	// callers both see the explanation instead of a silent total_records:0.
+	assert.Contains(t, syncSrc, "no bulk-list endpoints",
+		"sync should print a stderr hint when defaultSyncResources is empty")
+	assert.Contains(t, syncSrc, `"reason":"no_bulk_list_endpoints"`,
+		"sync should emit a sync_warning JSON event when defaultSyncResources is empty")
+}
+
+// TestGenerateSyncSkipsEmptyHintWhenBulkListExists ensures the template hint
+// is template-time conditional and does not appear when the spec exposes at
+// least one syncable resource. Without this guard, every CLI would carry the
+// dead branch.
+func TestGenerateSyncSkipsEmptyHintWhenBulkListExists(t *testing.T) {
+	t.Parallel()
+
+	apiSpec := minimalSpec("withbulk")
+	outputDir := filepath.Join(t.TempDir(), naming.CLI(apiSpec.Name))
+	require.NoError(t, New(apiSpec, outputDir).Generate())
+
+	syncGo, err := os.ReadFile(filepath.Join(outputDir, "internal", "cli", "sync.go"))
+	require.NoError(t, err)
+	syncSrc := string(syncGo)
+
+	assert.NotContains(t, syncSrc, "no bulk-list endpoints",
+		"sync should not carry the empty-list hint when a syncable resource exists")
+	assert.NotContains(t, syncSrc, `"reason":"no_bulk_list_endpoints"`,
+		"sync should not emit the no_bulk_list_endpoints event when a syncable resource exists")
+}
diff --git a/internal/generator/templates/sync.go.tmpl b/internal/generator/templates/sync.go.tmpl
index b55d02cb..312a10fa 100644
--- a/internal/generator/templates/sync.go.tmpl
+++ b/internal/generator/templates/sync.go.tmpl
@@ -156,6 +156,22 @@ Resource scoping:
 			if len(resources) == 0 {
 				resources = defaultSyncResources()
 			}
+{{- if and (not .SyncableResources) (not .DependentSyncResources)}}
+
+			// Empty-sync hint: this spec exposed no bulk-list endpoint and no
+			// dependent resources, so `sync` cannot populate the store on its
+			// own. Emit a one-line note so users and agents understand the
+			// runtime no-op instead of seeing only `total_records: 0`. The
+			// store is still populated by single-fetch commands (recipe, get,
+			// fetch, …) that the spec's other resources define.
+			if len(resources) == 0 {
+				if humanFriendly {
+					fmt.Fprintln(os.Stderr, "{{.Name}}-pp-cli sync: no bulk-list endpoints in spec; populate the store via single-fetch commands instead.")
+				} else {
+					fmt.Fprintln(os.Stdout, `{"event":"sync_warning","reason":"no_bulk_list_endpoints","detail":"no bulk-list endpoints in spec; populate the store via single-fetch commands"}`)
+				}
+			}
+{{- end}}
 
 			// Reject --resource-param keys that don't match a known resource.
 			// Validates against the full top-level + dependent set, not the
diff --git a/internal/pipeline/dogfood.go b/internal/pipeline/dogfood.go
index 763dd05c..b063f8db 100644
--- a/internal/pipeline/dogfood.go
+++ b/internal/pipeline/dogfood.go
@@ -123,10 +123,12 @@ type DeadCodeResult struct {
 }
 
 type PipelineResult struct {
-	SyncCallsDomain   bool   `json:"sync_calls_domain"`
-	SearchCallsDomain bool   `json:"search_calls_domain"`
-	DomainTables      int    `json:"domain_tables"`
-	Detail            string `json:"detail"`
+	SyncCallsDomain      bool   `json:"sync_calls_domain"`
+	SearchCallsDomain    bool   `json:"search_calls_domain"`
+	DomainTables         int    `json:"domain_tables"`
+	SyncFileEmitted      bool   `json:"sync_file_emitted"`
+	SyncResourcesPresent bool   `json:"sync_resources_present"`
+	Detail               string `json:"detail"`
 }
 
 type ExampleCheckResult struct {
@@ -1460,6 +1462,8 @@ func checkPipelineIntegrity(dir string) PipelineResult {
 	result.SyncCallsDomain = domainUpsertRe.MatchString(syncSource)
 	result.SearchCallsDomain = domainSearchRe.MatchString(searchSource)
 	result.DomainTables = countDomainTables(storeSource)
+	result.SyncFileEmitted = syncSource != ""
+	result.SyncResourcesPresent = hasPopulatedSyncResources(syncSource)
 
 	var parts []string
 	switch {
@@ -1484,10 +1488,48 @@ func checkPipelineIntegrity(dir string) PipelineResult {
 		parts = append(parts, fmt.Sprintf("%d domain tables found", result.DomainTables))
 	}
 
+	// When sync.go is emitted but defaultSyncResources() returns an empty list,
+	// the sync command is a no-op at runtime. Store-dependent novel commands
+	// (cookbook, pantry, top-rated, …) then ship with no advertised path to
+	// populate the store. Flag so the absence surfaces at shipcheck time.
+	if syncSource != "" && !result.SyncResourcesPresent {
+		parts = append(parts, "defaultSyncResources empty (sync command is a no-op)")
+	}
+
 	result.Detail = strings.Join(parts, "; ")
 	return result
 }
 
+// defaultSyncResourcesEmptyRe matches the generator's empty-list emission for
+// defaultSyncResources, after gofmt collapses `return []string{\n}` to a single
+// line. Matching the open-brace through the literal "}" keeps the check robust
+// against trailing whitespace and the gofmt-aware "\n\t}" form some emitters
+// produce when the template body has a leading newline.
+var defaultSyncResourcesEmptyRe = regexp.MustCompile(
+	`(?s)func\s+defaultSyncResources\s*\(\s*\)\s*\[\]string\s*\{\s*return\s+\[\]string\{\s*\}\s*\}`,
+)
+
+// hasPopulatedSyncResources reports whether the emitted sync.go declares at
+// least one syncable resource via the defaultSyncResources() helper. Returns
+// true when defaultSyncResources is either absent (hand-rolled or test
+// fixture sync surfaces are not the failure mode this check targets) or
+// present with at least one entry. Returns false only when the helper is
+// emitted with an explicit empty-list body `return []string{}`. Used by
+// dogfood's pipeline check to surface CLIs that emit a sync command with
+// nothing to sync: the failure mode where store-dependent novel commands
+// have no advertised population path.
+func hasPopulatedSyncResources(syncSource string) bool {
+	if syncSource == "" {
+		return false
+	}
+	if !strings.Contains(syncSource, "func defaultSyncResources") {
+		// No generator-emitted helper to inspect. Treat as "not the failure
+		// mode" rather than risking false positives on hand-rolled sync.
+		return true
+	}
+	return !defaultSyncResourcesEmptyRe.MatchString(syncSource)
+}
+
 type dogfoodVerdictRule struct {
 	verdict string
 	match   func(*DogfoodReport, bool) bool
@@ -1508,6 +1550,13 @@ var dogfoodVerdictRules = []dogfoodVerdictRule{
 	{"WARN", func(r *DogfoodReport, _ bool) bool { return r.DeadFlags.Dead >= 1 && r.DeadFlags.Dead <= 2 }},
 	{"WARN", func(r *DogfoodReport, _ bool) bool { return r.DeadFuncs.Dead >= 1 }},
 	{"WARN", func(r *DogfoodReport, _ bool) bool { return !r.PipelineCheck.SyncCallsDomain }},
+	{"WARN", func(r *DogfoodReport, _ bool) bool {
+		// Issue #1156: when defaultSyncResources is emitted empty, the sync
+		// command is a runtime no-op and store-dependent novel commands have
+		// no advertised path to populate the store. Promote to WARN so the
+		// gap surfaces at shipcheck time rather than after publish.
+		return r.PipelineCheck.SyncFileEmitted && !r.PipelineCheck.SyncResourcesPresent
+	}},
 	{"WARN", func(r *DogfoodReport, _ bool) bool { return len(r.ExampleCheck.InvalidFlags) > 0 }},
 	{"WARN", func(r *DogfoodReport, _ bool) bool { return r.ExampleCheck.Skipped }},
 	{"FAIL", func(r *DogfoodReport, _ bool) bool { return len(r.WiringCheck.CommandTree.Unregistered) > 0 }},
@@ -1562,6 +1611,9 @@ func collectDogfoodIssues(report *DogfoodReport, hasSpec bool) []string {
 	if !report.PipelineCheck.SyncCallsDomain {
 		issues = append(issues, "sync uses generic Upsert only")
 	}
+	if report.PipelineCheck.SyncFileEmitted && !report.PipelineCheck.SyncResourcesPresent {
+		issues = append(issues, "defaultSyncResources empty: sync command is a runtime no-op; store-dependent novel commands have no advertised population path")
+	}
 	if report.ExampleCheck.Tested > 0 && (report.ExampleCheck.WithExamples*100/report.ExampleCheck.Tested) < 50 {
 		issues = append(issues, fmt.Sprintf("%d%% example coverage", report.ExampleCheck.WithExamples*100/report.ExampleCheck.Tested))
 	}
diff --git a/internal/pipeline/dogfood_test.go b/internal/pipeline/dogfood_test.go
index 2ccebbfe..306c163f 100644
--- a/internal/pipeline/dogfood_test.go
+++ b/internal/pipeline/dogfood_test.go
@@ -215,13 +215,126 @@ CREATE TABLE IF NOT EXISTS sync_state (
 	assert.Equal(t, 1, countDomainTables(storeSource))
 }
 
+// TestCheckPipelineIntegritySyncResourcesEmpty asserts that when the generator
+// emits sync.go with an empty defaultSyncResources() body (the structural
+// signature of an API with no bulk-list endpoint, e.g., Allrecipes), dogfood's
+// pipeline check records SyncFileEmitted=true and SyncResourcesPresent=false
+// and surfaces the detail string. Issue #1156.
+func TestCheckPipelineIntegritySyncResourcesEmpty(t *testing.T) {
+	dir := t.TempDir()
+	require.NoError(t, os.MkdirAll(filepath.Join(dir, "internal", "cli"), 0o755))
+	require.NoError(t, os.MkdirAll(filepath.Join(dir, "internal", "store"), 0o755))
+
+	writeTestFile(t, filepath.Join(dir, "internal", "cli", "sync.go"), `package cli
+
+func runSync(s interface{ UpsertItems() error }) error {
+	return s.UpsertItems()
+}
+
+func defaultSyncResources() []string {
+	return []string{}
+}
+`)
+	writeTestFile(t, filepath.Join(dir, "internal", "store", "store.go"), "package store\n")
+
+	result := checkPipelineIntegrity(dir)
+	assert.True(t, result.SyncFileEmitted, "sync.go was written")
+	assert.False(t, result.SyncResourcesPresent, "defaultSyncResources is empty")
+	assert.Contains(t, result.Detail, "defaultSyncResources empty")
+}
+
+// TestCheckPipelineIntegritySyncResourcesPopulated covers the normal case where
+// the generator emits sync.go with one or more resources. Both new fields
+// should be set; the empty-list detail string should not appear.
+func TestCheckPipelineIntegritySyncResourcesPopulated(t *testing.T) {
+	dir := t.TempDir()
+	require.NoError(t, os.MkdirAll(filepath.Join(dir, "internal", "cli"), 0o755))
+	require.NoError(t, os.MkdirAll(filepath.Join(dir, "internal", "store"), 0o755))
+
+	writeTestFile(t, filepath.Join(dir, "internal", "cli", "sync.go"), `package cli
+
+func runSync(s interface{ UpsertUsers() error }) error {
+	return s.UpsertUsers()
+}
+
+func defaultSyncResources() []string {
+	return []string{
+		"users",
+	}
+}
+`)
+	writeTestFile(t, filepath.Join(dir, "internal", "store", "store.go"), "package store\n")
+
+	result := checkPipelineIntegrity(dir)
+	assert.True(t, result.SyncFileEmitted)
+	assert.True(t, result.SyncResourcesPresent)
+	assert.NotContains(t, result.Detail, "defaultSyncResources empty")
+}
+
+func TestHasPopulatedSyncResources(t *testing.T) {
+	tests := []struct {
+		name string
+		src  string
+		want bool
+	}{
+		{
+			name: "empty source",
+			src:  "",
+			want: false,
+		},
+		{
+			name: "helper absent (hand-rolled or fixture)",
+			src:  "package cli\nfunc runSync() {}\n",
+			want: true,
+		},
+		{
+			name: "helper present with empty list",
+			src: `package cli
+func defaultSyncResources() []string {
+	return []string{}
+}
+`,
+			want: false,
+		},
+		{
+			name: "helper present with one entry",
+			src: `package cli
+func defaultSyncResources() []string {
+	return []string{
+		"users",
+	}
+}
+`,
+			want: true,
+		},
+		{
+			name: "helper present with several entries",
+			src: `package cli
+func defaultSyncResources() []string {
+	return []string{
+		"commissions",
+		"customers",
+		"domains",
+	}
+}
+`,
+			want: true,
+		},
+	}
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			assert.Equal(t, tc.want, hasPopulatedSyncResources(tc.src))
+		})
+	}
+}
+
 func TestDeriveDogfoodVerdict(t *testing.T) {
 	report := &DogfoodReport{
 		PathCheck:     PathCheckResult{Tested: 10, Valid: 10, Pct: 100},
 		AuthCheck:     AuthCheckResult{Match: true},
 		DeadFlags:     DeadCodeResult{Dead: 1},
 		DeadFuncs:     DeadCodeResult{Dead: 0},
-		PipelineCheck: PipelineResult{SyncCallsDomain: true},
+		PipelineCheck: PipelineResult{SyncCallsDomain: true, SyncResourcesPresent: true},
 	}
 	assert.Equal(t, "WARN", deriveDogfoodVerdict(report, true))
 
@@ -236,6 +349,15 @@ func TestDeriveDogfoodVerdict(t *testing.T) {
 	report.PipelineCheck.SyncCallsDomain = true
 	assert.Equal(t, "PASS", deriveDogfoodVerdict(report, true))
 
+	// Issue #1156: when sync.go is emitted but defaultSyncResources is empty,
+	// the sync command is a runtime no-op. Dogfood must flag this as WARN so
+	// the gap surfaces at shipcheck time.
+	report.PipelineCheck.SyncFileEmitted = true
+	report.PipelineCheck.SyncResourcesPresent = false
+	assert.Equal(t, "WARN", deriveDogfoodVerdict(report, true))
+	report.PipelineCheck.SyncResourcesPresent = true
+	assert.Equal(t, "PASS", deriveDogfoodVerdict(report, true))
+
 	report.ExampleCheck = ExampleCheckResult{Tested: 10, WithExamples: 4}
 	assert.Equal(t, "FAIL", deriveDogfoodVerdict(report, true))
 
diff --git a/testdata/golden/expected/dogfood-verdict-matrix/fail-path-auth-dead.json b/testdata/golden/expected/dogfood-verdict-matrix/fail-path-auth-dead.json
index cb4f2924..803652fb 100644
--- a/testdata/golden/expected/dogfood-verdict-matrix/fail-path-auth-dead.json
+++ b/testdata/golden/expected/dogfood-verdict-matrix/fail-path-auth-dead.json
@@ -61,7 +61,9 @@
     "detail": "sync uses domain-specific Upsert methods; search methods not found",
     "domain_tables": 0,
     "search_calls_domain": false,
-    "sync_calls_domain": true
+    "sync_calls_domain": true,
+    "sync_file_emitted": true,
+    "sync_resources_present": true
   },
   "print_json_filtered_check": {
     "checked": 3
diff --git a/testdata/golden/expected/dogfood-verdict-matrix/pass.json b/testdata/golden/expected/dogfood-verdict-matrix/pass.json
index 15d537d0..75f68366 100644
--- a/testdata/golden/expected/dogfood-verdict-matrix/pass.json
+++ b/testdata/golden/expected/dogfood-verdict-matrix/pass.json
@@ -48,7 +48,9 @@
     "detail": "sync uses domain-specific Upsert methods; search methods not found",
     "domain_tables": 0,
     "search_calls_domain": false,
-    "sync_calls_domain": true
+    "sync_calls_domain": true,
+    "sync_file_emitted": true,
+    "sync_resources_present": true
   },
   "print_json_filtered_check": {
     "checked": 2
diff --git a/testdata/golden/expected/dogfood-verdict-matrix/warn-priority.json b/testdata/golden/expected/dogfood-verdict-matrix/warn-priority.json
index d796a421..cdadc080 100644
--- a/testdata/golden/expected/dogfood-verdict-matrix/warn-priority.json
+++ b/testdata/golden/expected/dogfood-verdict-matrix/warn-priority.json
@@ -55,7 +55,9 @@
     "detail": "sync uses domain-specific Upsert methods; search methods not found",
     "domain_tables": 0,
     "search_calls_domain": false,
-    "sync_calls_domain": true
+    "sync_calls_domain": true,
+    "sync_file_emitted": true,
+    "sync_resources_present": true
   },
   "print_json_filtered_check": {
     "checked": 3
diff --git a/testdata/golden/expected/generate-golden-api/dogfood.json b/testdata/golden/expected/generate-golden-api/dogfood.json
index f0770511..15ac1ee3 100644
--- a/testdata/golden/expected/generate-golden-api/dogfood.json
+++ b/testdata/golden/expected/generate-golden-api/dogfood.json
@@ -51,7 +51,9 @@
     "detail": "sync uses domain-specific Upsert methods; search uses generic Search only; 1 domain tables found",
     "domain_tables": 1,
     "search_calls_domain": false,
-    "sync_calls_domain": true
+    "sync_calls_domain": true,
+    "sync_file_emitted": true,
+    "sync_resources_present": true
   },
   "print_json_filtered_check": {
     "checked": 34

← 14bc18a4 feat(cli): default mcp.transport=[stdio, http] for small API  ·  back to Cli Printing Press  ·  fix(cli): route Swagger 2.0 specs through openapi2conv to av e798f671 →