Editor E4 park: review-verdict fixes, sweep-lead verification, gen2 policy default - #3601
Conversation
… self-owns a default registry The hardwired pre-E2 keymap had zero in-tree callers and had diverged from the registry bindings. text_source_edit without a registry now lazily registers the default keymap into a private CommandRegistry, so both overloads route through the one imgui_commands keymap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
examples/text/tests ran in no CI lane or gate; test_viewer.das becomes tests/test_text_viewer.das and rides nightly_imgui + preflight --only imgui. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
WORKTREE_TIER_UNKNOWN between warn and green: an unresolved base ref (no origin/master|main, rev-list failure, unparsable PTY output) used to fall through to the green delete verdict with a check-marked 'count unknown' row. Now the tier, the retire-dialog help glyph, the row tooltip, and the session-retire reason all say unknown honestly; delete stays advisory like warn. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
The two code-block rails walked the document's node list and indexed the view's node cache with it. The cache is sized on the first render, so a document in plain-text mode -- or one reparsed larger than the retained cache -- panicked with "array index out of range" instead of answering. markdown_view_code_blocks() owns the walk now and reports an undrawn block with laid_out = false and zero geometry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
…d one New extern _tree_sitter_highlight_and_structure parses once and feeds both the capture flattener and the multi-line structure walk (collectHighlights grew a keep_tree handoff; the walk and the token emitter are shared helpers). tree_sitter_source_document uses it whenever the language profile folds; the standalone syntax_structure/tree_sitter_collect_folds entry points stay for the markdown-lexical path and external callers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
The shared confirmation modal re-derived its terminate target from the live selection and only fired when it still matched the captured one. The network re-points that selection on its own -- every launch and relaunch attaches the new session, and a pruned session hands it to the first running one -- so a confirmation the user read and accepted silently terminated nothing. The captured worktree_delete repository was worse: the slot was read at confirm time and written nowhere, so wiring that kind up would have sent a delete with a blank repository for the watcher to aim. destructive_confirm.das owns the decision now: everything comes from the capture, and a confirmation that cannot name its target sends nothing. terminate_session() replaces terminate_selected(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
Iterating type<ImGuiKey> hands GetKeyName three values that are not keys: NamedKey_END (667), NamedKey_COUNT (155) and ImGuiMod_Mask_ (61440). Release ImGui answers "Unknown" and the lookup already rejects that, so no sentinel was ever passed on -- but IM_ASSERT(IsNamedKeyOrMod) fires on all three in an assert-enabled build, aborting on the unsupported-key path. imgui_key_is_nameable() gates the walk by value. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
gen2 has been the CLI default for a long time, but every embedder or das-side tool constructing a fresh CodeOfPolicies still parsed options-less buffers as gen1 (the editor's das provider shipped with exactly that bug). The struct default now matches the language default; per-file 'options gen2 = false' still opts out both ways (probe-proven), and tests-cpp-small passes 78/78 under the flip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
`var block = ...` is error[30151], which reads as nothing in particular until you know the lexer claims the word. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
The eight event-gated playwright scenarios and the JV state snapshot are suppressed by design, not by omission - say why on each line. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
Stripping every STYLE037/038 suppression in the E4 editor files showed that twelve of the sixteen no longer tripped anything - the code had shrunk under the caps since they were added. Those are gone. The four that still fire are a keymap registration table, a command-id ladder, an order-sensitive capture-prefix ladder, and a one-pass lexer; each now names why splitting it would cost more than it buys. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
There was a problem hiding this comment.
Pull request overview
This PR follows up on #3596 by landing a set of targeted fixes and verifications in the dasHerd watcher + dasImgui text stack, including safer destructive confirmations, a new “unknown” worktree delete tier for unmeasured unmerged counts, a single-parse Tree-sitter path for highlight+structure, and flipping the default CodeOfPolicies.version_2_syntax to gen2.
Changes:
- Introduce
WORKTREE_TIER_UNKNOWNand propagate it through watcher UI/messaging/tests so “unmerged count unknown” never reads as “safe/green”. - Replace ad-hoc destructive-confirm globals with a small
destructive_confirmmodel + tests; update termination to always target an explicit session id. - Add
_tree_sitter_highlight_and_structure(C++ + AOT header + das wrapper) and use it to avoid double-parsing when folds are needed.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| utils/dasHerd/watcher/tests/test_repository_core.das | Extends coverage for the new unknown delete tier and adds failure-explanation tests. |
| utils/dasHerd/watcher/tests/test_destructive_confirm.das | New tests ensuring confirm actions remain bound to captured identity and reject repo-less deletes. |
| utils/dasHerd/watcher/rich_sessions_ui.das | Integrates shared destructive-confirm model and adds unknown-tier retire reason messaging. |
| utils/dasHerd/watcher/rich_net.das | Changes termination API to target a specific session id (not “selected”). |
| utils/dasHerd/watcher/rich_live.das | Updates live-command tier docs and switches markdown code-block inspection to the new safe enumerator. |
| utils/dasHerd/watcher/rich_git_ui.das | Updates retire hint text to reflect the new unknown tier semantics. |
| utils/dasHerd/watcher/rich_client.das | Adds “help” glyph row support and surfaces the unknown tier as a third checklist state. |
| utils/dasHerd/watcher/repository_core.das | Defines WORKTREE_TIER_UNKNOWN and ensures unmeasured counts do not map to green. |
| utils/dasHerd/watcher/destructive_confirm.das | New pure-logic module that captures destructive-confirm intent and derives a safe dispatch action. |
| modules/dasTreeSitter/src/dasTreeSitter.cpp | Adds a combined highlight+structure extern, refactors structure walk, and supports tree reuse. |
| modules/dasTreeSitter/src/aot_builtin_tree_sitter.h | Declares the new combined extern for AOT builds. |
| modules/dasTreeSitter/daslib/tree_sitter.das | Adds syntax_highlight_and_structure wrapper for one-parse token+span collection. |
| modules/dasImgui/widgets/imgui_live_core.das | Adds imgui_key_is_nameable and uses it to avoid asserting ImGui key markers. |
| modules/dasImgui/text/imgui_text_tree_sitter.das | Refactors fold extraction and introduces the “wants_folds” single-parse path. |
| modules/dasImgui/text/imgui_text_source_edit.das | Removes dead hardwired key routing and makes the no-registry overload use a private registry. |
| modules/dasImgui/text/imgui_text_edit_syntax.das | Removes stale nolint from a small helper. |
| modules/dasImgui/text/imgui_text_edit_provider_das.das | Updates comment to reflect gen2 flip motivation (still explicitly sets gen2 for compatibility). |
| modules/dasImgui/text/imgui_text_edit_provider_cpp.das | Removes stale nolint from clang output parsing entry point. |
| modules/dasImgui/tests/test_text_viewer.das | Updates nolint annotations to include rationale for long scenario tests. |
| modules/dasImgui/tests/test_markdown_view_code_blocks.das | New regression tests for code-block enumeration when view cache is empty/short. |
| modules/dasImgui/tests/test_imgui_key_nameable.das | New tests asserting marker keys are excluded from GetKeyName probing. |
| modules/dasImgui/markdown/imgui_markdown_view.das | Adds markdown_view_code_blocks API that safely reports code blocks even before first layout. |
| modules/dasImgui/examples/features/text_edit.das | Removes stale nolint on the example update loop. |
| modules/dasImgui/CLAUDE.md | Updates the approximate test-file count in docs. |
| include/daScript/ast/ast.h | Flips CodeOfPolicies.version_2_syntax default to true and documents the opt-out. |
| examples/text/main.das | Switches code-block inspection to markdown_view_code_blocks and updates nolint rationale. |
| CLAUDE.md | Adds/records a lexer-reserved-words note (type-token identifiers). |
| .github/workflows/nightly_imgui.yml | Updates comment test-file count estimate in workflow header. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
test_compile_sample compiles its embedded sample under a DEFAULT CodeOfPolicies, so the gen1 sample stopped parsing when version_2_syntax flipped to true. The sample is now gen2, making the test the in-tree witness of the flipped default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 29 out of 29 changed files in this pull request and generated no new comments.
Suppressed comments (2)
modules/dasImgui/markdown/imgui_markdown_view.das:543
markdown_view_code_blockstreats a node aslaid_outpurely based onindex < length(state.nodes). Afterprepare_view_state()callsmarkdown_view_invalidate(),state.nodescan already be sized to the document while every entry hasscreen_revision = -1(never rendered yet). In that case this function incorrectly reportslaid_out = truefor undrawn blocks, which reintroduces the same class of inspection OOB/incorrect telemetry the helper is meant to avoid.
for (index in range(length(doc.nodes))) {
continue if (doc.nodes[index].kind != RichNodeKind.code_block)
var code = MarkdownViewCodeBlock(node = index,
collapsed = markdown_view_code_collapsed(state, index))
if (index < length(state.nodes)) {
modules/dasImgui/tests/test_markdown_view_code_blocks.das:62
test_markdown_code_blocks_report_layoutmanually populatesscreen_origin/icon rects but leavesentry.screen_revisionat its default (-1). In real rendering paths,screen_revisionis set when a node is actually placed, so the test should set it too to represent a laid-out cache entry (and to stay correct iflaid_outis keyed offscreen_revision).
var entry & = unsafe(state.nodes[node])
entry.icon_rects_valid = true
entry.screen_origin = float2(12.0f, 34.0f)
entry.fold_icon_rect = float4(10.0f, 20.0f, 30.0f, 40.0f)
entry.copy_icon_rect = float4(50.0f, 60.0f, 70.0f, 80.0f)
The subtool compiles its require-stub under a fresh CodeOfPolicies - the second consumer the version_2_syntax flip exposed (10 darwin extended_checks failures). Self-marking with options gen2 keeps it correct under any default. write_module_api's section ladder carries its reason. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
imgui_key_is_nameable(key : ImGuiKey) was the first documented signature naming a raw-binding type; das2rst emitted a :ref: to the nonexistent label enum-imgui-imguikey and sphinx -W died on it. mark_module_pageless declares a binding has no generated pages; handle/struct/enum mentions from it render as plain text. imgui2rst registers 'imgui'. Legacy describe_type-family offenders dragged into the changed set carry reasons. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
MSVC path::string() throws system_error on filenames outside the ANSI codepage, killing the whole process mid-walk (crashed the mcp test run locally). Treat an unconvertible name like an ec entry and skip it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 35 out of 35 changed files in this pull request and generated no new comments.
Suppressed comments (3)
modules/dasImgui/tests/test_markdown_view_code_blocks.das:58
- After initializing the node cache without a real render, the cache entries need to be explicitly constructed (avoid
unsafe resize). Also, ifMarkdownViewCodeBlock.laid_outis based onscreen_revision, the test should setentry.screen_revisionto a non-negative value when faking layout telemetry.
var state = MarkdownViewState()
unsafe(state.nodes |> resize(length(doc.nodes)))
let node = code_block_nodes(doc)[0]
var entry & = unsafe(state.nodes[node])
modules/dasImgui/markdown/imgui_markdown_view.das:536
MarkdownViewCodeBlock.laid_outis set totruewheneverindex < length(state.nodes), butstate.nodescan be pre-sized/retained (e.g. aftermarkdown_view_invalidate) before any render pass sets geometry. This contradicts the docstring (“False until the view has laid this node out”) and can mis-report undrawn blocks as laid out.
if (index < length(state.nodes)) {
let entry & = unsafe(state.nodes[index])
code.laid_out = true
code.icons_valid = entry.icon_rects_valid
code.screen_origin = entry.screen_origin
modules/dasImgui/tests/test_markdown_view_code_blocks.das:41
- This test uses
unsafe(state.nodes |> resize(2)), which leavesMarkdownNodeViewCacheelements uninitialized. Sincemarkdown_view_code_blocksmay read cache fields for nodes within the resized range, this can make the test nondeterministic (and can mask real issues). Prefer constructing initialized cache entries.
This issue also appears on line 55 of the same file.
var state = MarkdownViewState()
unsafe(state.nodes |> resize(2))
let expected <- code_block_nodes(doc)
Follow-up to #3596: executes Boris's verdicts on the landing review's deferred questions and parks E4 for good.
Review-question verdicts executed
20ae2dce6) —examples/text/tests/test_viewer.dasran in no CI lane; nowmodules/dasImgui/tests/test_text_viewer.daspermodules/dasImgui/CODEREVIEW.md, riding nightly_imgui +preflight --only imgui.4ce3d70ca) —route_editor_keys(the pre-registry "interim hardwired keymap", zero callers, drifted bindings) and itsnav_pressedhelper are gone. The no-registrytext_source_editoverload now lazily owns a private default-keymap registry, so both overloads route through the one imgui_commands keymap.022fdb234) — new_tree_sitter_highlight_and_structureextern parses once and feeds both the highlight flattener and the multi-line structure walk;tree_sitter_source_documentuses it whenever the language profile folds. The standalonesyntax_structure/tree_sitter_collect_foldsentry points stay for the markdown-lexical path and external callers.5e5e68f77) — an unmeasured unmerged count (no origin/master|main, rev-list failure, unparsable PTY output) used to fall through to the green delete verdict with a check-marked "count unknown" row. NewWORKTREE_TIER_UNKNOWNbetween warn and green: help-glyph checklist row, honest tooltip and session-retire reason; delete stays advisory like warn.CodeOfPolicies.version_2_syntaxdefaults totrue(8bef48c7e) — gen2 has long been the CLI default, but every embedder or das tool constructing a fresh cop still parsed options-less buffers as gen1 (the editor's das provider shipped with exactly that bug). Per-fileoptions gen2 = falsestill opts out both ways (probe-proven);tests-cpp-smallpasses 78/78 (1,103,732 assertions) under the flip.Sweep-lead verification (adversarial, fixes test-first)
026f9cf1b): the rail indexed the view's layout cache with document-node indices, but that cache is empty until the first render — a plain-text-mode file containing a fence panicked (array index out of range, 3 of 0, reproduced).markdown_view_code_blocksnow owns the walk and reports undrawn blocks aslaid_out = false; the same unguarded pattern inrich_live.dasfixed too. Newtest_markdown_view_code_blocks(3), watched red first.2dc2d5caf): the retire-dialog lead was refuted as located (identity held by path, not index), but the shared destructive-confirm modal re-derived its terminate target from the live selection, which the network re-points on its own (launch, herd-create, pruned-session auto-attach) — a confirm could silently act on nothing. Newdestructive_confirm.dasmodel derives the action from the captured identity and refuses a repository-less delete. Newtest_destructive_confirm(5), watched red first.IM_ASSERT(IsNamedKeyOrMod)on ImGuiKey's range markers in assert-enabled builds (9b0fb8c9f) —imgui_key_is_nameable()now gates by value. Newtest_imgui_key_nameable(3).Nolint hygiene (STYLE037/038 on new code)
Stripping all suppressions and re-linting showed 12 of 16 were stale — the code had already shrunk under the caps; they are simply removed (
c1fa17f4e). The 4 that still fire carry measured reasons in the— whyformat (keymap registration table, command-verb ladder, ordered capture-prefix ladder, one-pass lexer). The 8test_text_viewerscenarios and the viewer state snapshot carry theirs too (123a8ea8d).Gates
already_formatted🤖 Generated with Claude Code
https://claude.ai/code/session_01Kv2yQu558ryra5WS1AFASZ