Measured on @objectstack/cli 17.2.0 / @objectstack/spec 17.2.0, from a real app (objectstack-ai/duly), while adding kanban / gantt / timeline lenses over one object.
The rule
checkViewCompleteness (spec/dist/kernel — functional-completeness.ts) drives the view/layout-without-binding warning off this table:
var VIEW_BINDING_BLOCKS = {
kanban: "kanban",
calendar: "calendar",
gantt: "gantt"
};
ListViewSchema.type has nine members, and six of them carry a type-specific binding block: kanban, calendar, gantt, timeline, map, tree. The table names three.
Why the other three are the same defect, not a lesser one
The rule's own message is "the renderer falls back to literal default field names … the view renders empty while authoring reports success." That is literally what the uncovered three do. From the console's ListView adapter (plugins-views-*.js, 17.2.0), the fallbacks are hard-coded strings:
| view type |
renderer fallback when the block is absent |
gate |
calendar |
startDateField || 'start_date', endDateField || 'end_date' |
✅ warns |
gantt |
startDateField || 'start_date', endDateField || 'end_date', progressField || 'progress', dependenciesField || 'dependencies' |
✅ warns |
kanban |
groupBy = groupByField || groupField || <inferred> |
✅ warns |
timeline |
startDateField || 'created_at', titleField || 'name' |
❌ silent |
map |
locationField || 'location' |
❌ silent |
tree |
labelField || titleField || 'name' |
❌ silent |
timeline is the sharpest of the three: 'created_at' is a plausible-looking name that many objects do not declare, and the timeline renderer drops every row whose start date does not parse — so the view is blank, not merely mis-titled.
Reproduction (measured, both directions)
In a stack with a duly_task object that declares neither created_at nor start_date:
listViews.recent = { type: 'timeline', … } with its timeline: { startDateField: 'last_update_at', titleField: 'subject', … } block → os validate --json → warnings: [].
- Delete the
timeline block (confirmed on disk: startDateField occurrences 1 → 0, marker present) → os validate --json → warnings: [] again, valid: true. No diagnostic at all.
- Same ablation against the sibling
gantt view → view/layout-without-binding warning fires as designed.
So the gate is working; the table it reads is short.
Suggested fix
Extend VIEW_BINDING_BLOCKS to the full set and give each the same shaped fix hint the existing three carry:
var VIEW_BINDING_BLOCKS = {
kanban: "kanban", calendar: "calendar", gantt: "gantt",
timeline: "timeline", map: "map", tree: "tree",
};
Hints, matching the required keys in each block's schema:
timeline: { startDateField: '<date_field>', titleField: '<text_field>' } (both required by TimelineConfigSchema)
map: { latitudeField: '<number_field>', longitudeField: '<number_field>' } or { locationField: '<field>' }
tree: { labelField: '<text_field>', parentField: '<self_lookup_field>' }
tree is the one worth a second look: TreeConfigSchema's keys are all optional, so "has a tree block" is a weaker assertion there than for the others — see the sibling issue on tree having no value-grouped mode.
Related
Measured on
@objectstack/cli17.2.0 /@objectstack/spec17.2.0, from a real app (objectstack-ai/duly), while adding kanban / gantt / timeline lenses over one object.The rule
checkViewCompleteness(spec/dist/kernel—functional-completeness.ts) drives theview/layout-without-bindingwarning off this table:ListViewSchema.typehas nine members, and six of them carry a type-specific binding block:kanban,calendar,gantt,timeline,map,tree. The table names three.Why the other three are the same defect, not a lesser one
The rule's own message is "the renderer falls back to literal default field names … the view renders empty while authoring reports success." That is literally what the uncovered three do. From the console's ListView adapter (
plugins-views-*.js, 17.2.0), the fallbacks are hard-coded strings:calendarstartDateField || 'start_date',endDateField || 'end_date'ganttstartDateField || 'start_date',endDateField || 'end_date',progressField || 'progress',dependenciesField || 'dependencies'kanbangroupBy = groupByField || groupField || <inferred>timelinestartDateField || 'created_at',titleField || 'name'maplocationField || 'location'treelabelField || titleField || 'name'timelineis the sharpest of the three:'created_at'is a plausible-looking name that many objects do not declare, and the timeline renderer drops every row whose start date does not parse — so the view is blank, not merely mis-titled.Reproduction (measured, both directions)
In a stack with a
duly_taskobject that declares neithercreated_atnorstart_date:listViews.recent={ type: 'timeline', … }with itstimeline: { startDateField: 'last_update_at', titleField: 'subject', … }block →os validate --json→warnings: [].timelineblock (confirmed on disk:startDateFieldoccurrences 1 → 0, marker present) →os validate --json→warnings: []again,valid: true. No diagnostic at all.ganttview →view/layout-without-bindingwarning fires as designed.So the gate is working; the table it reads is short.
Suggested fix
Extend
VIEW_BINDING_BLOCKSto the full set and give each the same shapedfixhint the existing three carry:Hints, matching the required keys in each block's schema:
timeline: { startDateField: '<date_field>', titleField: '<text_field>' }(both required byTimelineConfigSchema)map: { latitudeField: '<number_field>', longitudeField: '<number_field>' }or{ locationField: '<field>' }tree: { labelField: '<text_field>', parentField: '<self_lookup_field>' }treeis the one worth a second look:TreeConfigSchema's keys are all optional, so "has atreeblock" is a weaker assertion there than for the others — see the sibling issue ontreehaving no value-grouped mode.Related
timeline/gantt/map/ other switcher visualizations share the #13748 shape — whitelisted inappearance.allowedVisualizationswith no binding block, renderer behavior unmeasured #14074 asks whether the switcher-whitelisted visualizations share the 视图声明 calendar 可视化但缺 calendar 配置块时,平台不报错——直接渲染成一屏错位画面(全部记录堆在今天) #13748 shape. This is the authored-typehalf of the same root cause; I have posted the renderer measurements there.