Repository navigation
feat(*): let a dag decision node choose which of its branches run - #1001
Conversation
gloryfromca
left a comment
There was a problem hiding this comment.
Blocking: valid double-negated done guards are rejected as impossible.
I found one inline correctness issue. I covered the repository rules and canonical DAG terminology, the full diff, the parser/validator/scheduler/judge/storage path, RPC and both UI callers, playbook compilation, the single-commit history, backward compatibility for non-branching DAGs and retired config migration, and test changes; I did not find weakened tests or an architecture-boundary violation.
Verification: uv run pytest tests/test_subagent_dag_guard.py tests/test_subagent_dag_core.py tests/test_subagent_dag_runner.py tests/test_subagent_dag_verdict.py tests/test_subagent_dag_control_tools.py tests/test_rpc_dag.py tests/test_rpc_tasks.py tests/test_rpc_schema_match.py tests/test_playbook_executor.py tests/test_playbook_validate.py tests/test_unified_playbook.py -q (1681 passed); changed TUI suites (341 passed); changed web suites (471 passed).
|
Windows compatibility review: inspected the full 94-file diff and relevant callers at head
Verification: 343 selected added Python cases passed, plus 158 guard/verdict cases and 5 branch-config cases. The external native-filesystem probe passed 16 assertions (including six confirmations of finding 1); its six unconditional controls also passed at base. Changed TUI suites: 372 passed; changed Web suites: 704 passed. Both Limitations: the wider Python run stopped after 238 passes / 2 skips at Frontend verification commandsFrom the respective isolated head archive's # Setup, both projects: successful; lifecycle scripts disabled during installation.
npm ci --ignore-scripts --no-audit --no-fund
# TUI: 372 passed. npm's pretest also built the local Hermes Ink package.
npm test -- src/__tests__/agentsOverlay.test.tsx src/__tests__/dagCommand.test.ts src/__tests__/dagNodePoll.test.tsx src/__tests__/dagPanel.test.tsx src/__tests__/dagRun.test.ts src/__tests__/dagStatus.test.ts src/__tests__/liveAgentsStore.test.ts src/__tests__/liveAgentsStrip.test.ts --maxWorkers=2 --reporter=json --outputFile 'C:/Users/livxu/AppData/Local/Temp/raven-windows-review/fc077797d3174e3b89f5749c21a12dcd/checks/1001-tui/vitest.json'
# Web: 704 passed.
npm test -- src/features/dag/nodes.test.ts src/features/desk/DeskPalette.test.tsx src/features/desk/DeskSurface.test.tsx src/features/desk/store.test.ts src/features/tasks/BoardCard.test.tsx src/features/tasks/NodeRecord.test.tsx src/features/tasks/TasksPage.test.tsx src/features/tasks/live.test.ts src/features/tasks/source.test.ts src/features/tasks/store.test.ts src/features/transcript/TranscriptPage.test.tsx src/features/transcript/store.test.ts --maxWorkers=2 --reporter=json --outputFile 'C:/Users/livxu/AppData/Local/Temp/raven-windows-review/fc077797d3174e3b89f5749c21a12dcd/checks/1001-web/vitest.json'
# Both projects: exit 0.
npm run type-checkPython used 3.13.12, an isolated environment prepared with Exact verification commands# pure: 238 passed, 1 failed, 0 errors, 2 skipped; exit 1
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\pr1001\source\head
uv run pytest tests/test_subagent_dag_guard.py tests/test_subagent_dag_verdict.py tests/test_config_loader.py tests/test_config_raven_sections.py -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-pure\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-pure\junit.xml'
# base-config: 0 passed, 1 failed, 0 errors, 0 skipped; exit 1
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\pr1001\source\base
uv run pytest 'tests/test_config_loader.py::test_a_row_pinning_a_gone_raven_interpreter_follows_this_install' -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-base-config\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-base-config\junit.xml'
# config-branch: 5 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\pr1001\source\head
uv run pytest tests/test_config_loader.py tests/test_config_raven_sections.py -k 'verdict or subagent_dag' -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-config-branch\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-config-branch\junit.xml'
# added: 308 passed, 1 failed, 0 errors, 0 skipped; exit 1
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\pr1001\source\head
uv run pytest tests/test_playbook_executor.py tests/test_playbook_validate.py tests/test_rpc_dag.py tests/test_rpc_instances.py tests/test_rpc_playbooks.py tests/test_rpc_schema_match.py tests/test_rpc_spine.py tests/test_rpc_subagent_calls.py tests/test_rpc_tasks.py tests/test_subagent_dag_control_tools.py tests/test_subagent_dag_core.py tests/test_subagent_dag_runner.py tests/test_subagent_third_party.py tests/test_unified_playbook.py -p review_changed_tests -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-added\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-added\junit.xml'
# added-rest: 343 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\pr1001\source\head
uv run pytest tests/test_playbook_executor.py tests/test_playbook_validate.py tests/test_rpc_dag.py tests/test_rpc_instances.py tests/test_rpc_playbooks.py tests/test_rpc_schema_match.py tests/test_rpc_spine.py tests/test_rpc_subagent_calls.py tests/test_rpc_tasks.py tests/test_subagent_dag_control_tools.py tests/test_subagent_dag_core.py tests/test_subagent_dag_runner.py tests/test_subagent_third_party.py tests/test_unified_playbook.py -p review_changed_tests -k 'not test_the_finish_text and not test_branch_e2e_one_tool_call' -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-added-rest\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-added-rest\junit.xml'
# finish-cat: 0 passed, 1 failed, 0 errors, 0 skipped; exit 1
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\pr1001\source\head
uv run pytest 'tests/test_subagent_dag_runner.py::test_the_finish_text_counts_and_explains_the_branches_that_were_not_taken' -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-finish-cat\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-finish-cat\junit.xml'
# alias-final: 16 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\pr1001\source\head
uv run pytest 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\test_windows_branch_alias.py' -s --asyncio-mode=auto -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-alias-final\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-alias-final\junit.xml'
# base-alias: 6 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:/Users/livxu/AppData/Local/Temp/raven-windows-review/fc077797d3174e3b89f5749c21a12dcd/pr1001/source/base
uv run pytest 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\test_windows_branch_alias.py' -k unconditional_alias_control -s --asyncio-mode=auto -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-base-alias\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fc077797d3174e3b89f5749c21a12dcd\checks\1001-base-alias\junit.xml' |
|
Addressed both findings in the Windows review:
Native Windows build 26300 / Python 3.13.12: the initial selection reproduced 15 failures / 9 passes; the final focused selection passes 34 tests (669 deselected, no skips), and 16 external native cases pass. The broader Windows selection has 1686 passes and 16 failures; every remaining failing ID also fails on the unmodified original PR head. The final Linux selection passes 1702 tests with no skips. Removing any of the three normalization/mapping components makes the regression fail; source was restored byte-identically and the focused tests passed again. Full-PR diff coverage is 97.55% (716/734). Lint/type/import/commit/source/asset checks pass; the dependency gate passes in Linux with the declared channel extras installed. The PR description records exact commands and the native baseline limitations. The separate double-negated guard finding remains open; I did not resolve any review thread. New-head CI is pending and will be checked separately. |
gloryfromca
left a comment
There was a problem hiding this comment.
Blocking: the existing double-negation guard rejection remains reproducible on this head.
I reviewed the two-commit delta from 213d68eecd19 and found no new blocker in the Windows path normalization, platform-native finish-text expectations, or CI coverage. The open finding at dag_guard.py remains unchanged: the same not not decide.done graph still fails validation on this revision, so that thread continues to block.
Coverage for this revision included the delta, its local-file/path callers, the existing guard validation path, commit history, backward compatibility on non-Windows hosts, test changes, and the repository rules/architecture already covered in my first full review. I found no weakened tests. Verification: uv run pytest tests/test_subagent_dag_guard.py tests/test_subagent_dag_core.py tests/test_subagent_dag_runner.py -q (766 passed), plus the direct double-negation reproduction (still rejected).
|
Windows compatibility re-review at head [P2] A same-drive relative alias still bypasses the conditional-artifact check (reproduced on Windows). At dag_graph.py:1022, Native reproduction: Verification on native Windows / Python 3.13.12:
The separate double-negated guard finding remains in the existing discussion and is not duplicated here. Setup: isolated exact-SHA archives and uv environment via Exact verification commands# focused: 34 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\pr1001\source\head
uv run pytest tests/test_subagent_dag_core.py tests/test_subagent_dag_runner.py -k 'at_nodes or file_input_aimed or test_the_finish_text or test_branch_e2e_one_tool_call' -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\checks\1001-focused\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\checks\1001-focused\junit.xml'
# alias-original: 3 passed, 1 failed, 0 errors, 0 skipped; exit 1
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\pr1001\source\head
uv run pytest -c pyproject.toml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\test_windows_branch_alias_original.py' -s -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\checks\1001-alias-original\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\checks\1001-alias-original\junit.xml'
# alias-current: 22 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\pr1001\source\head
uv run pytest -c pyproject.toml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\test_windows_branch_alias_current.py' -s -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\checks\1001-alias-current\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\checks\1001-alias-current\junit.xml'
# base-alias: 9 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\pr1001\source\base
uv run pytest -c pyproject.toml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\test_windows_branch_alias_current.py' -k unconditional -s -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\checks\1001-base-alias\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\d600058f8f1348f7b0ccc38bebd9753b\checks\1001-base-alias\junit.xml' |
|
Addressed the same-drive relative alias finding in Native Native Windows build 26300 / Python 3.13.12: the new filesystem matrix reproduced 9 failures / 21 passes before the fix. Three external runner probes independently reproduced the accepted reference followed by Linux Python 3.12.12: 1711 related tests pass with no skips/errors. Full-PR diff coverage is 97.55% (717/735). Lint/type/import/dependency, full-PR pre-commit and commit/source/asset checks pass. The PR description records exact commands and keeps the earlier broad native failures separate; that broad native selection was not rerun for this follow-up. The generic double-negation finding remains open, and no review thread was resolved. New-head CI will be checked separately. |
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; suggestions only, and they are marked inline.
I reviewed the 0313297466ee delta and found no concrete regression in the drive-relative conditional-artifact handling or its tests. The existing double-negation validation issue remains a worthwhile follow-up, but at this fifth round it does not meet the blocker bar: it is introduced here, yet is low-reachability and has the direct workaround not not X -> X. I withdrew that objection and resolved my thread.
Coverage included the new diff and commit history, local path resolution/validation callers, Windows versus POSIX behavior, backward compatibility, test changes, and the repository rules and architecture covered in the original full review. No weakened tests found. Verification: uv run pytest tests/test_subagent_dag_core.py -q (363 passed).
|
Windows compatibility re-review at head The reported same-drive relative alias failure is fixed in the tested native scenarios; no additional Windows compatibility issue found in the inspected scope. Re-running the previous reproduction now rejects Native Windows / Python 3.13.12: 43 repository path/finish-text tests passed, 669 deselected, and 22 external native controls passed under a space/non-ASCII path. All four foreground/finish-text cases passed with the existing Git The generic double-negation limitation remains documented in the existing follow-up; its reviewer closed the thread, and this Windows review does not refile it. Setup: isolated exact-SHA archive and uv environment via Exact verification commands# focused: 43 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\pr1001\source\head
uv run pytest tests/test_subagent_dag_core.py tests/test_subagent_dag_runner.py -k 'at_nodes or file_input_aimed or test_the_finish_text or test_branch_e2e_one_tool_call' -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\checks\1001-focused\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\checks\1001-focused\junit.xml'
# alias-previous: 16 passed, 1 failed, 0 errors, 0 skipped; exit 1
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\pr1001\source\head
uv run pytest -c pyproject.toml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\test_windows_branch_alias_previous.py' -s -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\checks\1001-alias-previous\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\checks\1001-alias-previous\junit.xml'
# alias-fixed: 22 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\pr1001\source\head
uv run pytest -c pyproject.toml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\test_windows_branch_alias_fixed.py' -s -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\checks\1001-alias-fixed\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\7ec6ce43ce1a4efe9b15878b7d4000d6\checks\1001-alias-fixed\junit.xml' |
0313297 to
7340bef
Compare
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
Re-reviewed the rebased revision against current github/main and inspected the complete new delta, callers, history, compatibility, tests, and architecture contracts. The reserved-node identity change now matches conditional artifact paths with the session's case-folding rule, and the Boolean-context walker fixes the previously named double-negation follow-up while preserving valid or arms. I found no new plain error or blocker.
Verification: uv run pytest tests/test_subagent_dag_guard.py tests/test_subagent_dag_core.py -q passed (463 tests); a generated check of 927 depth-bounded Boolean guards found zero satisfiable expressions falsely rejected; git diff --check github/main...HEAD passed; exact-head TUI CI passed. The full Python CI matrix was still pending when reviewed. Tests were strengthened rather than weakened.
Covered the applicable AGENTS.md, CLAUDE.md, CONTEXT-MAP.md/CONTEXT.md rules, the PR diff and rebase range-diff, production callers, backward compatibility, and the DAG validation/runtime boundary. Patch-risk assessment: merge, human review required because this changes an authored public DAG contract; impact moderate, regression likelihood low, protection strong, recovery easy, confidence high. The assessment JSON validated against the patch-risk schema.
|
Completed the pending native Windows verification for Windows build 26300 / Python 3.13.12, isolated profile/OAuth/temp state:
All three selections had zero failures, errors or skips. Source imports were verified outside the checkout with PYTHONPATH cleared; Git cat was exposed to the test environment for the existing fixture. The earlier 16-failure broad native selection was not rerun. No new full-repository, frontend/browser, live-model, macOS, UNC-share, ACL or symlink validation is claimed. Current-head CI was observed at 21 passing checks and 2 intentional skips. |
|
No additional Windows compatibility issue found in the inspected scope. Reviewed head Code inspection: conditional artifact lookup now uses the same folded node identity as namespace reservation while retaining native separator/drive normalization and canonical-ID advice. The Boolean walker preserves negation and disjunction context. Traced both checks into graph validation, the existing resolver/renderer and runner guard evaluation. Fresh native Windows verification, Python 3.13.12. This separately isolated rerun corroborates the native verification report:
The previous double-negation follow-up is corrected in these tested scenarios. Setup: Limits: one guard case emitted an advisory idle-ceiling warning; strict idle mode was not enabled. No new full-suite, frontend/browser, live-model, Linux/macOS, absolute-path, UNC-share, ACL or symlink verification was performed. Exact verification commands# focused: 72 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\pr1001\source\head
uv run pytest tests/test_subagent_dag_core.py tests/test_subagent_dag_runner.py -k 'at_nodes or file_input_aimed or test_the_finish_text or test_branch_e2e_one_tool_call or satisfiable_guards_survive or impossible_guards_are_still_rejected' -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\checks\1001-focused\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\checks\1001-focused\junit.xml'
# guards: 71 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\pr1001\source\head
uv run pytest tests/test_subagent_dag_guard.py -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\checks\1001-guards\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\checks\1001-guards\junit.xml'
# native: 26 passed, 0 failed, 0 errors, 0 skipped; exit 0
# Working directory: C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\pr1001\source\head
uv run pytest -c pyproject.toml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\test_windows_branch_alias_fixed.py' 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\test_windows_branch_guard.py' -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\checks\1001-native\pytest' --junitxml 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\ab5372c6053347c693aeec4e4b0449c9\checks\1001-native\junit.xml' |
7340bef to
18aa692
Compare
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
Re-reviewed the rebased revision against current github/main. Range-diff confirms the seven previously reviewed commits are unchanged in substance; I inspected all seven new commits and their production callers. The config cleanup, UTF-8-safe route evidence, physical node-root path validation, CLI playbook judging, documentation corrections, and not-executed card layout fix are consistent with the existing contracts. I found no new plain error or blocker.
Verification: the focused Python suites for config, verdicts, registry persistence, DAG validation/execution, and CLI playbooks passed (1,021 tests). The targeted web card suite passed (28 tests). git diff --check passed. Exact-head page, TUI, Windows ACP, trajectory, lint, docs, bridge, repository, and packaging CI checks passed; the sharded Python and UI RPC jobs were still pending when reviewed. Tests were strengthened rather than weakened.
Covered the applicable AGENTS.md, CLAUDE.md, CONTEXT-MAP.md/CONTEXT.md rules, the full PR comparison and rebase history, changed callers and callees, backward compatibility, persistence/config behavior, filesystem alias boundaries, and CLI/runtime architecture. Patch-risk assessment: merge, human review required because the change affects public DAG/config behavior and persisted registry data; impact moderate, regression likelihood low, protection strong, recovery easy, confidence high. The assessment JSON validated against the patch-risk schema.
A node that declares routes is a decision node: Raven's per-node judge, the existing verdict call, picks the route or routes the node's answer satisfies, and a downstream node guarded with `when` runs only on its route. Guards combine `<node>.<route>` and `<node>.done` atoms with not, and, or, using three-valued logic. A node left out is not_executed with a reason, and a merge node reads a missing upstream as a fixed sentence written outside every untrusted fence. Graphs with no routes and no `when` behave as before. The subagentDag.verdictEnabled switch is retired by config migration 14.
Use native path and case normalization before matching a file reference to a conditional node, and retain the declared node ID in rejection advice. Verify the aliases against LocalFileBackend and actual filesystem reads.
Build expected artifact paths with Path joins in all four new foreground finish-text cases. Run the alias and finish-text regressions in Windows CI, making the installed Git cat executable available to the existing fixture.
Match the relative suffix of a native drive-qualified path before looking up a conditional node. Preserve the declared ID and missing-output advice. Extend the real-filesystem matrix across all three reference entry points, including drive prefixes combined with case and separator aliases.
Match conditional artifact references using the session node identity on every host. Preserve native path normalization, canonical node advice and unconditional file reads.
Carry negation parity through conjunctions and reject a disjunction only when every arm is impossible. Preserve three-valued runtime evaluation and bounded validation without distributing route combinations.
…loor has run Floor 14 stripped subagentDag.verdictEnabled only from a config stamped below it. The build before this one reads a stamp of 14 as current, keeps it and accepts the key, so a rollback, or a second install sharing the home, could write the key back, and the next load of this build then refused the whole config in load_raven_config. The strip now holds on every load, as the retired sessionTitle and sentinel keys already do; the notice is still given once, when the floor runs.
…egistry An unpaired escape in the judge's JSON decodes to a lone surrogate. The route quote kept it, the instance registry failed to encode it on flush, and since the cache already held the row, every later registry write in the process failed the same way, for every session, until a restart. The run's manifest could not be written either. The quote now keeps such a character as the escape it was written with, before the 500-character cut. The registry also drops its cache when a flush fails on the data rather than the disk, so a row the file cannot hold fails its own write and no other.
… may not run Rule 8 read only the @nodes/ spelling. The history root around the node root is a reference root of its own, so an absolute path, as a finish text prints it, or a path out of the workdir reached the same artifacts and was accepted; the reader then failed at render on the missing file, and the run reported that instead of the branch that was not taken. Such a reference is now resolved the way the confinement check resolves it, through one shared helper, and held to the same rule when it lands in the node root the renderer reads. The tool, the runner and the replan path pass that root to validation.
raven playbook run built its graph tool with no judge, so a playbook that declares routes was refused before anything ran, while the command's own compose prompt invites a branch. The tool now judges each node as a conversation does, on the user's subagentDag settings and on a pinned verdictModel's own provider, resolved by one helper both hosts call. Nobody on the command line can answer a node that falls short, so such a node fails on its judge's reason instead of waiting.
…fely The skill said a single-select decision with no catch-all route fails the node whenever its answer fits none of the conditions. The judge is held to the declared routes, so it may instead pick the nearest one and send the graph down a branch the answer does not support. The paragraph now says both.
Retiring subagentDag.verdictEnabled changes what an upgraded build does, so its entry moves from Added to Changed, beside the other behaviour changes, and the test that pins it follows it.
The status copy floated into the title leaves its first line about 78px. A first word wider than that moved below the float, so the title started under a blank line and its second line, ellipsis included, fell outside the clamp. The not-executed title may now break a word where that room ends; every other status keeps its title as it was.
18aa692 to
e643822
Compare
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
Reviewed the rebased head against both the previously reviewed revision and the current GitHub base. Thirteen commit patches are identical; the remaining patch differs only in a CI comment updated for the Mirasim Windows job, with no executable change. I found no new defect and no weakened test.
Coverage included AGENTS.md and the routed domain context, the full github/main...HEAD diff, normalized history, relevant DAG/RPC/playbook/UI callers, backward compatibility, test integrity, and the existing architecture boundaries. The patch-risk assessment recommends merge; its human-review workflow label reflects the broad persistent-state and public-contract surface, not a blocking issue.
Verification on exact head: 63 focused DAG tests passed; the complete ui-web suite passed (4,104 tests); git diff --check passed; and GitHub's Windows ACP, all four Python unit shards, TUI, RPC-contract, lint, repository, page, bridge, wheel, installer, and trajectory jobs passed. Coverage aggregation was still pending when checked. My only review thread is already resolved.
The pin from EverMind-AI#1001 asserted the silence this branch removes -- a cascade skip on the pass that meets a replan got no event. It now expects that frame, under a name and docstring that say the exit publishes it.
#1002) ## Summary - A node the cascade skipped, or a stop cancelled, on the pass that meets a replan got no `dag_node_updated` frame and no registry row until the run finalized: that pass breaks at the replan before the sweep could take it, so a live panel kept drawing the node as running. - The replan exit now publishes `skipped` and `cancelled` alongside `not_executed`, through `_publish_terminal` -- the helper #1001 introduced for exactly this stamping. One definition covers every pass, and the end stamp is hard-assigned there: the helper's docstring sentence and the exit's comment now say so instead of naming the replan pass as announced by nobody. - The first revision of this branch put a second copy of that publish inside `_apply_replan`, stamped with `setdefault`, which kept an earlier attempt's end on a node cancelled out of a retry and wrote a duration that ran backwards (a start after its end). That copy is withdrawn in favor of the shared helper; the regression test drives the retry-cancelled-on-the-replan-pass case under a strictly increasing counter clock, so the ordering it asserts cannot race the real clock's millisecond resolution. - #1001's pin test asserted the silence this branch removes; it now expects the cascade skip's frame, under a name that says the exit publishes it. ## Type - [x] Fix ## Verification - [x] Relevant tests pass locally: `uv run pytest tests/test_subagent_dag_runner.py tests/test_subagent_dag_adjudication.py tests/test_subagent_dag_core.py tests/test_subagent_dag_control_tools.py tests/test_rpc_dag.py -q` -> 916 passed, after rebasing onto #1001 - [x] The three new tests fail on the merge base (no frames for the settled nodes, and 1020 > 1010 under the counter clock) and pass on this head - [x] Relevant lint / type checks pass locally: `ruff check` and `ruff format --check` on both files; `make lint-types` -> clean - [x] User-facing docs or screenshots are updated when needed: no user-facing surface changes; the frames carry statuses consumers already read at finalization ## Risk - [x] Security impact considered: announcement only; no value or path crosses that did not before - [x] Backward compatibility considered: a replan pass now emits one extra `dag_node_updated` frame per cascade-skipped or stop-cancelled node, which is the fix itself; the manifest's end stamps on that pass are re-assigned rather than kept, so no duration runs backwards - [x] Rollback path is clear: plain revert restores the silent exit ## Related Issues N/A (adopts `_publish_terminal` from #1001)
Summary
A sub-agent DAG node can now decide which of its downstream branches run. Before this, a background run could not turn on a result: every node ran, and choosing a path meant the host winding the run down and starting another.
How it works:
routes(route name to condition) is a decision node;selectis"one"(the default) or"many". Raven's per-node judge, the existing verdict call, picks the route or routes the node's answer satisfies. The node's own text never selects a route. A route that cannot be determined fails the node, with no fallback route.when, a guard over<node>.<route>and<node>.doneatoms joined withnot,and,orand parentheses, evaluated with three-valued logic: a route of a decision node that was never executed is unknown. Every decision node in a node'sdepends_onmust appear in itswhen; such graphs are refused at submission otherwise, along with guards that can never hold and a route nameddonein any letter case. Validation keeps negation parity and the surrounding boolean expression: a double-negateddoneand a disjunction with a satisfiable arm are accepted, without expanding disjunctions into combinations.not_executed, with a reason:when_false,when_unknownorupstream_not_executed. A node whose dependencies all went unexecuted is not executed either; a failed or skipped dependency still skips its dependents first.<This task is not executed and the output is missing, please go on without this output.>, written outside every untrusted-content fence, plus a note listing the inputs that may be missing. A file reference to the files of a node that may not execute is refused at submission however its path is spelled:@nodes/, an absolute path into the node root, or a workdir path that lands there, symlinks followed. Windows case, separator and drive-relative aliases are recognized, and the advice keeps the declared node ID.subagentDag.verdictEnabledswitch is retired. Config migration 14 removes it with a notice, and drops it again on every later load should an older build sharing the config write it back.raven playbook runnow judges its nodes too, on the samesubagentDagsettings and a pinnedverdictModel's own provider; with nobody there to answer, a node judged not to have accomplished its task fails on the judge's reason. A host with no judge at all refuses graphs that declare routes.Where it shows:
dag.get,tasks.listanddag.run_completedcarryreason,selected_routesandroute_evidenceper node, androutes,selectandwhenfrom the graph. The instance registry's DAG-node rows (andInstanceRow) carry the outcome too, so a client that reloads before the run finalizes shows what a branch decided.TaskCounts.not_executedis a new counter./dag <node>. The Agents Overlay and the live agents strip leave not-executed nodes out, as the backend's agent lists do.run_subagent_dagschema, the DAG orchestration skill and the docs site (English and Chinese) describe routes, guards and the merge rule; CHANGELOG has the entries.A graph with no
routesand nowhenbehaves exactly as before: the same judge requests, events, records, summary and finish text.route_evidenceis a quote the judge picks from the sub-agent's output; it is cut at 500 characters, keeps a lone surrogate from a malformed escape as the escape's own text, and never enters model-facing text (finish text,dag_status, exception reports). When a judge answer does not report a usable route, the judge is asked again at most twice, each time with one correction. The shared instance registry drops its cache when a write fails on the data rather than the disk, so a row the file cannot hold fails its own write and no other.Two Windows CI steps run the alias and finish-text regressions; the latter exposes the installed Git
catexecutable required by the existing fixture.Type
Verification
Linux, Python 3.12.13, on this revision rebased onto the current main (
$CHECKSis a temporary evidence directory):The full run's 23 failures and 3 errors are 25 tests. 24 of them fail the same way on the current main in this environment: the venv lacks
nltkanddatrie(16), a proxy is set in the environment (5), this box has its ownnpmin/usr/bin(1 install-script case), LibreOffice writes no.xlshere (1), and the run is root (1). The 25th,test_a_cli_run_left_on_the_machine_when_this_computer_stops_is_picked_up_by_the_next_start, failed with its teardown in the full run and in one of two runs of its file, and passed in five runs on its own: it reads the remote-run record the moment its pid file appears, a race in code this branch does not change (#840 makes that test wait for both). The four uncovered changed lines are the gateway's_verdict_providerbody, whose helper is tested on its own; a guard atom over a node that did not complete, which the runner never evaluates because it reads a guard only once every dependency completed or was not executed; and the cut of an over-long terminal output.Ruff check and format,
ty checkover the changed modules, the import contracts,deptry raven, commitlint, andscripts/check_commit_messages.py,check_large_files.pyandcheck_source_language.pyover this branch's commits pass. ui-web:vitest run src/features/tasks/BoardCard.test.tsx scripts/gatespasses 50 files and 244 tests, andtsc --noEmitis clean. In Chromium a not-executed title whose first word is wider than the room beside its status now breaks that word instead of starting under a blank line, and every other tasks-board card renders pixel-identical, English and Chinese, light and dark. Firefox still starts such a title under a blank line and cuts it without an ellipsis. CI'sTUI checkscovers ui-tui.Mutation checks: removing any one of these makes its own test fail: the every-load strip of the retired switch, the quote's escape before the cut, the registry's cache drop, the node-root check in the tool, the runner and the replan path, the physical path through a symlink, the CLI's judge, its settings and its no-answer failure, and the pinned judge provider. A model reading only the DAG skill's catch-all paragraph answers that without a catch-all route the judge may pick the nearest route or fail the node; an earlier wording led it to answer that the graph always stops.
A live run on
openrouter/z-ai/glm-5.3-flash, two graphs with synthetic messages, selected the expected route at each decision node, left the unselected branchnot_executedwithwhen_false, and put the fixed sentence outside the fences. Earlier revisions of this change passed the native Windows selections (aliases, finish text, guards; Windows build 26300, Python 3.13.12). The final revision has not been rerun on native Windows or macOS.Risk
Security: sub-agent text stays fenced or out of model-facing text on every new path. The routes block in the judge request sits after the last untrusted fence and is labelled as the graph author's; the missing-output sentence is written outside every fence;
route_evidenceis bounded and reaches records, events, the registry and the UIs only. In the TUI, route evidence is drawn through the same path as a node's error text; neither strips terminal control sequences, which this PR leaves as it is.Behaviour changes: a config that set
subagentDag.verdictEnabled: falsenow gets judged nodes; migration 14 removes the key and says so once.raven playbook runjudges every node, one more model call per node, and a node judged not to have accomplished its task fails there instead of completing. New wire fields are optional exceptTaskCounts.not_executed, which is always present (0 when nothing branched).InstanceRowgains three optional fields, and a decision node's registry row now also stores its selection and up to 500 characters of route evidence.Conditional-artifact validation matches node IDs using the session namespace's case-insensitive identity on every host, including macOS. This conservatively rejects case-only spellings even on case-sensitive filesystems. Separator and drive normalization remain native, and unconditional file resolution keeps its existing behaviour.
Rollback: revert the squash commit. A config already stamped 14 loads unchanged on the previous build, since the stamp only gates migrations; a user who had set
verdictEnabled: falsecan set it again there, and a later build drops it again on load.Related Issues
Related, found while building this and not changed here: #998, #999, #1000. Follow-ups from its review, not changed here: #1008.