feat(status): declared waits, stale watchdog, reported_at aging - #45
Merged
Conversation
Union of both test suites. #45's declared-wait test called report() without a pane or socket, which the merged base now forbids: report() falls back to HERDR_PANE_ID / HERDR_SOCKET_PATH, so such a call posts its fixture to whatever herdr server owns the shell running the suite. It now names an isolated pane and socket like every other call.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements slice 4 status reporting across the existing v2 hook payload, server state/API/events, watchdog scheduler, and TUI projections.
Acceptance criteria
AC1: ✓ turn-end reports with
waitandeta_sare stored server-side and exposed through JSON API/events; absent fields remain unchanged —pane_report_agent_declared_wait_and_reported_at_are_exposed_in_api_and_event,declared_wait_watchdog_uses_deadline_and_fresh_report_clears_stale, and closing-block emitter tests.AC2: ✓ a declared deadline violation derives STALE and a fresh report clears it —
declared_wait_watchdog_uses_deadline_and_fresh_report_clears_stale,stale_watchdog_is_visible_in_api_event_and_cleared_by_fresh_report, andprocess_exit_clears_supervisor_stale_with_hook_authority.AC3: ✓ 20-minute silence without a wait derives STALE, while a live declared wait does not —
no_declared_wait_watchdog_stales_after_silence_only_while_working,declared_wait_watchdog_uses_deadline_and_fresh_report_clears_stale, anddeclared_wait_is_ignored_for_non_working_reports.AC4: ✓ agents cannot self-report STALE; the payload is rejected without corrupting state —
stale_is_not_a_self_reportable_agent_state.AC5: ✓ accepted reports store/expose
reported_at, and the TUI continuously ages the projection from the instant that supplied the visible age —pane_report_agent_declared_wait_and_reported_at_is_visible_in_api_and_event,status_report_age_projection, andreported_at_age_refresh_uses_the_reported_instant_on_desktop_and_mobilecovering desktop and mobile refresh collectors.AC6: ✓ a missing
vis treated as v2 and strict-decodes malformedgates/items/decisionsasinvalid_request; foreign v1 and forward-v3 reports skip silently before strict payload decoding, while malformed v2 remains rejected —report_agent_params_without_version_keep_strict_arrays,malformed_missing_version_report_returns_invalid_request,report_agent_params_with_foreign_version_arrays_still_parse,report_agent_params_with_foreign_version_defers_typed_fields(v3 structuredstate),foreign_version_report_is_a_silent_no_op_without_pty,foreign_version_with_reshaped_state_is_a_silent_no_op, andreport_agent_params_with_current_version_keep_strict_arrays.AC7: ✓ supervisor STALE is a fifth distinct state with a dedicated global stale bucket:
GlobalAgentCounts.staleincrements from the shared stale-aware status key, contributes tototal(), and renders as! N stale; stale also outranks other states in both legacy priority and declarative attention sorting via the shared helper —global_agent_counts_exclude_supervisor_stale_working_agentsassertsstale == 1andtotal() == 1,agent_summary_renders_stale_as_a_distinct_segment,distinct_agent_summary_uses_configured_symbols_for_every_state,priority_sort_surfaces_stale_agents_before_blocked_agents,declarative_attention_sort_surfaces_stale_agents_before_blocked_agents,stale_mobile_agent_detail_uses_the_stale_bucket,workspace_activity_summary_excludes_supervisor_stale_working_panes,navigator_working_filter_excludes_supervisor_stale_rows, andprocess_exit_clears_supervisor_stale_with_hook_authority. Nosrc/detect/changes; navigator metadata/color and desktop/mobile age accents are also stale-aware.AC8: ✓ closing-block emitter assets are updated and tested; deployed copies were not touched — 15 Python closing-block tests plus integration asset tests.
Requirement inventory
wait+eta_sreported_atstorage/API/events and agingValidation
malformed_missing_version_report_returns_invalid_requestpassed; foreign-version dispatcher/schema tests: 4 passed, including v1 silent no-op and v3 structured-state silent no-op.just check-parallelin isolated XDG temp dirs: lint passed; Rust reached the documented parallelwork_context_gitfixture flake, with no changed-surface failures.cargo test --bin herdr work_context_git -- --test-threads=1passed 19/19.