So I'm answering to myself. ;-)
Such "flat" polygon collision shape generate error's message in the debugger. But the collision was working as it seems.
But I finally needed a more fine grained control over the collision of this shape (The tail). So I redesigned the tail as follow:

The tail is basically a Line2D with an empty StaticBoby2D
The collision shape is a now a list of Segment2D managed by the following code. To avoid collision with the player, I added some code to reduce the size of the last two segment. Because I still use collision detection with the player as we are not allowed cross the tail.
The code is not yet optimized, and update all segment each time, but in the gameplay only the last two only need to be updated.
func update_collision_shape():
var n = points.size()
if n < 2:
# waiting for a 2nd point to create a segment
return
# replace all segments (for now, TODO: optimize the update)
segments.clear()
for i in range(n-1):
segments.append(create_segment(points[i], points[i+1]))
reduce_last_segment()
# re-add all segments: delete old childs and recreate all
clear_all_shape(true)
for s in segments:
$col.add_child(s)
And the helpers functions (a lot of variables are exposed for debugger easy access):
func clear_all_shape(keep_segments = false):
for c in $col.get_children():
c.queue_free()
if not keep_segments:
segments.clear()
func create_segment(p1 : Vector2, p2 : Vector2, shorten : int = 0) -> CollisionShape2D:
var collision = CollisionShape2D.new()
collision.shape = SegmentShape2D.new()
collision.shape.a = p1
collision.shape.b = p2
if shorten > 0:
reduce_segment(collision, shorten)
return collision
func reduce_segment(seg : CollisionShape2D, shorten : int):
var v = (seg.shape.b - seg.shape.a).normalized()
# we calculated the length of the segment, reducing at max of its length
var d = seg.shape.a.distance_to(seg.shape.b)
var delta = min(d, shorten)
var b = seg.shape.b
b -= v * delta
seg.shape.b = b
func reduce_last_segment(shorten : int = -1) -> int:
if points.size() < 2 or segments.size() == 0:
return 0
if shorten < 0:
# default value
shorten = last_segment_reduction
# r count the number of segment modified
var r = 0
# last point is the player, to avoid collision we shorten
# this last segment, or even the previous one on corner
var d = points[-2].distance_to(points[-1])
if d < shorten:
# skip last segment too short
segments.pop_back()
r += 1
# we also reduce previous segment, as are still to near
if segments.size() > 0:
reduce_segment(segments[-1], shorten - d)
r += 1
else:
# we shorten the last segment only
reduce_segment(segments[-1], shorten)
r += 1
return r
And the runtime the node tree result is as follow:

And it looks like:

So now the player can collide with the tail and is stopped. The player's collision in the same layer as the tail is the small 5 px circle shape. Collision between player and tail are disabled while rewinding on the tail.
I will evolve as I discover more on Godot and as I need to handle more use case.
Suggestions are welcome. :-)
Regards,
Sylvain.