elanous 0.2.18 → 0.2.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apps/pwa/out/404/index.html +1 -1
- package/apps/pwa/out/404.html +1 -1
- package/apps/pwa/out/_next/static/chunks/{1307-30dff22c9e1f3073.js → 1307-77fad80cf54477c6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/1612-f60c0c93ec773f81.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2116-6429c188eb846ab8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/224-e7be8f762fe74986.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2489-ff55a35b202c0f94.js +1 -0
- package/apps/pwa/out/_next/static/chunks/2549-89c518a4c8ed4d00.js +1 -0
- package/apps/pwa/out/_next/static/chunks/3857-995ea9f5ef33d71e.js +1 -0
- package/apps/pwa/out/_next/static/chunks/4144-fad095b48a1862ee.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5755-ea7ed88eb956f47b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/5977-94ed6f78e9814b2b.js +1 -0
- package/apps/pwa/out/_next/static/chunks/7748-6e51bfe927019f5c.js +25 -0
- package/apps/pwa/out/_next/static/chunks/8401-35e94e9091f5eb8d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/9247-c1753a059e7bac08.js +1 -0
- package/apps/pwa/out/_next/static/chunks/a9f2b54d-33c0689b70ed8cf3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/approvals/{page-d92f7ee3994e84c7.js → page-c855c24de7db74fe.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/autopilot/{page-4733c967b56a4277.js → page-85b316bb4235980b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/board/{page-d22fd849cc22f104.js → page-9b2b26a33cb2cd42.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/botlab/{page-bb742f995c6769e7.js → page-c9955fde67b1bcb5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/bots/{page-02b073a2ac793b83.js → page-7a852956c74015a3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-c5a5c621be0e04ae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/chat/{page-8a9b3594bc23289b.js → page-4ba4abe096b6c2a8.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-575d4a8b4f7becb2.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/control/{page-308111abadf35670.js → page-f5d56ff5f45ad164.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-2260e9eef0357421.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/design-check/{page-5d97b2901e0d1ea6.js → page-7c058069c5e7fa63.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-dc5da0b8a2edb8a4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/exec/{page-8c3d8e63ae2e1c98.js → page-466bf0ee16ad1432.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/field/{page-9b72a07d424701c6.js → page-a23bc71713bcc08f.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-ed4a6f799f005d09.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/intake/{page-a572f58cd3ca5864.js → page-9cd565005b93aca6.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-55f0f40c6db95f15.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/live/{page-be5ea965a07fbc41.js → page-474cb5888ea0e8f3.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-35bfec2e631d3eae.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/market/{page-fa244bd146a00ae8.js → page-9ca21f9ad3208a61.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-44d56d6391965a6a.js → page-f9ccb1b1adbea14d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/morning/{page-83a700d4c754d802.js → page-ec102c9b8b691e37.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/{not-found-7b3170f374f77b9d.js → not-found-a9c2cfa8dda922a5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-6da35144878feb6d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-f6055495e9ed7ea8.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-25204694fa9984a5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-a60e035f151d84d3.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-189c587f36874538.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/page-c56634bde705a65d.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/reflection/{page-1467047104141297.js → page-db03ae3589a81c9e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-4a6463b97f0ad94f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/sessions/{page-102310930791197a.js → page-75bffecc9aa1004e.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-a8d2fe0c669e0de4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/settings/{page-6ed0b73bae8351d8.js → page-31d5b875760bb62d.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-c26fa10aac6c21c4.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/setup/{page-43336055451f6e37.js → page-68793c6e10331d66.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/share/{page-3cc47dca0922ab9a.js → page-46d5201d2207a511.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/showroom/{page-a77ee355a2304ff0.js → page-d81c07a7b4f618ae.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/tasks/{page-b17cd46cf0e9b8cf.js → page-be1c4e8697f22360.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-cf0a4b4abead71ea.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/today/page-a4717e2c4bf7a28f.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/trace/{page-7bf54c9bb9274af8.js → page-0fd895fab9b62c1b.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-8b6c1454a8e8f306.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-c6e4364d9de8f717.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-0acc8e198f7b0dfb.js +1 -0
- package/apps/pwa/out/_next/static/chunks/app/workspace/{page-134da468538baf48.js → page-34882c84f84021c5.js} +1 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-0506a1e0e4bdb2f5.js +1 -0
- package/apps/pwa/out/_next/static/chunks/{webpack-c2782b330447ffb6.js → webpack-c260571513bf43c2.js} +1 -1
- package/apps/pwa/out/_next/static/css/{e99e3cff94ced78a.css → 599369d853c61df7.css} +1 -1
- package/apps/pwa/out/_next/static/css/c23d959d3ee15e57.css +1 -0
- package/apps/pwa/out/_next/static/css/d3427996da11e480.css +1 -0
- package/apps/pwa/out/approvals/index.html +1 -1
- package/apps/pwa/out/approvals/index.txt +14 -14
- package/apps/pwa/out/autopilot/index.html +1 -1
- package/apps/pwa/out/autopilot/index.txt +14 -14
- package/apps/pwa/out/board/index.html +1 -1
- package/apps/pwa/out/board/index.txt +14 -14
- package/apps/pwa/out/botlab/index.html +1 -1
- package/apps/pwa/out/botlab/index.txt +14 -14
- package/apps/pwa/out/bots/index.html +1 -1
- package/apps/pwa/out/bots/index.txt +14 -14
- package/apps/pwa/out/ceo/index.html +1 -1
- package/apps/pwa/out/ceo/index.txt +14 -14
- package/apps/pwa/out/chat/index.html +1 -1
- package/apps/pwa/out/chat/index.txt +14 -14
- package/apps/pwa/out/consult/index.html +1 -1
- package/apps/pwa/out/consult/index.txt +14 -14
- package/apps/pwa/out/control/index.html +1 -1
- package/apps/pwa/out/control/index.txt +14 -14
- package/apps/pwa/out/decisions/index.html +1 -1
- package/apps/pwa/out/decisions/index.txt +14 -14
- package/apps/pwa/out/design-check/index.html +1 -1
- package/apps/pwa/out/design-check/index.txt +14 -14
- package/apps/pwa/out/editor/index.html +1 -1
- package/apps/pwa/out/editor/index.txt +16 -15
- package/apps/pwa/out/exec/index.html +1 -1
- package/apps/pwa/out/exec/index.txt +14 -14
- package/apps/pwa/out/field/index.html +1 -1
- package/apps/pwa/out/field/index.txt +14 -14
- package/apps/pwa/out/healthz +1 -1
- package/apps/pwa/out/index.html +1 -1
- package/apps/pwa/out/index.txt +14 -14
- package/apps/pwa/out/inside/index.html +1 -1
- package/apps/pwa/out/inside/index.txt +16 -15
- package/apps/pwa/out/intake/index.html +1 -1
- package/apps/pwa/out/intake/index.txt +14 -14
- package/apps/pwa/out/live/index.html +1 -1
- package/apps/pwa/out/live/index.txt +14 -14
- package/apps/pwa/out/loops/index.html +1 -1
- package/apps/pwa/out/loops/index.txt +24 -23
- package/apps/pwa/out/market/index.html +1 -1
- package/apps/pwa/out/market/index.txt +14 -14
- package/apps/pwa/out/missions/placeholder/index.html +1 -1
- package/apps/pwa/out/missions/placeholder/index.txt +14 -14
- package/apps/pwa/out/morning/index.html +1 -1
- package/apps/pwa/out/morning/index.txt +14 -14
- package/apps/pwa/out/observatory/index.html +1 -1
- package/apps/pwa/out/observatory/index.txt +14 -14
- package/apps/pwa/out/ops/checklist/index.html +1 -1
- package/apps/pwa/out/ops/checklist/index.txt +14 -14
- package/apps/pwa/out/ops/release/index.html +1 -1
- package/apps/pwa/out/ops/release/index.txt +14 -14
- package/apps/pwa/out/ops/seats/index.html +1 -1
- package/apps/pwa/out/ops/seats/index.txt +14 -14
- package/apps/pwa/out/outputs/index.html +1 -1
- package/apps/pwa/out/outputs/index.txt +14 -14
- package/apps/pwa/out/reflection/index.html +1 -1
- package/apps/pwa/out/reflection/index.txt +15 -15
- package/apps/pwa/out/scheduler/index.html +1 -1
- package/apps/pwa/out/scheduler/index.txt +14 -14
- package/apps/pwa/out/sessions/index.html +1 -1
- package/apps/pwa/out/sessions/index.txt +14 -14
- package/apps/pwa/out/settings/devices/index.html +1 -1
- package/apps/pwa/out/settings/devices/index.txt +14 -14
- package/apps/pwa/out/settings/index.html +1 -1
- package/apps/pwa/out/settings/index.txt +14 -14
- package/apps/pwa/out/setup/done/index.html +1 -1
- package/apps/pwa/out/setup/done/index.txt +14 -14
- package/apps/pwa/out/setup/index.html +1 -1
- package/apps/pwa/out/setup/index.txt +14 -14
- package/apps/pwa/out/share/index.html +1 -1
- package/apps/pwa/out/share/index.txt +14 -14
- package/apps/pwa/out/showroom/index.html +1 -1
- package/apps/pwa/out/showroom/index.txt +14 -14
- package/apps/pwa/out/tasks/index.html +1 -1
- package/apps/pwa/out/tasks/index.txt +14 -14
- package/apps/pwa/out/term/index.html +1 -1
- package/apps/pwa/out/term/index.txt +14 -14
- package/apps/pwa/out/today/index.html +1 -1
- package/apps/pwa/out/today/index.txt +14 -14
- package/apps/pwa/out/trace/index.html +1 -1
- package/apps/pwa/out/trace/index.txt +14 -14
- package/apps/pwa/out/vault/index.html +1 -1
- package/apps/pwa/out/vault/index.txt +14 -14
- package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
- package/apps/pwa/out/workflows/chat-ui/index.txt +14 -14
- package/apps/pwa/out/workflows/index.html +1 -1
- package/apps/pwa/out/workflows/index.txt +14 -14
- package/apps/pwa/out/workspace/index.html +1 -1
- package/apps/pwa/out/workspace/index.txt +14 -14
- package/apps/pwa/out/worktrees/index.html +1 -1
- package/apps/pwa/out/worktrees/index.txt +14 -14
- package/graphs/demo/editor-recipes.yaml +22 -0
- package/graphs/ops/guardian.yaml +26 -0
- package/graphs/ops/recipes.yaml +3 -0
- package/graphs/retro/daily.yaml +25 -0
- package/graphs/retro/recipes.yaml +24 -0
- package/package.json +1 -1
- package/scripts/ask-marker-check.ts +3 -1
- package/scripts/coord-channel-watch.sh +2 -2
- package/scripts/discord-seat-probe.ts +3 -1
- package/scripts/land-global-checks.ts +89 -0
- package/scripts/lib/pch-regress-map.ts +24 -0
- package/scripts/morning-report.ts +18 -4
- package/scripts/pch-regress.ts +88 -0
- package/scripts/release-loop/gate-diff.ts +18 -0
- package/scripts/release-loop/gate-node.ts +628 -65
- package/scripts/release-loop/gate-partial.ts +106 -0
- package/scripts/release-loop/gate-timing.ts +229 -0
- package/scripts/release-loop/preflight.ts +6 -4
- package/scripts/release-loop/publish-window.ts +141 -0
- package/scripts/release-loop/release-docs.ts +1 -4
- package/scripts/release-loop/release-universe.ts +38 -0
- package/scripts/release-loop/resume-release.ts +67 -5
- package/scripts/release-loop/shard-plan.ts +65 -0
- package/scripts/release-loop/unattended-release.ts +12 -2
- package/scripts/release-story/draft.ts +5 -1
- package/scripts/retro/shadow-compare.ts +71 -0
- package/scripts/rhythm/daily.ts +6 -1
- package/scripts/video/scene-table.ts +159 -0
- package/src/acp/core-turn-bridge.ts +39 -2
- package/src/agent-mission/driver.ts +34 -6
- package/src/autopilot/build/llm-conflict-merge.ts +132 -7
- package/src/autopilot/build/merge-intent.ts +135 -7
- package/src/away/presence.ts +40 -0
- package/src/away/release-watch.ts +272 -0
- package/src/chat/index.ts +2 -1
- package/src/chat/short-question.ts +3 -40
- package/src/cli/away-cli.ts +68 -0
- package/src/cli/config-drift.ts +513 -0
- package/src/cli/guardian-cli.ts +49 -0
- package/src/cli/intake-cli.ts +13 -7
- package/src/cli/log-event-names.ts +5 -0
- package/src/cli/pod-cli.ts +5 -1
- package/src/cli/pr-cli.ts +20 -0
- package/src/cli/pty-drive-cli.ts +14 -3
- package/src/cli/release-cli.ts +52 -12
- package/src/cli/retro-cli.ts +78 -0
- package/src/cli/setup-cli.ts +31 -1
- package/src/cli/tasks-cli.ts +193 -14
- package/src/context-bus/context-now-public.ts +1 -1
- package/src/context-bus/context-now-surfaces.ts +16 -6
- package/src/context-bus/context-now.ts +97 -3
- package/src/core-turn/short-question.ts +100 -0
- package/src/dashboard/dashboard-status-lines.ts +24 -4
- package/src/dashboard/index.ts +50 -5
- package/src/dashboard/input/slash-executor.ts +6 -2
- package/src/dashboard/slash-runtime/dashboard-handlers.ts +68 -40
- package/src/dashboard/slash-runtime/decide-slash.ts +60 -0
- package/src/dashboard/slash-runtime/help-from-registry.ts +62 -23
- package/src/dashboard/slash-runtime/help-groups.ts +44 -0
- package/src/dashboard/slash-runtime/model-choices.ts +125 -0
- package/src/domains/guardian-tick.ts +138 -0
- package/src/domains/outbound-alert.ts +44 -13
- package/src/domains/outbound-log-probe.ts +6 -1
- package/src/domains/schedule-registry.ts +23 -0
- package/src/domains/telegram-kind-route.ts +39 -0
- package/src/domains/watch-default-scheduler.ts +95 -0
- package/src/esc-abort-gate.ts +44 -0
- package/src/graph-runner/graph-run-api.ts +205 -0
- package/src/graph-runner/runner.ts +36 -6
- package/src/harness/harness-cli-command.ts +420 -51
- package/src/harness/harness-queue.ts +315 -25
- package/src/harness/harness-salvage-cli.ts +140 -0
- package/src/harness/harness-worktree-add.ts +68 -0
- package/src/harness/ledger-write-guard.ts +6 -16
- package/src/hq/fence-outcomes.ts +63 -0
- package/src/hq/fence-wrapper.ts +33 -0
- package/src/hq/hq.ts +17 -2
- package/src/index.ts +118 -6
- package/src/instance/test-write-guard-spy-first.fixture.ts +13 -0
- package/src/instance/test-write-guard.ts +200 -0
- package/src/intake-plane/digest.ts +39 -15
- package/src/intake-plane/harness-target.ts +4 -3
- package/src/intake-plane/intake-sources.ts +1 -0
- package/src/intake-plane/items.ts +1 -0
- package/src/loops/orchestrator/degradation.ts +57 -0
- package/src/loops/orchestrator/finish-rate.ts +33 -3
- package/src/loops/orchestrator/tick.ts +166 -45
- package/src/maturity/feature-maturity.ts +6 -4
- package/src/maturity/tui-slash-maturity.ts +1 -0
- package/src/mss/logging/log-store.ts +3 -0
- package/src/nexus/api/graph-kinds.ts +10 -4
- package/src/nexus/api/graphs-api.ts +178 -6
- package/src/nexus/api/http-server.ts +54 -8
- package/src/nexus/api/loop-edges.ts +292 -17
- package/src/nexus/api/ops-api.ts +112 -29
- package/src/nexus/api/ops-board-route.ts +48 -0
- package/src/nexus/index.ts +7 -0
- package/src/onboarding/entry-hints.ts +5 -0
- package/src/onboarding.ts +24 -6
- package/src/release-loop/checklist.ts +2 -0
- package/src/release-loop/feature-store.ts +68 -18
- package/src/release-loop/gate-shards.ts +158 -0
- package/src/release-loop/light-rc.ts +173 -0
- package/src/release-loop/placement.ts +51 -17
- package/src/release-loop/release-schedule.ts +6 -2
- package/src/release-loop/rubric.ts +57 -1
- package/src/retro/daily.ts +372 -0
- package/src/seat-loop/op-decide.ts +173 -0
- package/src/seat-loop/seat-loop.ts +60 -3
- package/src/seat-loop/seat-report.ts +58 -3
- package/src/self-dev/ask-launch-flow.ts +5 -4
- package/src/self-dev/ask-launch-io.ts +49 -1
- package/src/self-dev/ask-path-candidates.ts +40 -2
- package/src/self-dev/dev-cli.ts +36 -0
- package/src/self-dev/draft-sweep.ts +371 -16
- package/src/self-dev/draft-triage-rules.ts +19 -4
- package/src/self-dev/orchestrate.ts +1 -0
- package/src/self-dev/pr-preview.ts +247 -0
- package/src/self-dev/shard-run.ts +23 -7
- package/src/self-implement/blocked-draft-policy.ts +101 -0
- package/src/self-implement/execution-clarification.ts +11 -0
- package/src/self-implement/gate-cli.ts +29 -8
- package/src/self-implement/gate-env-retry.ts +83 -0
- package/src/self-implement/goal-author-clarification.ts +88 -13
- package/src/self-implement/goal-clarification-escalation.ts +2 -0
- package/src/self-implement/orchestrator.ts +220 -6
- package/src/self-implement/run-stop.ts +123 -0
- package/src/self-implement/run-ttl.ts +258 -0
- package/src/self-implement/salvage-branches.ts +254 -0
- package/src/self-implement/salvage-retention.ts +123 -0
- package/src/self-implement/seams.ts +4 -0
- package/src/self-implement/self-implement-cli.ts +2 -0
- package/src/self-implement/sibling-resync.ts +223 -0
- package/src/self-implement/stop-autoheal.ts +204 -0
- package/src/task-agent/actions.ts +63 -2
- package/src/task-agent/board.ts +132 -0
- package/src/task-agent/card-evidence.ts +292 -0
- package/src/task-agent/completion-evidence.ts +126 -0
- package/src/task-agent/judge.ts +25 -0
- package/src/task-agent/live-moves.ts +276 -0
- package/src/task-agent/mission.ts +33 -7
- package/src/task-agent/shadow.ts +192 -15
- package/src/task-agent/task-hand.ts +124 -17
- package/src/task-orchestrator/surfaces/pod-command-job.ts +82 -8
- package/src/task-orchestrator/surfaces/pod-failure-reason.ts +4 -0
- package/src/task-orchestrator/surfaces/pod-install-slots.ts +89 -0
- package/src/task-orchestrator/surfaces/pod-lease.ts +233 -21
- package/src/task-orchestrator/surfaces/pod-pool.ts +155 -34
- package/src/task-orchestrator/surfaces/self-implement-pod.ts +21 -5
- package/src/telegram-away-command.ts +38 -0
- package/src/telegram-commands.ts +52 -0
- package/src/telegram-report-log-probe.ts +21 -0
- package/src/telegram-report.ts +27 -3
- package/src/testing/real-cli-spawn.ts +106 -0
- package/src/tui-client/dashboard-session.ts +1 -0
- package/src/user-config.ts +190 -5
- package/src/version/packed-revision.json +1 -1
- package/apps/pwa/out/_next/static/chunks/224-798346143007ff65.js +0 -1
- package/apps/pwa/out/_next/static/chunks/3857-4f936cdb30322aa6.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4144-a0041c8dc3be57ac.js +0 -1
- package/apps/pwa/out/_next/static/chunks/4554-5761612531d0146b.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5977-a11f37254196b659.js +0 -1
- package/apps/pwa/out/_next/static/chunks/5994-ae92c0de046ab9ba.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8401-8615a660c84cdb03.js +0 -1
- package/apps/pwa/out/_next/static/chunks/8868-10a3a4440fb0ccd8.js +0 -25
- package/apps/pwa/out/_next/static/chunks/9247-269e4464cc4b491c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/a9f2b54d-7865aba0f4d2ee49.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ceo/page-60c3da708f9a0ccc.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/consult/page-a0eb02638b1e6f31.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/decisions/page-6eaf7bac37830c21.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/editor/page-c39554c321576982.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/inside/page-bd5d586429167fea.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/layout-59b7834d497c2255.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/loops/page-c130b63862437814.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/observatory/page-5f23d0c66a3b4793.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/checklist/page-a3c58f5c72a5f3f9.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/release/page-a2c4625596f8d69c.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-0e9099531d239f11.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/outputs/page-e8e1ecaea7cd71d2.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/page-a1b7ffed710a93e0.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/scheduler/page-2da6f9b8a38c6978.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/settings/devices/page-f331e38fefc00393.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/setup/done/page-44d5f767491692bf.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/term/page-61553851aa606146.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/today/page-a1f585e154e61c59.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/vault/page-5150ef17b5383a57.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-b9d8ce70792c1672.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/workflows/page-a5a3de231f2cc7d5.js +0 -1
- package/apps/pwa/out/_next/static/chunks/app/worktrees/page-31ac4afa2dcd915c.js +0 -1
- package/apps/pwa/out/_next/static/css/7fa358fec7da7c47.css +0 -1
- /package/apps/pwa/out/_next/static/{P6YTVgzuZz5oTZhY4Din_ → Bam1YziK2iH9bN4K0utGk}/_buildManifest.js +0 -0
- /package/apps/pwa/out/_next/static/{P6YTVgzuZz5oTZhY4Din_ → Bam1YziK2iH9bN4K0utGk}/_ssgManifest.js +0 -0
|
@@ -64,12 +64,15 @@ import { GoalRunStore, insertGoalRunRecord, type GoalPriorRuns } from './goal-ru
|
|
|
64
64
|
import { writeGoalRunRecordFragment } from './goal-execution-records.js';
|
|
65
65
|
import { getUserConfig } from '../user-config.js';
|
|
66
66
|
import { appendRunLedgerEntry, loadRunLedger, parseRunShardIdentity, queryRunChain, type RunChainShardSibling, type RunLedgerEntry, type RunLedgerWriter, type RunOriginData, type RunShardIdentity } from './run-ledger.js';
|
|
67
|
+
import { classifyMergeHoldStop, forgetRunStop, readRunStopRecord, recordRunStop, runStopRecorded } from './run-stop.js';
|
|
68
|
+
import { autohealFromStop, parseAutohealMode, type AutohealActions, type AutohealResult } from './stop-autoheal.js';
|
|
67
69
|
import { emitSessionEvent, type SessionEventInput } from '../context-bus/session-events.js';
|
|
68
70
|
import { decideLineageSupersede, lineageSupersedeCloseComment, type LineageSupersedeOpenDraft } from './lineage-supersede.js';
|
|
69
71
|
import { basename, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
70
72
|
import { homedir } from 'node:os';
|
|
71
73
|
import { enqueueControlMemo, readSoftStopRequestStatus, type SoftStopRequestRead } from '../harness/control-inbox.js';
|
|
72
74
|
import { debug } from '../debug/log.js';
|
|
75
|
+
import { classifyGateEnvDeficit, DEFAULT_GATE_ENV_RETRY, GATE_ENV_DEFICIT_HARVESTABLE_MARK, type GateEnvDeficitKind } from './gate-env-retry.js';
|
|
73
76
|
import { recordFailureEvent } from './heal-intake.js';
|
|
74
77
|
import { classifyReworkCapExhaustion, type ReworkCapHealDecision } from './heal-triage.js';
|
|
75
78
|
import { releasePathHold, releasePathHoldComment, RELEASE_PATH_LABEL } from '../self-dev/release-path-guard.js';
|
|
@@ -210,7 +213,7 @@ import { hasModuleLoadFailure, type GateTestFailure } from './gate-baseline.js';
|
|
|
210
213
|
import { commitWorktree, defaultBranchRef, preservationHasChanges } from './seams.js';
|
|
211
214
|
import { detectUncommittedWork } from './uncommitted-work.js';
|
|
212
215
|
import { spawnSync } from 'node:child_process';
|
|
213
|
-
import { blockedDraftDisposition } from './blocked-draft-policy.js';
|
|
216
|
+
import { blockedDraftDisposition, decideDraftOnStop, nextMoveFor, parseDraftOnStopMode, salvageBranchForRun, type DraftOnStopMode } from './blocked-draft-policy.js';
|
|
214
217
|
import { formatLlmMergeOutcome } from '../autopilot/build/llm-conflict-merge.js';
|
|
215
218
|
import { FOUND_CITED_PATH_REFUTATION_QUOTE, MISSING_CITED_PATH_REFUTATION_QUOTE, MUST_FIX_REFUTATION_ACKNOWLEDGEMENT_WITH_REASON, REFUTATION_QUOTE_GRAMMAR, observeMustFixCitedPaths, parseMustFixRefutationAcknowledgement, parseMustFixRefutations, renderMustFixCitedPathFacts, snapshotMustFixFindings, stableMustFixId, type ReflectEvidenceFacts, type ReflectGateFacts, type MustFixCitedPathFact, type MustFixFinding, type MustFixRecurrenceHistory, type MustFixRefutation, type MustFixRefutationKind } from './reflect-mustfix.js';
|
|
216
219
|
import type { IngestionEntry } from '../agent-substrate/execution/ingestion-policy.js';
|
|
@@ -762,7 +765,8 @@ function changedFileIsInsideDeclaredTarget(changedFile: string, declaredPath: st
|
|
|
762
765
|
const file = normalizeDeclaredScopePath(changedFile);
|
|
763
766
|
const target = normalizeDeclaredScopePath(declaredPath);
|
|
764
767
|
if (!file || !target) return false;
|
|
765
|
-
return file === target || file.startsWith(`${target}/`)
|
|
768
|
+
return file === target || file.startsWith(`${target}/`)
|
|
769
|
+
|| (target.endsWith('.ts') && !target.endsWith('.test.ts') && file === `${target.slice(0, -3)}.test.ts`);
|
|
766
770
|
}
|
|
767
771
|
|
|
768
772
|
function parseDeclaredTargetPathsFromAsk(askText: string): { readable: boolean; paths: readonly string[] } {
|
|
@@ -930,6 +934,12 @@ export type ImplementTerminalStatus = {
|
|
|
930
934
|
export interface SelfImplementSeams {
|
|
931
935
|
/** Run-observer ledger sink. Tests inject an in-memory sink to avoid touching user state. */
|
|
932
936
|
writeRunLedger?: RunLedgerWriter;
|
|
937
|
+
/** STOP-AUTOHEAL — heal action seams (live mode only runs actions given here; missing = needs-owner). */
|
|
938
|
+
stopAutohealActions?: AutohealActions;
|
|
939
|
+
/** STOP-AUTOHEAL — one-attempt guard reader. Default: real run ledger, or none when `writeRunLedger` is injected. */
|
|
940
|
+
stopAutohealLoadLedger?: (runId: string) => readonly RunLedgerEntry[] | null;
|
|
941
|
+
/** STOP-AUTOHEAL — observes each dispatcher result (tests). */
|
|
942
|
+
onStopAutoheal?: (result: AutohealResult) => void;
|
|
933
943
|
/** Optional context-journal sink for isolated runs. */
|
|
934
944
|
emitContextEvent?: (input: SessionEventInput) => void;
|
|
935
945
|
/** Registers this run as an ephemeral loop-agent asset; failures are observed but never affect execution. */
|
|
@@ -1028,6 +1038,11 @@ export interface SelfImplementSeams {
|
|
|
1028
1038
|
reviewBaselineObservationSource?: (cwd: string, base: string) => Promise<string | undefined>;
|
|
1029
1039
|
/** ④ gate — cwd 에서 bun test/build. postsync=정합 후 재게이트(merge-base 실행 범위). */
|
|
1030
1040
|
gate: (cwd: string, ctx?: { runId?: string; mode?: 'postsync'; round?: number }) => Promise<SelfImplementGateResult>;
|
|
1041
|
+
/**
|
|
1042
|
+
* GATE-ENV-RETRY — 환경 결손 gate 실패에 «게이트만» 다시 도는 정책. 생략 시 기본(2회 · 20초).
|
|
1043
|
+
* `attempts: 0` 이면 재시도하지 않는다. 시험은 `sleep` 으로 대기를 주입한다.
|
|
1044
|
+
*/
|
|
1045
|
+
gateEnvRetry?: { attempts?: number; delayMs?: number; sleep?: (ms: number) => Promise<void> };
|
|
1031
1046
|
/** Gate가 실행된 worktree HEAD가 local origin/main보다 뒤처진 커밋 수. 실패는 undefined(unknown)로 정직하게 남긴다. */
|
|
1032
1047
|
gateWorktreeBehindMain?: (cwd: string) => Promise<number | undefined>;
|
|
1033
1048
|
/** 변경 파일 목록 — 게이트 «라우터»가 「코드가 바뀌었나」를 판정하는 입력.
|
|
@@ -1068,6 +1083,8 @@ export interface SelfImplementSeams {
|
|
|
1068
1083
|
headCommit?: (cwd: string) => string | undefined;
|
|
1069
1084
|
/** `commit` pins the pushed state; without it the worktree HEAD is pushed. */
|
|
1070
1085
|
preserveBlockedBranch?: (ctx: { cwd: string; branch: string; title: string; commit?: string }) => boolean | Promise<boolean>;
|
|
1086
|
+
/** DRAFT-NOT-ARCHIVE — `tools.selfImplement.draftOnStop` 읽기 seam. 생략하면 user-config(실패·부재 = 'always' · 종전). */
|
|
1087
|
+
draftOnStopMode?: () => DraftOnStopMode;
|
|
1071
1088
|
/** Hard-cap salvage evidence: a clean worktree and commits ahead of origin/main. */
|
|
1072
1089
|
readReworkSalvageEvidence?: (cwd: string) => Promise<ReworkSalvageEvidence>;
|
|
1073
1090
|
/** Starts exactly one detached `elanous dev --file <goal> --base <branch>` follow-up. */
|
|
@@ -1092,6 +1109,8 @@ export interface SelfImplementSeams {
|
|
|
1092
1109
|
mergePr?: (opts: { number: number; cwd: string; matchHeadCommit?: string }) => Promise<{ merged: boolean; baseRefName?: string; mergeCommit?: string; detail?: string }>;
|
|
1093
1110
|
/** Only successful merges trigger this injected, fail-closed draft inventory and mutation seam. */
|
|
1094
1111
|
supersedeDraftsOnMerge?: (number: number, cwd: string) => Promise<void>;
|
|
1112
|
+
/** SIBLING-RESYNC-ON-MERGE — after a successful merge, tell open sibling PRs on the same paths to rebase + regate now. Failure is observation-only. */
|
|
1113
|
+
resyncSiblingsOnMerge?: (number: number, cwd: string) => Promise<void>;
|
|
1095
1114
|
/** Post-merge cleanup is opt-in and injectable so tests never touch the filesystem. */
|
|
1096
1115
|
postMergeCleanup?: {
|
|
1097
1116
|
enabled: boolean;
|
|
@@ -3479,6 +3498,28 @@ function runOriginData(env: NodeJS.ProcessEnv = process.env): RunOriginData {
|
|
|
3479
3498
|
};
|
|
3480
3499
|
}
|
|
3481
3500
|
|
|
3501
|
+
/**
|
|
3502
|
+
* STOP-AUTOHEAL — a recorded stop goes straight to the dispatcher (shadow by default:
|
|
3503
|
+
* `tools.selfImplement.autoheal.mode`). Never throws and never changes the run outcome.
|
|
3504
|
+
*/
|
|
3505
|
+
async function autohealRecordedStop(stopEntry: RunLedgerEntry, s: SelfImplementSeams | undefined): Promise<void> {
|
|
3506
|
+
try {
|
|
3507
|
+
const record = readRunStopRecord(stopEntry);
|
|
3508
|
+
if (!record) return;
|
|
3509
|
+
const mode = parseAutohealMode((await import('../user-config.js')).getUserConfig().tools.selfImplement.autoheal?.mode);
|
|
3510
|
+
const loadLedger = s?.stopAutohealLoadLedger ?? (s?.writeRunLedger ? () => null : undefined);
|
|
3511
|
+
const result = await autohealFromStop({ runId: stopEntry.runId, ...(stopEntry.goalId ? { goalId: stopEntry.goalId } : {}), record }, {
|
|
3512
|
+
mode,
|
|
3513
|
+
...(s?.stopAutohealActions ? { actions: s.stopAutohealActions } : {}),
|
|
3514
|
+
...(loadLedger ? { loadLedger } : {}),
|
|
3515
|
+
...(s?.writeRunLedger ? { writeLedger: s.writeRunLedger } : {}),
|
|
3516
|
+
});
|
|
3517
|
+
s?.onStopAutoheal?.(result);
|
|
3518
|
+
} catch (error) {
|
|
3519
|
+
try { debug.log('self-implement.autoheal', 'dispatch-failed', { runId: stopEntry.runId, error: error instanceof Error ? error.message : String(error) }); } catch { /* fail-soft */ }
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3482
3523
|
export async function runSelfImplement(opts: SelfImplementOptions): Promise<SelfImplementResult> {
|
|
3483
3524
|
if (opts.childLlm && (typeof opts.childLlm.provider !== 'string' || !opts.childLlm.provider.trim() || typeof opts.childLlm.model !== 'string' || !opts.childLlm.model.trim())) {
|
|
3484
3525
|
throw new Error('childLlm.provider and childLlm.model must both be non-empty');
|
|
@@ -3500,6 +3541,7 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
|
|
|
3500
3541
|
const attemptOrdinal = incrementRunAttemptOrdinal(runId);
|
|
3501
3542
|
const shardIdentity = parseRunShardIdentity(opts.feature);
|
|
3502
3543
|
const observeOuter = makeRunObserver(runId, opts.goalId, debug.log.bind(debug), opts.seams.writeRunLedger, shardIdentity);
|
|
3544
|
+
forgetRunStop(runId); // STOP-RECORD: one stop per run «attempt» — a rerun with the same id may record again
|
|
3503
3545
|
try {
|
|
3504
3546
|
// 10-05 PODPROVIDER: record which child provider this run uses — «default» when the launch named none.
|
|
3505
3547
|
const launch = opts.launch ?? resolveLaunchStamp();
|
|
@@ -4108,6 +4150,21 @@ export async function runSelfImplement(opts: SelfImplementOptions): Promise<Self
|
|
|
4108
4150
|
observeOuter('credential-failure-observed', { count: credentialFailureCount, ...lastCredentialFailure });
|
|
4109
4151
|
}
|
|
4110
4152
|
terminalResult = withEvidenceCoverage(addressedResult);
|
|
4153
|
+
// runSelfImplement is the terminal caller: retain every existing PR/ledger/log observation and append one stop fact.
|
|
4154
|
+
if ((addressedResult.stage === 'aborted' || (addressedResult.mergeReason && addressedResult.mergeReason !== 'auto')) && !runStopRecorded(runId)) {
|
|
4155
|
+
const reason = addressedResult.mergeReason;
|
|
4156
|
+
const aborted = addressedResult.stage === 'aborted';
|
|
4157
|
+
let stopEntry: RunLedgerEntry | undefined;
|
|
4158
|
+
try {
|
|
4159
|
+
stopEntry = recordRunStop({ runId, ...(opts.goalId ? { goalId: opts.goalId } : {}), shardIdentity,
|
|
4160
|
+
site: aborted ? 'implement-aborted' : 'merge-hold',
|
|
4161
|
+
class: aborted ? 'unclassified' : classifyMergeHoldStop(reason), cause: aborted ? 'implement aborted' : `merge held: ${reason}`,
|
|
4162
|
+
evidenceRef: addressedResult.prUrl ?? `run-ledger:${runId}:${aborted ? 'implemented' : 'merge-decision'}`,
|
|
4163
|
+
nextMove: aborted ? 'Inspect preserved worktree and child summary' : 'Review merge decision and PR before landing',
|
|
4164
|
+
}, opts.seams.writeRunLedger ?? appendRunLedgerEntry);
|
|
4165
|
+
} catch { /* stop observation cannot change the run outcome */ }
|
|
4166
|
+
if (stopEntry) await autohealRecordedStop(stopEntry, opts.seams);
|
|
4167
|
+
}
|
|
4111
4168
|
observeDeclaredScopeDiff(observeOuter, {
|
|
4112
4169
|
goalFile: opts.goalFile,
|
|
4113
4170
|
changedFiles: opts.goalFile && addressedResult.worktreePath
|
|
@@ -5134,6 +5191,8 @@ async function runSelfImplementInner(
|
|
|
5134
5191
|
limitationCount: number;
|
|
5135
5192
|
} | undefined;
|
|
5136
5193
|
let gate!: SelfImplementGateResult;
|
|
5194
|
+
/** GATE-ENV-RETRY: 재시도 뒤에도 남은 환경 결손의 종류. 정의되면 이 라운드의 gate 실패는 «수확 대기»로 끝난다. */
|
|
5195
|
+
let gateEnvDeficitKind: GateEnvDeficitKind | undefined;
|
|
5137
5196
|
let review: SelfImplementReview | undefined;
|
|
5138
5197
|
/** Review-budget leftovers and the body that carried them, so a later merge drafts from the same text. */
|
|
5139
5198
|
let preparedReviewBudgetPrBody: string | undefined;
|
|
@@ -5381,6 +5440,7 @@ async function runSelfImplementInner(
|
|
|
5381
5440
|
const { listSubscribers } = await import('../session/index.js');
|
|
5382
5441
|
clarificationEscalation = await escalateGoalDocumentClarifications({
|
|
5383
5442
|
goalFile: resolvedGoalFile,
|
|
5443
|
+
runId,
|
|
5384
5444
|
dispatchContext: clarificationDispatchContext,
|
|
5385
5445
|
resolveOriginDelivery: (sessionId) => originHitlDelivery(listSubscribers(sessionId)),
|
|
5386
5446
|
// ⛔ seam 이 주입되면 전역 리졸버는 «불리지 않는다» — 그때 'terminal' 이라 적으면
|
|
@@ -5555,6 +5615,15 @@ async function runSelfImplementInner(
|
|
|
5555
5615
|
});
|
|
5556
5616
|
};
|
|
5557
5617
|
const podReviewBlockedDraft = process.env.ELANOUS_SUBSTRATE === 'pod';
|
|
5618
|
+
/** DRAFT-NOT-ARCHIVE: 멈춤 산출을 PR 대신 수확 가지로 보냈으면 그 가지 — hard-cap 재발사의 base 가 된다. */
|
|
5619
|
+
let salvagedStopBranch: string | undefined;
|
|
5620
|
+
const readDraftOnStopMode = (): DraftOnStopMode => {
|
|
5621
|
+
try {
|
|
5622
|
+
return s.draftOnStopMode ? s.draftOnStopMode() : parseDraftOnStopMode(getUserConfig().tools?.selfImplement?.draftOnStop).mode;
|
|
5623
|
+
} catch {
|
|
5624
|
+
return 'always';
|
|
5625
|
+
}
|
|
5626
|
+
};
|
|
5558
5627
|
let blockedDraftNoChanges = false;
|
|
5559
5628
|
let blockedDraftPrFailure: string | undefined;
|
|
5560
5629
|
const reviewBlockedResult = (pr: { url: string; number: number } | undefined) => ({
|
|
@@ -5767,6 +5836,72 @@ async function runSelfImplementInner(
|
|
|
5767
5836
|
progress(stage, '보존할 변경이 없어 draft PR을 열지 않음');
|
|
5768
5837
|
return undefined;
|
|
5769
5838
|
}
|
|
5839
|
+
// DRAFT-NOT-ARCHIVE (RFC R1): harvestable 멈춤은 draft PR 대신 수확 가지 ⊕ 런 원장(사유·다음 수).
|
|
5840
|
+
// ⛔ Pod review-blocked 는 결과 stage 가 PR 유무로 갈리므로 이 조각에서는 건드리지 않는다.
|
|
5841
|
+
const draftOnStopMode = readDraftOnStopMode();
|
|
5842
|
+
let launchSeat: string | undefined;
|
|
5843
|
+
try { launchSeat = (opts.launch ?? resolveLaunchStamp()).actor; } catch { launchSeat = undefined; }
|
|
5844
|
+
const draftOnStop = decideDraftOnStop({ mode: draftOnStopMode, classification: classificationRecord.classification, seat: launchSeat });
|
|
5845
|
+
const stopCard = {
|
|
5846
|
+
stage,
|
|
5847
|
+
mode: draftOnStop.mode,
|
|
5848
|
+
stopClass: draftOnStop.stopClass,
|
|
5849
|
+
classification: classificationRecord.classification,
|
|
5850
|
+
reason: reason.slice(0, 240),
|
|
5851
|
+
nextMove: nextMoveFor(classificationRecord.classification),
|
|
5852
|
+
branch: wt.branch,
|
|
5853
|
+
};
|
|
5854
|
+
if (draftOnStop.action === 'salvage-branch' && !(stage === 'review-blocked' && podReviewBlockedDraft)) {
|
|
5855
|
+
const salvageBranch = salvageBranchForRun(runId, wt.branch);
|
|
5856
|
+
let artifactPath: string | undefined;
|
|
5857
|
+
let artifactError: string | undefined;
|
|
5858
|
+
try {
|
|
5859
|
+
artifactPath = persistFullPrBody(s.persistPrBodyArtifact, {
|
|
5860
|
+
origin: 'self-implement-draft-not-archive',
|
|
5861
|
+
body: assembled.body,
|
|
5862
|
+
originalChars: assembled.originalChars,
|
|
5863
|
+
});
|
|
5864
|
+
} catch (persistenceError) {
|
|
5865
|
+
artifactError = persistenceError instanceof Error ? persistenceError.message : String(persistenceError);
|
|
5866
|
+
}
|
|
5867
|
+
let salvageError: string | undefined;
|
|
5868
|
+
try {
|
|
5869
|
+
if (s.preserveBlockedBranch) {
|
|
5870
|
+
if (!await s.preserveBlockedBranch({ cwd: wt.path, branch: salvageBranch, title: prTitle(opts.feature) })) throw new Error('수확 가지 push가 성공하지 않았음');
|
|
5871
|
+
} else {
|
|
5872
|
+
if (!existsSync(wt.path)) throw new Error(`worktree not found: ${wt.path}`);
|
|
5873
|
+
const commit = commitWorktree(wt.path, prTitle(opts.feature));
|
|
5874
|
+
if (!commit.ok && !/nothing to commit/.test(commit.out)) throw new Error(`로컬 커밋 실패: ${commit.out}`);
|
|
5875
|
+
const push = runGitCommand(wt.path, ['push', 'origin', `HEAD:refs/heads/${salvageBranch}`]);
|
|
5876
|
+
if (push.status !== 0) throw new Error(push.stderr || push.stdout || 'git push failed');
|
|
5877
|
+
}
|
|
5878
|
+
} catch (error) {
|
|
5879
|
+
salvageError = safeErrorDescription(error);
|
|
5880
|
+
}
|
|
5881
|
+
const artifactFields = { ...(artifactPath ? { prBodyArtifactPath: artifactPath } : {}), ...(artifactError ? { prBodyArtifactError: artifactError } : {}) };
|
|
5882
|
+
if (salvageError === undefined) {
|
|
5883
|
+
salvagedStopBranch = salvageBranch;
|
|
5884
|
+
observe('salvaged', { ...stopCard, salvageBranch, ...artifactFields }, { category: 'self-implement.draft-not-archive' });
|
|
5885
|
+
observe('rework-blocked-draft-pr', { ...observation, skipped: 'draft-not-archive', salvageBranch, nextMove: stopCard.nextMove, ...artifactFields });
|
|
5886
|
+
progress(stage, `멈춤 — draft PR 없이 수확 가지로 보존: ${salvageBranch} · 사유: ${stopCard.reason.slice(0, 160)} · 다음 수: ${stopCard.nextMove}${artifactPath ? ` · 판정 본문: ${artifactPath}` : ''}`);
|
|
5887
|
+
return undefined;
|
|
5888
|
+
}
|
|
5889
|
+
// 수확 가지를 못 남기면 산출을 잃지 않도록 종전대로 draft PR 로 간다.
|
|
5890
|
+
observe('salvage-failed', { ...stopCard, salvageBranch, error: salvageError, fallback: 'open-draft', ...artifactFields }, { category: 'self-implement.draft-not-archive', level: 'warn' });
|
|
5891
|
+
} else if (draftOnStop.mode === 'needs-owner-only') {
|
|
5892
|
+
const ownerLabel = draftOnStop.action === 'open-draft' ? draftOnStop.ownerLabel : undefined;
|
|
5893
|
+
// 자리를 모르면 «모름»으로 남긴다(⛔ OP 로 추측하지 않는다).
|
|
5894
|
+
observe(draftOnStop.stopClass === 'landable' ? 'landable-draft' : 'needs-owner-draft', { ...stopCard, ownerSeat: ownerLabel ? ownerLabel.slice('elanous:seat-'.length) : 'unknown', ...(ownerLabel ? { ownerLabel } : {}) }, { category: 'self-implement.draft-not-archive' });
|
|
5895
|
+
}
|
|
5896
|
+
// 'always' 는 종전 라벨 그대로 · needs-owner-only 의 needs-owner 는 `elanous:needs-owner` ⊕ (아는 경우만) 자리 라벨.
|
|
5897
|
+
// landable(승인된 산출)은 자리 라벨만 — 다음 수가 `pr land` 라 needs-owner 가 아니다.
|
|
5898
|
+
const needsOwnerDraft = draftOnStop.mode === 'needs-owner-only' && draftOnStop.stopClass === 'needs-owner';
|
|
5899
|
+
const seatLabelled = draftOnStop.mode === 'needs-owner-only' && draftOnStop.stopClass !== 'harvestable';
|
|
5900
|
+
const draftLabels = [
|
|
5901
|
+
...(stage === 'review-blocked' ? ['review-blocked'] : []),
|
|
5902
|
+
...(seatLabelled && draftOnStop.action === 'open-draft' && draftOnStop.ownerLabel ? [draftOnStop.ownerLabel] : []),
|
|
5903
|
+
...(needsOwnerDraft ? ['elanous:needs-owner'] : []),
|
|
5904
|
+
];
|
|
5770
5905
|
// Pod review-blocked: a failed commit or PR still pushes the branch, and the result detail says what survived.
|
|
5771
5906
|
const preserveReviewBlockedBranch = async (cause: string, commitFirst: boolean, suffix = ''): Promise<undefined> => {
|
|
5772
5907
|
let pushed = false;
|
|
@@ -5816,7 +5951,7 @@ async function runSelfImplementInner(
|
|
|
5816
5951
|
head: wt.branch,
|
|
5817
5952
|
...(opts.base ? { base: opts.base } : {}),
|
|
5818
5953
|
draft: true,
|
|
5819
|
-
...(
|
|
5954
|
+
...(draftLabels.length > 0 ? { labels: draftLabels } : {}),
|
|
5820
5955
|
cwd: wt.path,
|
|
5821
5956
|
}), T.pr, 'pr');
|
|
5822
5957
|
} catch (error) {
|
|
@@ -5838,6 +5973,17 @@ async function runSelfImplementInner(
|
|
|
5838
5973
|
...(artifactPath ? { prBodyArtifactPath: artifactPath } : {}),
|
|
5839
5974
|
...(artifactError ? { prBodyArtifactError: artifactError } : {}),
|
|
5840
5975
|
}, { level: 'warn' });
|
|
5976
|
+
// STOP-RECORD: a failed blocked-draft PR open (e.g. same-branch rerun with a PR already open) left no stop reason.
|
|
5977
|
+
let draftStopEntry: RunLedgerEntry | undefined;
|
|
5978
|
+
try {
|
|
5979
|
+
const prExists = /already exists|pull request for branch/i.test(prError);
|
|
5980
|
+
draftStopEntry = recordRunStop({ runId, ...(opts.goalId ? { goalId: opts.goalId } : {}), site: 'draft-pr-open-failed', class: 'unclassified',
|
|
5981
|
+
cause: prExists ? 'draft PR open failed: a PR already exists for this branch' : `draft PR open failed: ${prError}`,
|
|
5982
|
+
evidenceRef: artifactPath ?? `branch:${wt.branch}`,
|
|
5983
|
+
nextMove: prExists ? '기존 PR 갱신 (update the existing PR for this branch)' : 'Retry draft PR open from the preserved branch',
|
|
5984
|
+
}, s.writeRunLedger ?? appendRunLedgerEntry);
|
|
5985
|
+
} catch { /* stop observation cannot change the run outcome */ }
|
|
5986
|
+
if (draftStopEntry) await autohealRecordedStop(draftStopEntry, s);
|
|
5841
5987
|
if (stage === 'review-blocked' && podReviewBlockedDraft) {
|
|
5842
5988
|
return preserveReviewBlockedBranch(`draft PR 생성 실패: ${prError}`, true,
|
|
5843
5989
|
`; ${artifactPath ? `판정 본문: ${artifactPath}` : `판정 본문 보존 실패: ${artifactError ?? 'unknown error'}`}`);
|
|
@@ -5872,6 +6018,13 @@ async function runSelfImplementInner(
|
|
|
5872
6018
|
observe('pr.comment.seam-missing', { number: pr.number, salvageAction: action }, { level: 'warn' });
|
|
5873
6019
|
return;
|
|
5874
6020
|
}
|
|
6021
|
+
// QUIET-PR-COMMENTS: a parked outcome is history of this run, not a new notification — fold it into the
|
|
6022
|
+
// single edited status comment (an edit mails nobody). Without the status seams it stays a separate comment.
|
|
6023
|
+
if (s.findPrComment && s.editPrComment) {
|
|
6024
|
+
bufferPrComment(round, 'author', `Rework salvage status: ${action}.`, reason ? [`reason: ${reason}`] : []);
|
|
6025
|
+
await flushPrComments(pr);
|
|
6026
|
+
return;
|
|
6027
|
+
}
|
|
5875
6028
|
const body = [
|
|
5876
6029
|
formatPrComment({ role: 'author', round, run: runId }),
|
|
5877
6030
|
`Rework salvage status: ${action}.`,
|
|
@@ -6045,7 +6198,7 @@ async function runSelfImplementInner(
|
|
|
6045
6198
|
observe('rework-salvage', { action: 'launching', ...launchObservation });
|
|
6046
6199
|
try {
|
|
6047
6200
|
if (!s.launchReworkSalvage) throw new Error('launch seam unavailable');
|
|
6048
|
-
await s.launchReworkSalvage({ goalFile: opts.goalFile!, base: wt.branch, salvageAttempt: (opts.salvageAttempt ?? 0) + 1 });
|
|
6201
|
+
await s.launchReworkSalvage({ goalFile: opts.goalFile!, base: salvagedStopBranch ?? wt.branch, salvageAttempt: (opts.salvageAttempt ?? 0) + 1 });
|
|
6049
6202
|
observe('rework-salvage', { action: 'launched', ...launchObservation });
|
|
6050
6203
|
await postSalvageStatus(pr, 'launched', environmentReason ?? (hardCapBlockedExtend ? 'hard-cap-extend' : undefined));
|
|
6051
6204
|
return 'launched';
|
|
@@ -6231,7 +6384,7 @@ async function runSelfImplementInner(
|
|
|
6231
6384
|
const source = readFileSync(opts.goalFile, 'utf8');
|
|
6232
6385
|
// Always run the shared self-answer so every rework pass leaves one observation, even with nothing pending.
|
|
6233
6386
|
const resolved = await selfAnswerGoalDocumentClarifications(source, {
|
|
6234
|
-
path: 'rework', ask: source, resolver: s.selfResolveClarification,
|
|
6387
|
+
path: 'rework', ask: source, resolver: s.selfResolveClarification, runId,
|
|
6235
6388
|
});
|
|
6236
6389
|
if (resolved.newlyAnswered > 0) writeGoalDocumentAtomic(opts.goalFile, resolved.document);
|
|
6237
6390
|
} catch (error) {
|
|
@@ -6842,7 +6995,7 @@ async function runSelfImplementInner(
|
|
|
6842
6995
|
{ label: 'Stay in scope', description: 'Do not accept out-of-scope changes.', recommended: true },
|
|
6843
6996
|
{ label: 'Expand scope', description: 'Accept the changed files outside the target paths.' },
|
|
6844
6997
|
],
|
|
6845
|
-
}, { runId }, { writeRunLedger: s.writeRunLedger });
|
|
6998
|
+
}, { runId, outsideFiles: scope.outsideNames, outsideCount: scope.outsideCount, declaredPaths: declaredPathsFromGoalDocumentText(goalDocument!).paths }, { writeRunLedger: s.writeRunLedger });
|
|
6846
6999
|
if ('parked' in result || 'deferred' in result || result.choice !== 'Expand scope') {
|
|
6847
7000
|
finalizeSupervisorDeliveries('execution-scope-not-approved');
|
|
6848
7001
|
observe('execution-scope-held', { outsideCount: scope.outsideCount, disposition: 'parked' in result ? 'parked' : 'in-scope-only' });
|
|
@@ -6874,6 +7027,31 @@ async function runSelfImplementInner(
|
|
|
6874
7027
|
}
|
|
6875
7028
|
onNodeEntry(node('gate'), round);
|
|
6876
7029
|
gate = await stepTimeout(s.gate(wt.path, { runId, round }), T.gate, 'gate');
|
|
7030
|
+
// ⭐ GATE-ENV-RETRY — 「잰 쪽」이 넘어진 실패(시험 결과 미수신·index.lock·OOM·측정 불가·네트워크)는
|
|
7031
|
+
// 구현을 버리지 않고 짧게 쉰 뒤 gate «만» 다시 돈다. ⛔ 도입 실패·자식 책임은 판정자가 거짓을 낸다.
|
|
7032
|
+
gateEnvDeficitKind = undefined;
|
|
7033
|
+
let envVerdict = classifyGateEnvDeficit(gate);
|
|
7034
|
+
const envRetryAttempts = Math.max(0, s.gateEnvRetry?.attempts ?? DEFAULT_GATE_ENV_RETRY.attempts);
|
|
7035
|
+
const envRetryDelayMs = Math.max(0, s.gateEnvRetry?.delayMs ?? DEFAULT_GATE_ENV_RETRY.delayMs);
|
|
7036
|
+
const envRetrySleep = s.gateEnvRetry?.sleep ?? ((ms: number) => new Promise<void>((done) => setTimeout(done, ms)));
|
|
7037
|
+
for (let attempt = 1; envVerdict.envDeficit && attempt <= envRetryAttempts; attempt++) {
|
|
7038
|
+
const kind = envVerdict.kind;
|
|
7039
|
+
debug.log('self-implement.gate-env-retry', 'retry-scheduled', { runId, round, attempt, attempts: envRetryAttempts, kind, delayMs: envRetryDelayMs });
|
|
7040
|
+
observe('gate-env-retry', { round, attempt, attempts: envRetryAttempts, kind, delayMs: envRetryDelayMs }, { level: 'warn' });
|
|
7041
|
+
progress('gating', `gate 환경 결손(${kind}) — 구현 유지 · ${Math.round(envRetryDelayMs / 1000)}초 뒤 gate 만 재측정 (${attempt}/${envRetryAttempts})`);
|
|
7042
|
+
await envRetrySleep(envRetryDelayMs);
|
|
7043
|
+
gate = await stepTimeout(s.gate(wt.path, { runId, round }), T.gate, 'gate');
|
|
7044
|
+
envVerdict = classifyGateEnvDeficit(gate);
|
|
7045
|
+
debug.log('self-implement.gate-env-retry', 'retry-result', {
|
|
7046
|
+
runId, round, attempt, kind, passed: gate.passed,
|
|
7047
|
+
stillEnvDeficit: envVerdict.envDeficit,
|
|
7048
|
+
...(envVerdict.envDeficit ? { nextKind: envVerdict.kind } : { verdict: envVerdict.reason }),
|
|
7049
|
+
});
|
|
7050
|
+
}
|
|
7051
|
+
if (envVerdict.envDeficit) {
|
|
7052
|
+
gateEnvDeficitKind = envVerdict.kind;
|
|
7053
|
+
debug.log('self-implement.gate-env-retry', 'exhausted', { runId, round, attempts: envRetryAttempts, kind: envVerdict.kind });
|
|
7054
|
+
}
|
|
6877
7055
|
} else {
|
|
6878
7056
|
observe('gate-skipped-by-graph', { ...graphAuthorityFields(graphAuthority, graphTemplate), round, reason: gateRoute.reason, changedFileCount: gateRouteFiles?.length ?? null });
|
|
6879
7057
|
gate = {
|
|
@@ -6960,6 +7138,26 @@ async function runSelfImplementInner(
|
|
|
6960
7138
|
// 타임아웃«뿐» — 도입 0 · 미분류 0 · 자식 책임 없음. 재작업으로 보내지 않고 리뷰로 진행한다.
|
|
6961
7139
|
// 게이트를 통과로 접지하지 않는다(allowsBaselineOnlyFailure 는 그대로 timedOut===0 을 요구).
|
|
6962
7140
|
// 이 런의 병합은 뒤에서 GATE_TIMEOUT_UNMEASURED_MERGE_REASON 으로 hitl 에 고정한다.
|
|
7141
|
+
if (gateEnvDeficitKind !== undefined) {
|
|
7142
|
+
// ⭐ GATE-ENV-RETRY — 재측정 뒤에도 환경 결손이면 구현을 «버리지 않는다».
|
|
7143
|
+
// 브랜치·draft PR 을 남기고 `harvestable` 로 끝낸다(재작업은 이 신호를 못 바꾼다).
|
|
7144
|
+
const envKind = gateEnvDeficitKind;
|
|
7145
|
+
finalizeSupervisorDeliveries('gate-env-deficit-harvestable');
|
|
7146
|
+
const reason = `gate failed on an environment deficit (${envKind}) after gate-only retries; ${GATE_ENV_DEFICIT_HARVESTABLE_MARK} — implementation kept without rework`;
|
|
7147
|
+
bufferPrComment(round, 'reviewer', `Round ${round}: ${reason}.`, [
|
|
7148
|
+
`Gate: ${gate.log?.trim() || '(gate log unavailable)'}`,
|
|
7149
|
+
]);
|
|
7150
|
+
observe('gate-env-deficit-harvestable', {
|
|
7151
|
+
round, kind: envKind,
|
|
7152
|
+
...(facts ? { introduced: facts.introduced, preexisting: facts.preexisting, unknown: facts.unknown } : {}),
|
|
7153
|
+
...(facts?.unknownReason !== undefined ? { unknownReason: facts.unknownReason } : {}),
|
|
7154
|
+
reason,
|
|
7155
|
+
}, { level: 'warn' });
|
|
7156
|
+
debug.log('self-implement.gate-env-retry', 'harvestable', { runId, round, kind: envKind, branch: wt.branch });
|
|
7157
|
+
progress('gate-failed', `중단 — 환경 결손(${envKind})이 재측정 뒤에도 남음 · 구현 유지 · 수확 대기`);
|
|
7158
|
+
const pr = await preserveBlockedArtifacts({ stage: 'gate-failed', reason, gate, salvageStatusExpected: false });
|
|
7159
|
+
return { ok: false, stage: 'gate-failed', node: 'rework', ...resolveRunOutcome({ termination: 'abandoned' }), harvestable: true, sessionId, worktreePath: wt.path, branch: wt.branch, gate, quotaExhaustionAssessment: quotaExhaustionAssessmentForRun(), ...(pr ? { prUrl: pr.url, prNumber: pr.number } : {}), detail: reason };
|
|
7160
|
+
}
|
|
6963
7161
|
if (isTimeoutOnlyUnmeasuredGate(facts)) {
|
|
6964
7162
|
observe('gate-timeout-only-continued-to-review', {
|
|
6965
7163
|
round,
|
|
@@ -7536,6 +7734,16 @@ async function runSelfImplementInner(
|
|
|
7536
7734
|
sync.status,
|
|
7537
7735
|
);
|
|
7538
7736
|
observe('gate.postsync', postSyncGateObservation(regate, wt.branch, hasModuleLoadFailure, sync.status));
|
|
7737
|
+
// MERGE-INTENT-RESOLVE — join the resolver's sibling-intent decisions with the regate verdict (OP metric).
|
|
7738
|
+
if (sync.intentResolve?.length) {
|
|
7739
|
+
debug.log('self-implement.main-sync', 'intent-resolve', {
|
|
7740
|
+
phase: 'regate', runId, branch: wt.branch, mergeTarget,
|
|
7741
|
+
adopted: [...new Set(sync.intentResolve.map((entry) => entry.adopted))],
|
|
7742
|
+
siblingIntentAdopted: sync.intentResolve.some((entry) => entry.adopted === 'sibling-intent'),
|
|
7743
|
+
files: sync.intentResolve,
|
|
7744
|
+
regatePassed: regate.passed,
|
|
7745
|
+
});
|
|
7746
|
+
}
|
|
7539
7747
|
if (timeoutOnlyPostSync) {
|
|
7540
7748
|
const facts = regate.reflectGateFacts!;
|
|
7541
7749
|
observe('post-sync-gate-timeout-only-continued', {
|
|
@@ -7859,6 +8067,12 @@ async function runSelfImplementInner(
|
|
|
7859
8067
|
} catch (error) {
|
|
7860
8068
|
observe('draft-supersede-on-merge-failed', { number: pr.number, error: safeErrorDescription(error) }, { level: 'warn' });
|
|
7861
8069
|
}
|
|
8070
|
+
// Runs after supersede: a sibling the merge already closed is no longer open, so it gets no resync.
|
|
8071
|
+
try {
|
|
8072
|
+
await s.resyncSiblingsOnMerge?.(pr.number, wt.path);
|
|
8073
|
+
} catch (error) {
|
|
8074
|
+
observe('sibling-resync-on-merge-failed', { number: pr.number, error: safeErrorDescription(error) }, { level: 'warn' });
|
|
8075
|
+
}
|
|
7862
8076
|
const directory = releaseNotesDir(elanousStateRoot());
|
|
7863
8077
|
const fragment: ReleaseNoteFragment = {
|
|
7864
8078
|
pr: pr.number,
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* STOP-RECORD (0.2.20 P0) — 런이 «멈춘» 자리마다 런 원장에 `event='stop'` 한 줄을 «더한다».
|
|
3
|
+
*
|
|
4
|
+
* 멈추는 자리 넷이 이 함수 하나를 부른다:
|
|
5
|
+
* ① 병합 보류(`mergeReason !== 'auto'`) · ② implement aborted — `orchestrator.ts` `runSelfImplement`
|
|
6
|
+
* ③ Pod exit 비0 — `harness-cli-command.ts` `onPod`
|
|
7
|
+
* ④ 발사 직후 자식 비0 종료(launch-failed) — `tasks-cli.ts` `defaultTaskLauncher`
|
|
8
|
+
*
|
|
9
|
+
* ⛔ 보존 계약: 기존 PR 본문·런 원장 항목·logs.db 사건(exit-classified 등)은 손대지 않고 «더하기»만 한다.
|
|
10
|
+
* ⭐ 이 스키마(`RunStopRecord`·`RUN_STOP_CLASSES`)는 STOP-AUTOHEAL 이 읽는다 — 칸 이름·닫힌 목록을 바꾸지 않는다(더하기만).
|
|
11
|
+
*/
|
|
12
|
+
import { debug } from '../debug/log.js';
|
|
13
|
+
import { appendRunLedgerEntry, type RunLedgerEntry, type RunLedgerWriter, type RunShardIdentity } from './run-ledger.js';
|
|
14
|
+
|
|
15
|
+
/** 닫힌 목록 — 못 고르면 `unclassified`. */
|
|
16
|
+
export const RUN_STOP_CLASSES = [
|
|
17
|
+
'env-unrelated', 'main-sync', 'pod-died', 'review-repeat',
|
|
18
|
+
'review-out-of-scope', 'evidence-uncovered', 'fabric', 'launch-failed', 'unclassified',
|
|
19
|
+
] as const;
|
|
20
|
+
export type RunStopClass = typeof RUN_STOP_CLASSES[number];
|
|
21
|
+
|
|
22
|
+
/** 런 원장 `event='stop'` 줄의 `data` 모양(STOP-AUTOHEAL 이 소비한다). */
|
|
23
|
+
export interface RunStopRecord {
|
|
24
|
+
class: RunStopClass;
|
|
25
|
+
/** 한 줄 · ≤120자 · 결정 라벨(원 로그 꼬리 금지). */
|
|
26
|
+
cause: string;
|
|
27
|
+
/** 근거 위치 — PR URL · `run-ledger:<runId>:<event>` · 파일 경로. */
|
|
28
|
+
evidenceRef: string;
|
|
29
|
+
/** 다음 한 수(사람·힐러가 읽는다). */
|
|
30
|
+
nextMove: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const RUN_STOP_EVENT = 'stop';
|
|
34
|
+
export const RUN_STOP_CAUSE_MAX = 120;
|
|
35
|
+
|
|
36
|
+
export interface RunStopInput {
|
|
37
|
+
runId: string;
|
|
38
|
+
goalId?: string;
|
|
39
|
+
shardIdentity?: RunShardIdentity;
|
|
40
|
+
/** 닫힌 목록 밖이거나 비면 `unclassified`. */
|
|
41
|
+
class?: string;
|
|
42
|
+
cause: string;
|
|
43
|
+
evidenceRef: string;
|
|
44
|
+
nextMove: string;
|
|
45
|
+
/** 관측용 — 어느 자리가 불렀나(merge-hold · implement-aborted · draft-pr-open-failed · pod-exit · launch-failed). */
|
|
46
|
+
site?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function isRunStopClass(value: unknown): value is RunStopClass {
|
|
50
|
+
return typeof value === 'string' && (RUN_STOP_CLASSES as readonly string[]).includes(value);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** 원 로그 꼬리가 아니라 «한 줄»로 — 첫 비어 있지 않은 줄 · ANSI 제거 · 공백 접기 · ≤120자(코드 포인트). */
|
|
54
|
+
export function boundRunStopCause(raw: string): string {
|
|
55
|
+
// eslint-disable-next-line no-control-regex
|
|
56
|
+
const plain = raw.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, '').replace(/[\x00-\x08\x0b-\x1f\x7f]/g, (c) => (c === '\r' ? '\n' : ' '));
|
|
57
|
+
const first = plain.split('\n').map((line) => line.replace(/\s+/g, ' ').trim()).find((line) => line.length > 0) ?? '';
|
|
58
|
+
return Array.from(first).slice(0, RUN_STOP_CAUSE_MAX).join('') || 'stop reason unclassified';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 병합 보류 사유 → 닫힌 목록. 모르면 `unclassified`. */
|
|
62
|
+
export function classifyMergeHoldStop(mergeReason: string | undefined): RunStopClass {
|
|
63
|
+
const reason = mergeReason ?? '';
|
|
64
|
+
if (reason.startsWith('main-sync') || reason === 'default-branch-unresolved') return 'main-sync';
|
|
65
|
+
if (reason === 'required-evidence-uncovered') return 'evidence-uncovered';
|
|
66
|
+
if (reason === 'review-must-fix' || reason.startsWith('review-budget')) return 'review-repeat';
|
|
67
|
+
if (reason.startsWith('review-diff') || reason === 'no-real-review') return 'review-out-of-scope';
|
|
68
|
+
return 'unclassified';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Pod exit 분류 사유 → 닫힌 목록. */
|
|
72
|
+
export function classifyPodExitStop(reason: string | undefined): RunStopClass {
|
|
73
|
+
switch (reason) {
|
|
74
|
+
case 'pod-failure': case 'pod-error': case 'OOMKilled': case 'ENOBUFS': case 'signal': return 'pod-died';
|
|
75
|
+
case 'no-launch': return 'launch-failed';
|
|
76
|
+
default: return 'unclassified';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** 이 프로세스에서 stop 을 이미 쓴 런 — 한 런이 두 자리(예: draft PR 실패 ⊕ aborted)에서 두 줄을 쓰지 않게. */
|
|
81
|
+
const recordedThisProcess = new Set<string>();
|
|
82
|
+
const RECORDED_MAX = 4096;
|
|
83
|
+
|
|
84
|
+
/** 이 프로세스가 그 런에 stop 을 이미 썼나(원장 재독 없이 · 같은 프로세스 안 중복 방지용). */
|
|
85
|
+
export function runStopRecorded(runId: string): boolean {
|
|
86
|
+
return recordedThisProcess.has(runId);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** 런 시작 때 부른다 — 같은 runId 로 다시 도는 런(재시도·시험)이 지난 판의 표시에 막히지 않게. */
|
|
90
|
+
export function forgetRunStop(runId: string): void {
|
|
91
|
+
recordedThisProcess.delete(runId);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** 멈춘 런에 stop 한 줄을 더한다 — 기존 관측은 바꾸지 않는다. 쓴 줄을 돌려준다. */
|
|
95
|
+
export function recordRunStop(input: RunStopInput, write: RunLedgerWriter = appendRunLedgerEntry): RunLedgerEntry {
|
|
96
|
+
const record: RunStopRecord = {
|
|
97
|
+
class: isRunStopClass(input.class) ? input.class : 'unclassified',
|
|
98
|
+
cause: boundRunStopCause(input.cause),
|
|
99
|
+
evidenceRef: input.evidenceRef,
|
|
100
|
+
nextMove: input.nextMove,
|
|
101
|
+
};
|
|
102
|
+
const entry: RunLedgerEntry = {
|
|
103
|
+
timestamp: new Date().toISOString(), runId: input.runId, event: RUN_STOP_EVENT,
|
|
104
|
+
data: { ...record },
|
|
105
|
+
...(input.goalId ? { goalId: input.goalId } : {}),
|
|
106
|
+
...input.shardIdentity,
|
|
107
|
+
};
|
|
108
|
+
write(entry);
|
|
109
|
+
if (recordedThisProcess.size >= RECORDED_MAX) recordedThisProcess.clear();
|
|
110
|
+
recordedThisProcess.add(input.runId);
|
|
111
|
+
try {
|
|
112
|
+
debug.log('self-implement.run-stop', 'recorded', { runId: input.runId, site: input.site ?? null, ...record, requestedClass: input.class ?? null });
|
|
113
|
+
} catch { /* observation is fail-soft */ }
|
|
114
|
+
return entry;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** 원장 항목이 stop 줄이면 그 레코드를 돌려준다(STOP-AUTOHEAL 소비용). */
|
|
118
|
+
export function readRunStopRecord(entry: RunLedgerEntry): RunStopRecord | undefined {
|
|
119
|
+
if (entry.event !== RUN_STOP_EVENT) return undefined;
|
|
120
|
+
const data = entry.data as Partial<RunStopRecord>;
|
|
121
|
+
if (typeof data.cause !== 'string' || typeof data.evidenceRef !== 'string' || typeof data.nextMove !== 'string') return undefined;
|
|
122
|
+
return { class: isRunStopClass(data.class) ? data.class : 'unclassified', cause: data.cause, evidenceRef: data.evidenceRef, nextMove: data.nextMove };
|
|
123
|
+
}
|