Logo white

宜博 / lemongraph

Sign in
  • Sign in
  • Project
  • Files
  • Commits
  • Network
  • Graphs
  • Milestones
  • Issues 0
  • Merge Requests 0
  • Labels
  • Wiki
  • Commits 341
  • Compare
  • Branches 1
  • Tags 0
  • lemongraph
04 Aug, 2026
5 commits
  • graphlemon: benchmark artifact for task 43dc7333-8e33-4df6-9c5c-179fde9e4786
    dd58e9a4
    graphlemon authored
    2026-08-04 00:12:38 +0800  
    Browse Code »
  • graphlemon: sdd artifact for task 43dc7333-8e33-4df6-9c5c-179fde9e4786
    ec913590
    graphlemon authored
    2026-08-04 00:12:38 +0800  
    Browse Code »
  • graphlemon: prd artifact for task 43dc7333-8e33-4df6-9c5c-179fde9e4786
    b06a535a
    graphlemon authored
    2026-08-04 00:12:38 +0800  
    Browse Code »
  • graphlemon: brd artifact for task 43dc7333-8e33-4df6-9c5c-179fde9e4786
    6926085c
    graphlemon authored
    2026-08-04 00:12:38 +0800  
    Browse Code »
  • Stop deploy health-check canary probes from leaking project/task rows ...
    d173e4c6
    check_canary_task() creates a real project + task through the candidate's
    own HTTP API to verify the write path works, but only ever cleaned up its
    throwaway git directory -- the DB rows it created via the API were never
    removed. Every real health check permanently grew whatever DB the candidate
    was using by one dead project (pointing at an already-deleted temp dir) and
    one task stuck at 'queued' forever.
    
    Found by inspecting the real ~/.graphlemon/graphlemon.db, which had 5 such
    leaked 'deploy-canary' projects from earlier real health-check runs (now
    archived by hand). Fix: archive the created project in a finally block that
    covers every return path, including task-creation/verification failures
    where only the project (not the task) got created. Best-effort -- the
    archive call failing must not override the real check result.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
    2026-08-04 00:04:02 +0800  
    Browse Code »

03 Aug, 2026
35 commits
  • graphlemon: auto-commit uncommitted changes for ed116584-46de-4db8-a374-82fc9c11… ...
    bd3956f6
    …10c5-main-checkout-drift
    graphlemon authored
    2026-08-03 23:50:59 +0800  
    Browse Code »
  • Deploy agent definitions on project creation; surface real blocked-task errors ...
    a9b5f082
    New target projects never got .claude/agents/*.md deployed, so their first
    Planner call always failed immediately (claude --agent planner finds nothing
    in cwd) -- self-target usage never noticed since those files are already
    committed as part of this repo. create_project() now deploys and commits
    them alongside the existing .graphlemon/ init commit.
    
    Also: unroutable execution failures were recorded as a bare
    blocked_reason='execution_error' with no way to see what actually broke.
    scheduler._block_task()/task_execution._mark_blocked() now persist the real
    exception message into execution_event.payload (blocked_reason itself is
    unchanged -- budget_guardrail matches its exact value elsewhere).
    
    Found via a real console Start-button failure on a freshly created project;
    see docs/implementation-gap-analysis.md for the full writeup.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
    2026-08-03 23:41:25 +0800  
    Browse Code »
  • v_task_detail/v_dashboard: Start/Pause/Stop task execution controls ...
    add263a9
    Users had no way to actually start a queued goal from the console --
    task.status just sits at 'queued' forever. Traced the root cause through
    03-C: c_task_create's own contract ("若 max_concurrent_goals 已达上限,
    任务落 queued 但不触发调度") implies task creation auto-triggers
    scheduling otherwise, and 03-C/04-P repeatedly assume an always-on Org
    Graph scheduler that watches the queue -- src/scheduler.py builds the
    mechanism but nothing ever spins it up as a running process, so no
    "start" button was ever designed because none was supposed to be needed.
    
    Design (confirmed with user, both recommended options chosen):
    - Pause/Stop are a soft stop, not a real subprocess kill -- the current
      in-flight `claude` call finishes naturally, only the next phase is
      withheld. Hard-killing would need Popen + PID tracking, out of scope.
    - No new task.status enum value -- reuses blocked_pending_human with
      blocked_reason='user_paused'/'user_stopped', riding the existing
      manual_resume mechanism instead of a schema change.
    
    New src/task_execution.py: run_or_resume_task_lifecycle() resumes from
    whichever phase actually hasn't run yet (queued/planning_brd_prd_sdd/
    coding), start_task_execution_in_background() runs it to completion on
    its own daemon thread + sqlite connection, request_pause() blocks an
    in-flight task. Extended /route's manual_resume handling so resuming
    from a user-initiated pause/stop actually re-continues execution in the
    background, not just flips the status field back.
    
    Real gap found while building this: backend_server.create_server() never
    stored db_path on the server object -- needed for the new background
    thread to open its own connection to the same db.
    
    22 new tests (14 src/test_task_execution.py + 8 TaskExecutionRouteTest in
    test_backend_server.py, HTTP wiring mocked around the already-unit-tested
    background thread mechanics). Verified against a real running server via
    curl: /execute 409s a non-queued task, /pause 409s a queued task and a
    double-pause, succeeds on a coding task. src/ suite: 496 tests, all green.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
    2026-08-03 17:30:25 +0800  
    Browse Code »
  • Add v_project_list and v_goal_list CRUD (user-requested scope expansion) ...
    7c720ab8
    Two new console pages requested directly by the user, beyond 02-V's
    original declared non-goal ("不做完整多项目管理 UI(项目列表/切换)"):
    
    - v_project_list: full project list + rename + archive/reactivate.
      "Import an existing directory with real code" needs no new code --
      project_scaffold.create_project() already only ever adds .graphlemon/
      inside the target folder. New: src/project_query.py (list/get/update),
      GET/PUT/DELETE /api/projects[/:id]. DELETE archives (status='archived'),
      never a physical row delete -- project_id is FK-referenced from task/
      artifact/bug_record/etc., and 01-M's own active/archived enum already
      models this as soft-delete.
    
    - v_goal_list: extends the existing v_task_board/v_task_detail rather than
      duplicating them. Added sort/order to task_query.list_tasks() (column
      whitelist, no injection surface) and edit/delete on v_task_detail, both
      restricted to status='queued' (task_query.TaskNotEditableError, HTTP 409)
      -- editing or deleting a goal after real work has referenced it would
      leave that history pointing at something that no longer matches reality.
    
    Implemented directly rather than through graphlemon's own self-hosting
    loop -- confirmed with the user first that implement_code() always uses a
    hardcoded single-node manifest (no plan_work_graph() call for Coder), so a
    multi-page/multi-endpoint feature like this would've been one unreviewable
    Coder session with no way to decompose it.
    
    Real bug found on first verification pass (not caught by the existing
    _insert_task test helper, which never writes execution_event): a real
    task_create.create_task() always writes an execution_event row in the same
    transaction (01-M's FK, no ON DELETE CASCADE) -- even a never-touched
    queued task already has one, so DELETE FROM task raised
    sqlite3.IntegrityError. Fixed by clearing the task's own execution_event
    rows first; new regression test goes through the real create_task() path.
    
    474 tests green. Verified end-to-end against a real running server (every
    new endpoint exercised via curl) since the Chrome extension is still
    unavailable this session.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
    2026-08-03 14:24:12 +0800  
    Browse Code »
  • Rewrite CLAUDE.md to reflect current repo state, not PH0-era scaffolding ...
    a5f1618e
    The original CLAUDE.md described a pre-scaffolding repo with no commits and
    open questions about A-2/critical path -- stale since PH0. Updates it to
    point at git log as the actual status record, document the two independent
    unittest discover roots (src/ and supervisor/), the real backend_server.py
    CLI, the .graphlemon-worktrees/ isolation mechanism and its three real
    incident notes, and a full repo layout reflecting what's actually there.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
    2026-08-03 14:23:52 +0800  
    Browse Code »
  • U-042: expose monitor_window_hours/monitor_min_task_count as testing knobs ...
    5098fbe4
    Attempt 13b was the first real run to get all the way through a real
    cutover -- task lifecycle, classification, staging, health check (fixed
    last commit), and a genuine blue-green cutover all succeeded for real. It
    correctly landed in 'monitor' and then correctly couldn't finish: the real
    production exit condition (deploy_monitor.MONITORING_WINDOW_HOURS=24h OR
    MONITORING_MIN_TASK_COUNT=10 real tasks in the monitored project, NOT the
    disposable per-cycle canary project) isn't practical to wait out in an
    interactive session. This isn't a bug -- those are sensible real defaults
    -- it's a testability gap: run_self_hosting_closed_loop already exposes
    monitor_timeout_cycles as an override knob for exactly this kind of
    situation, but never threaded the two constants that actually gate
    "monitoring_window_clean" through to run_monitor_cycle.
    
    Added monitor_window_hours/monitor_min_task_count params, defaulting to
    deploy_monitor's real constants (production behavior unchanged), threaded
    through to the actual run_monitor_cycle call. New assertion locks in that
    overrides actually reach it.
    
    Also documents the full run of 9 real bugs found and fixed across 13
    attempts in development-plan.md's U-042 note.
    
    564 tests green (441 src + 123 supervisor).
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
    2026-08-03 13:55:56 +0800  
    Browse Code »
  • graphlemon: test_report artifact for task 13601943-2489-42f0-a68d-10b2c56312f2
    efcf600c
    graphlemon authored
    2026-08-03 13:49:32 +0800  
    Browse Code »
  • graphlemon: code_diff artifact for task 13601943-2489-42f0-a68d-10b2c56312f2
    cc68d0fa
    graphlemon authored
    2026-08-03 13:49:32 +0800  
    Browse Code »
  • graphlemon: merge 55f7adaa-40f2-40cd-bde4-3ee67d46840c
    49fdbff1
    graphlemon authored
    2026-08-03 13:49:32 +0800  
    Browse Code »
  • graphlemon: auto-commit uncommitted changes for 55f7adaa-40f2-40cd-bde4-3ee67d46840c
    e9aeecdc
    graphlemon authored
    2026-08-03 13:49:32 +0800  
    Browse Code »
  • graphlemon: benchmark artifact for task 13601943-2489-42f0-a68d-10b2c56312f2
    5abfea66
    graphlemon authored
    2026-08-03 13:47:05 +0800  
    Browse Code »
  • graphlemon: sdd artifact for task 13601943-2489-42f0-a68d-10b2c56312f2
    e5bf7c33
    graphlemon authored
    2026-08-03 13:47:05 +0800  
    Browse Code »
  • graphlemon: prd artifact for task 13601943-2489-42f0-a68d-10b2c56312f2
    09ba0db1
    graphlemon authored
    2026-08-03 13:47:05 +0800  
    Browse Code »
  • graphlemon: brd artifact for task 13601943-2489-42f0-a68d-10b2c56312f2
    eb6ecd24
    graphlemon authored
    2026-08-03 13:47:05 +0800  
    Browse Code »
  • graphlemon: auto-commit uncommitted changes for 7dd4ce06-846e-4712-8e34-809c1289… ...
    d4537c6e
    …3203-main-checkout-drift
    graphlemon authored
    2026-08-03 13:37:39 +0800  
    Browse Code »
  • graphlemon: merge 06c1263c-711b-4cb4-8f4b-5fd29c242750 (retried after cleanup)
    4b42a1e9
    bboonnee authored
    2026-08-03 13:33:24 +0800  
    Browse Code »
  • graphlemon: auto-commit uncommitted changes for 06c1263c-711b-4cb4-8f4b-5fd29c24… ...
    b0799411
    …2750-main-checkout-drift
    graphlemon authored
    2026-08-03 13:32:35 +0800  
    Browse Code »
  • graphlemon: auto-commit uncommitted changes for 06c1263c-711b-4cb4-8f4b-5fd29c242750
    f786c2da
    graphlemon authored
    2026-08-03 13:32:35 +0800  
    Browse Code »
  • U-038 fix: http_health polls for startup readiness instead of one-shot ...
    d53156cd
    Attempts 7 and 11 both failed at exactly the same spot: process_alive read
    'ok' within milliseconds of Popen, then http_health hit ECONNREFUSED in the
    same second and gave up. Real cause: process_alive only confirms the
    process EXISTS, not that backend_server.py has finished importing modules
    and actually bound its listen socket -- a real, non-zero startup gap. The
    old check_http_health did one urlopen(timeout=X) call; that timeout only
    bounds how long to wait for a response once connected, not how long to
    wait for the port to start accepting connections at all -- ECONNREFUSED
    fires essentially instantly when nothing's listening yet, regardless of
    timeout.
    
    This touches an explicit 03-C design statement ("不重试——重试属于给坏版本
    第二次机会"), so confirmed with the user before changing it rather than
    just reinterpreting the policy unilaterally. Resolution: tolerating normal
    startup latency within ONE health-check pass isn't "retrying a failed
    check" -- check_process_alive already does exactly this (polls up to 30s
    for the pid to exist). http_health now does the same, polling within its
    own timeout for connection-refused-class errors specifically. A genuine
    non-2xx HTTP response is still a definitive answer from a live server and
    still fails immediately, no polling -- that boundary is unchanged.
    
    Two new real regression tests: a real server that starts listening 0.3s
    late is correctly waited for and passes; a real 500 response still fails
    immediately without being mistaken for "not up yet".
    
    564 tests green (441 src + 123 supervisor).
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
    2026-08-03 13:28:29 +0800  
    Browse Code »
  • graphlemon: real agent-memory updates from self-hosting run 11 (validator)
    2ffa71fa
    bboonnee authored
    2026-08-03 13:27:29 +0800  
    Browse Code »
  • Revert "graphlemon: test_report artifact for task 8ea58a57-b53b-4649-a081-de29ac60347d" ...
    e3cce77c
    This reverts commit b14c41371f803541c1f01debb0658ea13e816e0d.
    bboonnee authored
    2026-08-03 13:16:56 +0800  
    Browse Code »
  • graphlemon: test_report artifact for task 8ea58a57-b53b-4649-a081-de29ac60347d
    b14c4137
    graphlemon authored
    2026-08-03 13:12:09 +0800  
    Browse Code »
  • graphlemon: code_diff artifact for task 8ea58a57-b53b-4649-a081-de29ac60347d
    a22220a2
    graphlemon authored
    2026-08-03 13:12:09 +0800  
    Browse Code »
  • graphlemon: merge 4377f28d-6610-4891-a1de-58745b01f55d
    69567be4
    graphlemon authored
    2026-08-03 13:12:09 +0800  
    Browse Code »
  • graphlemon: auto-commit uncommitted changes for 4377f28d-6610-4891-a1de-58745b01f55d
    761681ae
    graphlemon authored
    2026-08-03 13:12:09 +0800  
    Browse Code »
  • graphlemon: benchmark artifact for task 8ea58a57-b53b-4649-a081-de29ac60347d
    93b76bdc
    graphlemon authored
    2026-08-03 13:07:27 +0800  
    Browse Code »
  • graphlemon: sdd artifact for task 8ea58a57-b53b-4649-a081-de29ac60347d
    e7dd5a35
    graphlemon authored
    2026-08-03 13:07:27 +0800  
    Browse Code »
  • graphlemon: prd artifact for task 8ea58a57-b53b-4649-a081-de29ac60347d
    00fb28e5
    graphlemon authored
    2026-08-03 13:07:27 +0800  
    Browse Code »
  • graphlemon: brd artifact for task 8ea58a57-b53b-4649-a081-de29ac60347d
    5faa2197
    graphlemon authored
    2026-08-03 13:07:27 +0800  
    Browse Code »
  • graphlemon: auto-commit uncommitted changes for e30e6617-203e-4941-b85f-131e4ae9… ...
    39213ab2
    …be04-main-checkout-drift
    graphlemon authored
    2026-08-03 13:01:26 +0800  
    Browse Code »
  • U-013 follow-up: drop the exclude pathspec, it was itself a hard error ...
    ebfcc437
    Attempt 10 crashed immediately in the fix committed last: git add -A --
    . ':!.graphlemon-worktrees' throws "paths are ignored by one of your
    .gitignore files" (exit 1, not just advisory text -- confirmed even with
    advice.addIgnoredFile=false suppressed) the moment that path is ALSO
    gitignored, which it now always is. Reproduced locally.
    
    Plain `git add -A` (no explicit pathspec) already skips gitignored paths
    correctly on its own -- the explicit exclude was redundant now that
    .gitignore covers it, and actively conflicting. Simplified
    ensure_worktree_committed() back down. Also added the same .gitignore
    entry to test_work_node_run.py's _init_git_repo() fixture so real-worktree
    tests match production config instead of coincidentally not hitting this.
    
    562 tests green (441 src + 121 supervisor).
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
    2026-08-03 12:59:06 +0800  
    Browse Code »
  • U-013 fix: auto-commit main-checkout drift too, not just the worktree's own ...
    b6423cff
    Attempts 8 and 9 both hit "local changes would be overwritten by merge"
    again, despite the earlier _check_prd_consistency worktree-isolation fix.
    Root cause is deeper: git worktrees deliberately SHARE project identity
    with their main checkout (same .git, just another checkout) -- a real
    `claude -p` call's memory:project write doesn't reliably respect the cwd it
    was invoked with, and can land directly on the main checkout regardless of
    which specific call triggered it. Worktree-wrapping one call (as done for
    _check_prd_consistency) only moves around which call happens to trigger
    this; it doesn't fix the underlying issue.
    
    ensure_worktree_committed() now also runs against repo_path itself (not
    just the worktree) right before every merge_worktree() call, in both
    work_node_run.run_work_node() and e2e_pipeline._check_prd_consistency().
    Same already-tested mechanism, now applied generically regardless of which
    real call caused the drift or why.
    
    Fixing this surfaced a second real bug in the fix itself: running `git add
    -A` against repo_path while a node's own .graphlemon-worktrees/<id>/
    checkout is still present on disk picks it up as a gitlink-like entry,
    which then shows as "deleted" the instant remove_worktree() runs right
    after. Fixed by excluding .graphlemon-worktrees/ from both the dirty-check
    and the add via pathspec (not relying on the caller repo's own .gitignore),
    plus added it to graphlemon's own .gitignore for correctness generally.
    
    New regression test: test_drift_on_main_checkout_is_auto_committed_before_merge
    reproduces a run_fn writing directly to repo_path instead of its worktree,
    and confirms a second node's own merge isn't affected by it.
    
    562 tests green (441 src + 121 supervisor).
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    bboonnee authored
    2026-08-03 12:50:34 +0800  
    Browse Code »
  • graphlemon: merge e37929c2-d191-4e22-b669-3d4f7f87f150 (retried after cleanup)
    8d980dec
    bboonnee authored
    2026-08-03 12:49:25 +0800  
    Browse Code »
  • graphlemon: real agent-memory updates from self-hosting run 8
    17a466ba
    bboonnee authored
    2026-08-03 12:48:01 +0800  
    Browse Code »
  • graphlemon: auto-commit uncommitted worktree changes for e37929c2-d191-4e22-b669-3d4f7f87f150
    1f58c5bc
    graphlemon authored
    2026-08-03 12:42:07 +0800  
    Browse Code »