fix(release): state what the echo helper does, and drop two dead claims

Three corrections from review, none of which change behaviour.

attemptStreaming promised output "as the command produces it", which
spawnSync cannot do: it returns only after the child exits, and the two
streams are echoed one after the other, so their interleaving is lost.
For an npm publish that is visible — notices go to stderr while the
`+ name@version` confirmation goes to stdout, so the confirmation prints
first. The helper is now attemptEchoed and its contract says buffered,
echoed after exit, stdout before stderr; live progress would need an
asynchronous spawn with data listeners.

The traversal comment claimed a node on the stack is a cycle only peer
edges can form, and that skipping it drops just that edge. The cycle does
carry a peer edge, because the install edges were proved acyclic a moment
earlier, but the back edge that reaches the stacked node need not be the
peer one — which is what the post-condition exists to catch, so the
comment now points at it instead of asserting an invariant the traversal
does not have.

The `if (placed.has(member.name)) return` after leaving the stack was
unreachable: a re-entrant visit returns at the top guard while the member
is on the stack, so it can never be placed by the time the recursion
unwinds.
This commit is contained in:
imccyu
2026-08-14 15:14:16 +08:00
parent 7b973e27c8
commit 0e50fa290c
3 changed files with 20 additions and 10 deletions

View File

@@ -180,8 +180,11 @@ export abstract class ReleaseFamily {
}
for (const member of byNameSorted) checkInstall(member, [])
// Emit the order over both kinds of edge. A node already on the stack is a
// cycle only peer edges can form, and skipping it drops just that edge.
// Emit the order over both kinds of edge. A node already on the stack closes
// a cycle, and that cycle carries at least one peer edge because the install
// edges were just proved acyclic — but the back edge that reaches the stacked
// node is not necessarily the peer one, so the post-condition below decides
// whether the emitted order survived.
const ordered: ReleaseMember[] = []
const droppedPeerEdges: DroppedPeerEdge[] = []
const placed = new Set<string>()
@@ -216,7 +219,6 @@ export abstract class ReleaseFamily {
visit(peer)
}
onStack.delete(member.name)
if (placed.has(member.name)) return
placed.add(member.name)
ordered.push(member)
}