Description
rootline schema propose --incremental emits a bootstrap-flat / create_stem proposal targeting an already-existing root .stem when the scanned records produce no inferred schema fields. The fixture is governed by a valid version-2 root schema, and every record validates cleanly before proposal generation.
Classification: CLI DEFECT
The documented claim is:
--incremental: skips proposals covered by existing .stem files
Source: .claude/skills/rootline/ref-schema.md:149.
Steps to Reproduce
Reconstruct a clean fixture that reaches real schema resolution and validation:
fixture="$(mktemp -d)"
cat >"$fixture/.stem" <<'YAML'
version: 2
root: true
scope:
match: "*.md"
schema:
kind:
type: enum
required: false
values: [note, memo]
YAML
printf '# Alpha\n\nBody only.\n' >"$fixture/a.md"
printf '# Beta\n\nBody only.\n' >"$fixture/b.md"
rootline describe "$fixture" --field schema.kind -o json
rootline validate --all "$fixture" -o json
rootline schema propose --incremental "$fixture" -o json
The describe command proves the existing .stem is resolved as a version-2 schema field:
{"required":false,"severity":"error","source":"<fixture>/.stem","type":"enum","values":["note","memo"]}
Validation reaches the governed records and succeeds:
{"version":2,"kind":"rootline/validate-batch","results":[{"version":1,"kind":"rootline/validate","path":"a.md","valid":true,"errors":[],"warnings":[]},{"version":1,"kind":"rootline/validate","path":"b.md","valid":true,"errors":[],"warnings":[]}],"structural":[],"stem_health":[],"drift_warnings":[],"notices":[],"summary":{"total":2,"valid":2,"invalid":0,"errors_count":0,"warnings_count":0,"drift_warnings_count":0,"structural_errors_count":0,"structural_warnings_count":0,"stem_health_errors_count":0,"stem_health_warnings_count":0,"stem_health_info_count":0}}
The incremental proposal still targets the existing .stem:
{"version":1,"kind":"rootline/schema-proposals","path":"<fixture>","root":"<fixture>","incremental":true,"proposals":[{"id":"bootstrap-flat","operation":"create_stem","target":"<fixture>/.stem","confidence":0.85,"requires_agent":false,"patch":"version: 2\nscope:\n match: \"*.md\"\nschema:\n","patch_preview":"version: 2\nscope:\n match: \"*.md\"\nschema:\n"}],"summary":{"total":1,"requires_agent":0,"engine_resolved":1}}
Expected Behavior
proposals is empty or null and summary.total is 0. The records are already governed by the existing valid root .stem, and the generated schema contains no uncovered inferred fields.
Actual Behavior
The command reports one create_stem proposal targeting the .stem that already governs the records. The operation is not applicable without forcing replacement of that existing file.
Why This Matters
Incremental mode cannot be used as a reliable no-op check for already-governed body-only records. Automation sees actionable schema drift where none exists, and the emitted operation targets an existing governance file rather than representing an uncovered inference.
Related Source Evidence
cmd/rootline/schema.go:99-103 and cmd/rootline/schema.go:125-126 expose the same incremental coverage contract in CLI help.
cmd/rootline/schema.go:583-603 appends bootstrap-flat/create_stem before incremental filtering.
cmd/rootline/schema.go:605-617 only runs coverage filtering when schemaToInferences returns at least one inference, so an empty generated schema leaves the pre-appended proposal intact.
cmd/rootline/schema.go:622-647 converts an empty generated schema into an empty inference slice.
cmd/rootline/schema_test.go:80-142 covers non-empty inferred fields but does not exercise the zero-inference branch.
Related Work
Neither issue covers this symptom.
Environment
- Rootline version:
rootline version 9.12.1
- OS: macOS
- Go version: Not applicable, reproduced with the released binary
Description
rootline schema propose --incrementalemits abootstrap-flat/create_stemproposal targeting an already-existing root.stemwhen the scanned records produce no inferred schema fields. The fixture is governed by a valid version-2 root schema, and every record validates cleanly before proposal generation.Classification: CLI DEFECT
The documented claim is:
Source:
.claude/skills/rootline/ref-schema.md:149.Steps to Reproduce
Reconstruct a clean fixture that reaches real schema resolution and validation:
The describe command proves the existing
.stemis resolved as a version-2 schema field:{"required":false,"severity":"error","source":"<fixture>/.stem","type":"enum","values":["note","memo"]}Validation reaches the governed records and succeeds:
{"version":2,"kind":"rootline/validate-batch","results":[{"version":1,"kind":"rootline/validate","path":"a.md","valid":true,"errors":[],"warnings":[]},{"version":1,"kind":"rootline/validate","path":"b.md","valid":true,"errors":[],"warnings":[]}],"structural":[],"stem_health":[],"drift_warnings":[],"notices":[],"summary":{"total":2,"valid":2,"invalid":0,"errors_count":0,"warnings_count":0,"drift_warnings_count":0,"structural_errors_count":0,"structural_warnings_count":0,"stem_health_errors_count":0,"stem_health_warnings_count":0,"stem_health_info_count":0}}The incremental proposal still targets the existing
.stem:{"version":1,"kind":"rootline/schema-proposals","path":"<fixture>","root":"<fixture>","incremental":true,"proposals":[{"id":"bootstrap-flat","operation":"create_stem","target":"<fixture>/.stem","confidence":0.85,"requires_agent":false,"patch":"version: 2\nscope:\n match: \"*.md\"\nschema:\n","patch_preview":"version: 2\nscope:\n match: \"*.md\"\nschema:\n"}],"summary":{"total":1,"requires_agent":0,"engine_resolved":1}}Expected Behavior
proposalsis empty or null andsummary.totalis0. The records are already governed by the existing valid root.stem, and the generated schema contains no uncovered inferred fields.Actual Behavior
The command reports one
create_stemproposal targeting the.stemthat already governs the records. The operation is not applicable without forcing replacement of that existing file.Why This Matters
Incremental mode cannot be used as a reliable no-op check for already-governed body-only records. Automation sees actionable schema drift where none exists, and the emitted operation targets an existing governance file rather than representing an uncovered inference.
Related Source Evidence
cmd/rootline/schema.go:99-103andcmd/rootline/schema.go:125-126expose the same incremental coverage contract in CLI help.cmd/rootline/schema.go:583-603appendsbootstrap-flat/create_stembefore incremental filtering.cmd/rootline/schema.go:605-617only runs coverage filtering whenschemaToInferencesreturns at least one inference, so an empty generated schema leaves the pre-appended proposal intact.cmd/rootline/schema.go:622-647converts an empty generated schema into an empty inference slice.cmd/rootline/schema_test.go:80-142covers non-empty inferred fields but does not exercise the zero-inference branch.Related Work
schema apply, not redundant proposal generation.Neither issue covers this symptom.
Environment
rootline version 9.12.1