fix: improve error handling for config loading, task parsing and file transport#10
Merged
tjb-tech merged 1 commit intoHKUDS:mainfrom Mar 18, 2026
Merged
Conversation
… transport - Fix _load_config() crashing on corrupted JSON files instead of returning None as all callers expect. - Fix task create/update accepting empty strings in --blocks and --blocked-by flags (e.g. ",,task1" produced ["", "", "task1"]), which caused tasks to be permanently blocked. - Fix FileTransport.deliver() leaving orphan tmp files on failure. Use Path.replace() for atomic move and clean up tmp in except block. Made-with: Cursor
a24ibrah
pushed a commit
to a24ibrah/ClawTeam
that referenced
this pull request
Mar 30, 2026
fix: improve error handling for config loading, task parsing and file transport
juntaochi
added a commit
to novix-science/ClawTeam-gstack
that referenced
this pull request
Apr 20, 2026
…st_command + deploy_url - 13 failing tests cover presence, frontmatter schema, stub detection (sections + blacklist), test-report rerun + cache-hit + exit-1 + timeout, and ship-notes deploy_url 2xx/non-2xx/URLError paths - Test-local schema fixtures (DesignDoc/TestReport/ShipNotes) inherit from ArtifactFrontmatterBase; Phase 3 GstackSprintPlugin ships the real subclasses - Pitfall HKUDS#4 proof: subprocess_runner injection seam asserted with shell-free list cmd + cwd pin + 300s timeout - Pitfall HKUDS#6 proof: unregistered artifact_type surfaces 'Phase 3 plugin must register' message - Pitfall HKUDS#10 proof: deploy_url_checker injection seam covers URLError offline-safety path - RED: all tests fail with ModuleNotFoundError on clawteam.harness.evidence_gate
juntaochi
added a commit
to novix-science/ClawTeam-gstack
that referenced
this pull request
Apr 20, 2026
…oy_url HEAD probe - New clawteam/harness/evidence_gate.py subclasses ArtifactRequiredGate with: - Layer 1 presence check (inherited) - Layer 2 frontmatter parse + EvidenceSchemaRegistry dispatch; unregistered artifact_type surfaces 'Phase 3 plugin must register' - Layer 3 stub detection (detect_stub): blacklist regex (TBD / TODO / xxx+ / placeholder / Lorem ipsum) with line numbers, then required ## section floor of 100 bytes - Layer 4 dispatch: test-report → _run_test_command (shell=False, cwd=workspace_branch, 300s timeout) with SHA256 content-hash cache persisted via file_locked + atomic_write_text; ship-notes → _check_deploy_url HEAD probe with 10s timeout - Layer 4b per-phase artifact-cap (phase_artifact_cap_bytes) with artifact_compaction suggestion - Injection seams: subprocess_runner (T-02-03 mitigation verification) and deploy_url_checker (Pitfall HKUDS#10 / T-02-01 Phase 5 allowlist contract) - Fix test file: rename TestReportFixture to ReportTestFixture (avoid pytest Test* collection warning); quote created_at YAML values so they stay str (YAML 1.1 auto-parses bare ISO-8601 as datetime) - 13 evidence-gate tests pass; template regression matrix (SC#10), harness, artifact_caps, evidence_schemas, turn_envelope all green (87/87)
juntaochi
added a commit
to novix-science/ClawTeam-gstack
that referenced
this pull request
Apr 27, 2026
- ToolCallCompleted (D-09, cost tracker input) - ClaudeApiResponse (D-12, cache-hit tracking) - BudgetAlarmReached (D-10, budget threshold crossing) - RateLimitSaturated (D-13, 429 backpressure) - ZombieWorktreeGced (SC HKUDS#10, worktree GC) - DormancyTransition (QUALITY-04, agent dormancy) - register_event_type calls appended at module bottom after Phase 6 block
juntaochi
added a commit
to novix-science/ClawTeam-gstack
that referenced
this pull request
Apr 27, 2026
…2 GREEN)
- clawteam/cli/commands.py doctor() gains optional `gc: bool = typer.Option(...)`
flag. When `--gc` absent, behavior is byte-identical to prior doctor()
(existing _DOCTOR_TOOLS iteration + _human() render + _output(checks, _human)).
- With `--gc`: after the tool checklist, walks get_data_dir()/teams/<name>/
for each team dir. For each, collects active_branches from every
SprintState.load(team, sprint_id) under sprints/ (unreadable state.json
fallbacks to sprint_dir.name — preserve-on-doubt safety posture).
Calls find_zombie_worktrees(worktrees_root, max_age_days=30,
active_branches=active_branches) then gc_zombies(zombies, team_name=...,
bus=get_event_bus()) emitting one ZombieWorktreeGced per deletion.
Appends per-team zombies_removed + active_branches_preserved + disk_usage
report to gc_summary["teams"]; combined dict {**checks, "gc": gc_summary}
dispatched via _output for both --json and human branches.
- Human renderer extension: after the existing tool-checklist render,
prints "GC complete: N zombie worktree(s) removed across M team(s)"
then per-team line with disk_usage gb + over_soft/over_hard color tag
(green ok / yellow over-soft / red over-hard).
- Safety invariant (07-RESEARCH §Pitfall 6): active SprintState
workspace_branches preserved regardless of worktree age. Test
test_doctor_gc_respects_active_sprints locks this contract.
Tests: tests/test_doctor_gc.py 4 passed + tests/test_doctor.py 6 passed
+ tests/test_doctor_new_entries.py 22 passed + tests/workspace/ 13 passed
= 45 passed total (BC + new, no regressions).
Closes Plan 07-08 Task 2; ROADMAP §Phase 7 SC HKUDS#10 (zombie worktree GC)
closed for the doctor-entry half. Wave 5 Plan 07-08 complete.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
juntaochi
added a commit
to novix-science/ClawTeam-gstack
that referenced
this pull request
Apr 27, 2026
- .planning/phases/07-parallel-sprints-attentionqueue-ux-cost-controls/07-08-SUMMARY.md (new) Documents both tasks, 2 deviations (Rule 3 cross-executor stash on Task 1 GREEN + Rule 1 fixture mtime bump), interface surface for Plan 07-09, 17 tests green, self-check passed. - .planning/STATE.md status/stopped_at/Current Position/session/decisions/metrics advanced for 07-08; completed_plans 73 -> 74 (96%). - .planning/ROADMAP.md Phase 7 plans table marks 07-08 complete; progress row flipped from 6/9 (Wave 4) to 8/9 (Wave 5 — only 07-09 load test remains). ROADMAP §Phase 7 SC HKUDS#10 (zombie-worktree auto-GC + 5 GB/10 GB disk budget) CLOSED for the doctor-entry half. Sprint-spawn-time auto-GC deferred to v1.x per scope boundary. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
juntaochi
added a commit
to novix-science/ClawTeam-gstack
that referenced
this pull request
Apr 27, 2026
The Phase 7 GC pass previously scanned teams/<team>/worktrees/ — a directory WorkspaceManager never writes to. Real worktrees live at <data_dir>/workspaces/<team>/<agent>/ (workspace/manager._workspaces_root). Net effect: every production invocation of clawteam doctor --gc reported total_zombies=0 even with real zombies on disk; Phase 7 SC HKUDS#10 was silently unmet. Exposed workspaces_root() as a public accessor, switched the CLI scan root to workspaces/<team>/, and rewrote tests/test_doctor_gc.py to build worktrees under the production layout so the test now exercises the shipped path rather than a parallel one. Team discovery now unions teams/ and workspaces/ directories so stale workspaces without a matching teams/ entry are still GC'd. Active-branch safety filter refinement to active_agents (IN-07) is deferred; this commit fixes the scan path only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
juntaochi
added a commit
to novix-science/ClawTeam-gstack
that referenced
this pull request
Apr 27, 2026
User request: "用tmux hook 把prompt注入进每一轮对话 包括身份和需要用的
skill 或者用tmux hook去做一些别的事情 总之tmux hook会是一个很好的技术".
Concept: agents drift over long sessions. CEO forgets to delegate (user
just hit this bug), engineer forgets which `clawteam` subcommands are
available, shipper forgets that `/ship` lives in the framework. A
periodic re-injection of "you are X; here's what you should use"
keeps them anchored.
Implementation:
1. `clawteam nudge <pane_id>` CLI command (new clawteam/nudge.py):
- Looks up pane_id → session → team → agent via the persisted
tmux_pane_map.json
- Debounces (60s cooldown per pane) so repeated silence-hook firings
don't spam the claude TUI
- Reads the latest sprint state (current_phase + goal) for context
- Builds a role-specific reminder text from _ROLE_NUDGES table
(each role gets 2-3 lines: what you ARE + what commands you CAN
run now). Appends "Goal: X · Phase: Y" when available.
- Injects via `tmux send-keys -l <text>` + `send-keys Enter` so
claude processes it as a user turn.
- Silent-fail on any error (a noisy hook drowns the user's tmux).
2. tmux hook wiring (tmux_backend.py::_configure_nudge_hook):
- `monitor-silence = 45s` on each window
- `alert-silence` hook fires `clawteam nudge #{pane_id}` in the
background (`run-shell -b`)
- Opt-out via `CLAWTEAM_NUDGE_SECONDS=0` env var
- Called from both `TmuxBackend.tile_panes()` (happy path) and
`TmuxBackend.enable_mouse()` (the --windows non-tiled path) so
every team gets nudge wiring regardless of layout choice.
3. pane_map normalization (tmux_backend.py::tile_panes):
- Post-layout readback of pane_title returned claude's dynamic
status strings like "⠐ CEO" / "✢ ENG-MGR" (spinner glyphs prefix).
- Normalize by matching uppercase title content against the
pre-merge window roster (roster_upper dict). Any title containing
a known role (e.g. "⠐ CEO" contains "CEO") maps to the canonical
lowercase role name.
- pane_map.json now reliably stores {"0": "ceo", "1": "pm", ...}
regardless of what claude's currently showing.
Real-env verified:
clawteam go --no-attach --no-window "test"
cat ~/.clawteam/teams/<team>/tmux_pane_map.json → clean lowercase roster
clawteam status → Panes: 0=ceo 1=pm ...
# wait for claude to boot
clawteam nudge --force <pane_id> → injects role reminder
tmux capture-pane → sees "[nudge] Reminder:
you DELEGATE, never
implement. Decompose..."
Future uses of this hook infrastructure (brainstormed but not impl):
- HKUDS#3 pane-died → log death reason, optional respawn
- HKUDS#5 alert-activity → append pane output to activity.jsonl timeline
- HKUDS#6 session-created → broadcast phase+goal to all panes
- HKUDS#7 send-keys filter → intercept dangerous commands (rm -rf, force push)
- HKUDS#10 pipe-pane → validate agent envelope JSON against schema
Tests: 30 solo/spawn_cli still green (nudge unit tests not added yet
— next commit candidate).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
_load_config()crashing on corrupted JSON: Whenconfig.jsoncontains invalid JSON or fails Pydantic validation, all callers expectNoneto be returned. Previously this raised an unhandled exception, potentially crashing discover, status, and other team commands.--blocks/--blocked-byflags: Input like--blocked-by ",,task1"produced["", "", "task1"], causing tasks to be permanently blocked since no task has an empty-string ID. Empty entries are now filtered out during parsing in bothtask createandtask update.FileTransport.deliver()leaving orphan tmp files on failure: Ifrenamefailed (e.g. cross-filesystem), the.tmp-*.jsonfile was left behind with no cleanup. Now usesPath.replace()for atomic move and cleans up the tmp file in an except block.Test plan
config.jsonand verifyteam discoverdoesn't crashtask create --blocked-by ",,task1"and verify onlytask1is in blockedBy.tmp-*.jsonfiles accumulate in inbox directoriesMade with Cursor