duaer-spec 0.27.2 → 0.27.3

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.
Files changed (55) hide show
  1. package/.duaer/active-job.json +3 -3
  2. package/.duaer/specs/281-release-0272/delivery.json +8 -0
  3. package/.duaer/specs/281-release-0272/tasks.md +1 -1
  4. package/.duaer/specs/282-dispatch-confirm-lock/delivery.json +12 -0
  5. package/.duaer/specs/282-dispatch-confirm-lock/spec.md +26 -0
  6. package/.duaer/specs/282-dispatch-confirm-lock/tasks.md +5 -0
  7. package/.duaer/specs/283-desk-theme-compact/delivery.json +12 -0
  8. package/.duaer/specs/283-desk-theme-compact/spec.md +26 -0
  9. package/.duaer/specs/283-desk-theme-compact/tasks.md +5 -0
  10. package/.duaer/specs/284-dispatch-graph-regen/delivery.json +12 -0
  11. package/.duaer/specs/284-dispatch-graph-regen/spec.md +33 -0
  12. package/.duaer/specs/284-dispatch-graph-regen/tasks.md +5 -0
  13. package/.duaer/specs/285-desk-light-compact/delivery.json +11 -0
  14. package/.duaer/specs/285-desk-light-compact/spec.md +13 -0
  15. package/.duaer/specs/285-desk-light-compact/tasks.md +5 -0
  16. package/.duaer/specs/286-modules-bug-theme/delivery.json +10 -0
  17. package/.duaer/specs/286-modules-bug-theme/spec.md +26 -0
  18. package/.duaer/specs/286-modules-bug-theme/tasks.md +5 -0
  19. package/.duaer/specs/287-progress-modules-ux/delivery.json +10 -0
  20. package/.duaer/specs/287-progress-modules-ux/spec.md +31 -0
  21. package/.duaer/specs/287-progress-modules-ux/tasks.md +5 -0
  22. package/.duaer/specs/288-settings-close-compact/delivery.json +10 -0
  23. package/.duaer/specs/288-settings-close-compact/spec.md +17 -0
  24. package/.duaer/specs/288-settings-close-compact/tasks.md +5 -0
  25. package/.duaer/specs/289-settings-close-click/delivery.json +10 -0
  26. package/.duaer/specs/289-settings-close-click/spec.md +16 -0
  27. package/.duaer/specs/289-settings-close-click/tasks.md +4 -0
  28. package/.duaer/specs/290-remove-quicknav/delivery.json +10 -0
  29. package/.duaer/specs/290-remove-quicknav/spec.md +11 -0
  30. package/.duaer/specs/290-remove-quicknav/tasks.md +4 -0
  31. package/.duaer/specs/291-release-0273/spec.md +12 -0
  32. package/.duaer/specs/291-release-0273/tasks.md +4 -0
  33. package/CHANGELOG.md +56 -0
  34. package/bin/duaer-live.mjs +11 -20
  35. package/bin/live-modules.mjs +23 -3
  36. package/docs/agent/e2e-test-plan.md +16 -5
  37. package/docs/agent/live-desk.md +24 -11
  38. package/package.json +1 -1
  39. package/web/live-dev/app.js +329 -167
  40. package/web/live-dev/dispatch-center.html +29 -1
  41. package/web/live-dev/dispatch-center.js +25 -1
  42. package/web/live-dev/i18n-de.js +5 -0
  43. package/web/live-dev/i18n-es.js +5 -0
  44. package/web/live-dev/i18n-fr.js +5 -0
  45. package/web/live-dev/i18n-ja.js +5 -0
  46. package/web/live-dev/i18n-ko.js +5 -0
  47. package/web/live-dev/i18n-pt-BR.js +5 -0
  48. package/web/live-dev/i18n-ru.js +5 -0
  49. package/web/live-dev/i18n-vi.js +5 -0
  50. package/web/live-dev/i18n-zh-TW.js +5 -0
  51. package/web/live-dev/i18n.js +10 -0
  52. package/web/live-dev/index.html +31 -32
  53. package/web/live-dev/styles.css +296 -315
  54. package/web/live-dev/task-graph.mjs +4 -1
  55. package/web/live-dev/theme.mjs +63 -0
@@ -1,5 +1,5 @@
1
1
  {
2
- "feature": "281-release-0272",
3
- "branch": "feat/release-0272",
4
- "worktree": ".worktree/feat-release-0272"
2
+ "feature": "291-release-0273",
3
+ "branch": "chore/release-0273",
4
+ "worktree": ".worktree/chore-release-0273"
5
5
  }
@@ -0,0 +1,8 @@
1
+ {
2
+ "status": "accepted",
3
+ "summary": "Released 0.27.2: architecture clean-flow, project create uniqueness, FDE-08. Tag v0.27.2 published.",
4
+ "verification": {
5
+ "commands": ["gh release view v0.27.2"],
6
+ "result": "GitHub Release published; npm Trusted Publishing via release event"
7
+ }
8
+ }
@@ -1,4 +1,4 @@
1
1
  # Tasks — 281-release-0272
2
2
 
3
3
  - [x] Bump package.json to 0.27.2 and move CHANGELOG Unreleased
4
- - [ ] Promote develop → main, tag, GitHub Release
4
+ - [x] Promote develop → main, tag, GitHub Release
@@ -0,0 +1,12 @@
1
+ {
2
+ "status": "accepted",
3
+ "summary": "After confirm+build, 确认人数并生成派工图 stays locked (chips too) until the dispatch graph is invalidated.",
4
+ "verification": {
5
+ "commands": [
6
+ "node --check web/live-dev/app.js",
7
+ "node --test test/task-graph.test.mjs test/live-i18n-common.test.mjs test/live-i18n-ja.test.mjs",
8
+ "npm run test:live"
9
+ ],
10
+ "result": "all pass"
11
+ }
12
+ }
@@ -0,0 +1,26 @@
1
+ # Feature Specification: Lock confirm-workers after dispatch graph
2
+
3
+ ## Goal
4
+
5
+ After the operator confirms worker count and the dispatch graph builds
6
+ successfully, **确认人数并生成派工图** stays locked so it cannot be
7
+ re-clicked. Worker-count chips lock with it. Unlock only when the graph
8
+ becomes stale (count/decompose/architecture invalidate).
9
+
10
+ ## In scope
11
+
12
+ - Keep confirm button disabled + locked label when `dispatchGraphReady`
13
+ - Lock worker-count chips while the graph is ready
14
+ - Re-enable when the graph is marked stale or cleared
15
+ - i18n + desk docs + E2E catalog + regression markers
16
+
17
+ ## Out of scope
18
+
19
+ - Changing how the graph is generated
20
+ - Locking「查看派工图」
21
+
22
+ ## Acceptance
23
+
24
+ 1. After a successful confirm+build, the confirm button is disabled and shows a locked label.
25
+ 2. Changing architecture / re-decompose / clearing ready unlocks the button again.
26
+ 3. `node --test test/task-graph.test.mjs` and live i18n key parity pass.
@@ -0,0 +1,5 @@
1
+ # Tasks — 282-dispatch-confirm-lock
2
+
3
+ - [x] Lock confirm button + worker chips when dispatchGraphReady
4
+ - [x] Unlock on stale / arch invalidate; sync on project restore
5
+ - [x] i18n + docs + tests
@@ -0,0 +1,12 @@
1
+ {
2
+ "status": "accepted",
3
+ "summary": "Compact FDE desk with calm slate light/dark themes and a persistent top-bar toggle.",
4
+ "verification": {
5
+ "commands": [
6
+ "node --check web/live-dev/app.js",
7
+ "node --test test/desk-theme.test.mjs test/live-i18n-common.test.mjs test/live-i18n-ja.test.mjs",
8
+ "npm run test:live"
9
+ ],
10
+ "result": "all pass"
11
+ }
12
+ }
@@ -0,0 +1,26 @@
1
+ # Feature Specification: Compact desk theme with light/dark toggle
2
+
3
+ ## Goal
4
+
5
+ Make the FDE desk easier to stare at for long sessions: tighter spacing,
6
+ calmer colors (less orange glow / hatch noise), and a light/dark theme
7
+ toggle that persists.
8
+
9
+ ## In scope
10
+
11
+ - Compact shell / header / layout / panel spacing
12
+ - Soft dark + light palettes via `html[data-theme]`
13
+ - Top-bar theme toggle; persist in `localStorage`; early boot to avoid flash
14
+ - Same theme on dispatch-center page
15
+ - i18n + docs + smoke markers
16
+
17
+ ## Out of scope
18
+
19
+ - Redesigning Archify diagram chrome
20
+ - Per-project theme overrides
21
+
22
+ ## Acceptance
23
+
24
+ 1. Desk feels denser (smaller brand, tighter gaps/padding).
25
+ 2. Light and dark themes both readable; toggle switches and persists across reload.
26
+ 3. `npm run test:live` and i18n key parity pass.
@@ -0,0 +1,5 @@
1
+ # Tasks — 283-desk-theme-compact
2
+
3
+ - [x] CSS: compact density + light/dark palettes
4
+ - [x] Theme toggle + persist + dispatch-center wire
5
+ - [x] i18n + docs + tests
@@ -0,0 +1,12 @@
1
+ {
2
+ "status": "accepted",
3
+ "summary": "Each architecture/improve wave forces a fresh 派工图; confirm button shows regenerate when rebuilding; stale clears old URL.",
4
+ "verification": {
5
+ "commands": [
6
+ "node --check web/live-dev/app.js",
7
+ "node --test test/task-graph.test.mjs test/live-i18n-common.test.mjs test/live-i18n-ja.test.mjs",
8
+ "npm run test:live"
9
+ ],
10
+ "result": "all pass"
11
+ }
12
+ }
@@ -0,0 +1,33 @@
1
+ # Feature Specification: Regenerate dispatch graph each wave
2
+
3
+ ## Goal
4
+
5
+ Every kickoff wave (first delivery and each **改进**) must build a **new**
6
+ 派工图. Confirm/lock buttons follow the operator flow: unlock and ask to
7
+ regenerate when the wave changes; stay locked only for the current ready graph.
8
+
9
+ ## Findings (current gaps)
10
+
11
+ 1. `showDispatchPanel` reuses an old `taskPool` after architecture confirm and
12
+ does not force a fresh decompose / clear graph URL.
13
+ 2. `enterReviseMode` (再改一版) does not clear graph ready/URL/pool.
14
+ 3. `markDispatchGraphStale` leaves `dispatchGraphUrl` pointing at an old file.
15
+ 4. Button copy does not distinguish first confirm vs regenerate after stale.
16
+
17
+ ## In scope
18
+
19
+ - Reset + redecompose on architecture confirm and revise entry
20
+ - Clear URL on stale/invalidate; sync chips/button
21
+ - Button labels: confirm / regenerate / locked
22
+ - Docs + tests
23
+
24
+ ## Out of scope
25
+
26
+ - Changing Archify render pipeline internals
27
+
28
+ ## Acceptance
29
+
30
+ 1. After「再改一版」→ plan → architecture confirm, confirm-workers is unlocked
31
+ and builds a new graph (new URL); old ready state is not reused.
32
+ 2. Stale / re-decompose / baseline open-change unlocks and prompts regenerate.
33
+ 3. `node --test` markers and live smoke pass.
@@ -0,0 +1,5 @@
1
+ # Tasks — 284-dispatch-graph-regen
2
+
3
+ - [x] Central resetDispatchGraphForNewWave; call from arch confirm / revise / baseline
4
+ - [x] showDispatchPanel always fresh pool after arch confirm; clear URL on stale
5
+ - [x] Button labels confirm / regen / locked + i18n + tests
@@ -0,0 +1,11 @@
1
+ {
2
+ "status": "accepted",
3
+ "summary": "Light theme uses shared tokens for inputs/composer/bubbles; denser compact spacing.",
4
+ "verification": {
5
+ "commands": [
6
+ "node --test test/desk-theme.test.mjs",
7
+ "npm run test:live"
8
+ ],
9
+ "result": "all pass"
10
+ }
11
+ }
@@ -0,0 +1,13 @@
1
+ # Feature Specification: Light theme contrast + denser compact
2
+
3
+ ## Goal
4
+
5
+ Fix unreadable black/dark hardcodes in light theme and tighten desk density
6
+ another step.
7
+
8
+ ## Acceptance
9
+
10
+ 1. Light theme inputs, composer, chat bubbles, and primary/confirm buttons
11
+ use theme tokens and stay readable.
12
+ 2. Shell spacing is tighter than the previous compact pass.
13
+ 3. `node --test test/desk-theme.test.mjs` and `npm run test:live` pass.
@@ -0,0 +1,5 @@
1
+ # Tasks — 285-desk-light-compact
2
+
3
+ - [x] Replace dark hardcodes with theme tokens; improve light contrast
4
+ - [x] Tighten compact spacing tokens
5
+ - [x] Docs + tests + delivery
@@ -0,0 +1,10 @@
1
+ {
2
+ "status": "accepted",
3
+ "acceptedAt": "2026-09-23T09:45:00.000Z",
4
+ "verification": {
5
+ "L0": "node --check web/live-dev/app.js bin/live-modules.mjs web/live-dev/task-graph.mjs",
6
+ "L1": "npm test (pass)",
7
+ "L3": "npm run test:live (pass)"
8
+ },
9
+ "summary": "Bug path appends defect tab without wiping modules; light theme inset tokens; bug pool prefers id=bug."
10
+ }
@@ -0,0 +1,26 @@
1
+ # Feature Specification: Keep modules clickable during bug + theme leftovers
2
+
3
+ ## Goal
4
+
5
+ After「改缺陷」, prior requirement module tabs must stay visible and clickable
6
+ (view). Fix remaining light-theme dark overlays that still look wrong.
7
+
8
+ ## Cause
9
+
10
+ `enterDeskKind("bug")` / `beginBugFixFromCta` replaced `state.modules` with a
11
+ single bug card, and `renderModuleTabs` hid tabs when `deskKind === "bug"`.
12
+
13
+ ## In scope
14
+
15
+ - Preserve feature modules; append/select a `bug` module instead of wiping
16
+ - Show module tabs in bug mode; feature tabs viewable (readonly when confirmed)
17
+ - Theme: replace leftover `rgba(8,14,20,…)` wells with tokens
18
+ - Docs + tests
19
+
20
+ ## Acceptance
21
+
22
+ 1. After starting a defect from a multi-module feature project, prior module
23
+ tabs remain and switching shows that module's card (readonly if confirmed).
24
+ 2. Bug module is editable; confirming the defect does not delete feature modules.
25
+ 3. Light theme no longer uses fixed near-black overlay fills on wells.
26
+ 4. Targeted tests pass.
@@ -0,0 +1,5 @@
1
+ # Tasks — 286-modules-bug-theme
2
+
3
+ - [x] Preserve modules on bug entry; show tabs; chat merge keeps features
4
+ - [x] Theme overlay leftovers → tokens
5
+ - [x] Tests + docs + delivery
@@ -0,0 +1,10 @@
1
+ {
2
+ "status": "accepted",
3
+ "acceptedAt": "2026-09-23T09:55:00.000Z",
4
+ "verification": {
5
+ "L0": "node --check web/live-dev/app.js bin/duaer-live.mjs bin/live-modules.mjs",
6
+ "L1": "npm test (pass)",
7
+ "L3": "npm run test:live (pass)"
8
+ },
9
+ "summary": "Bug confirm merges modules so prior tabs survive; progress run-blocks use inset tokens; denser desk spacing."
10
+ }
@@ -0,0 +1,31 @@
1
+ # Feature Specification: Progress theme + bug modules survive confirm
2
+
3
+ ## Goal
4
+
5
+ Light theme「派工进度」must not look dark. Desk denser / smoother. After
6
+ entering defect path (and after confirming the defect), prior requirement
7
+ module tabs must stay visible.
8
+
9
+ ## Cause
10
+
11
+ `/api/confirm` (bug) returned a one-item `modules` list (`bug` only). Client
12
+ `applyConfirmSuccess` replaced `state.modules`, wiping feature tabs. Progress
13
+ `.run-block` still used fixed dark `rgba(26,40,54,…)` fills.
14
+
15
+ ## In scope
16
+
17
+ - Server + client: bug confirm merges into existing modules (keep features)
18
+ - Progress column theme tokens + denser spacing / smoother scroll feel
19
+ - Docs + tests (E2E catalog)
20
+
21
+ ## Out of scope
22
+
23
+ - Changing bug task pool shape or hotfix branch rules
24
+
25
+ ## Acceptance
26
+
27
+ 1. Enter「改缺陷」with ≥1 prior module → tabs show prior + bug; after confirm
28
+ defect, prior tabs remain.
29
+ 2. Light theme progress run blocks / meters use theme inset tokens (no near-black
30
+ hardcodes).
31
+ 3. Progress column padding/gaps tighter than pre-fix; targeted tests pass.
@@ -0,0 +1,5 @@
1
+ # Tasks — 287-progress-modules-ux
2
+
3
+ - [x] Bug confirm merge keeps feature modules (API + client)
4
+ - [x] Progress column theme + denser compact
5
+ - [x] Tests + docs + delivery + merge handoff
@@ -0,0 +1,10 @@
1
+ {
2
+ "status": "accepted",
3
+ "acceptedAt": "2026-09-23T10:05:00.000Z",
4
+ "verification": {
5
+ "L0": "node --check web/live-dev/app.js",
6
+ "L1": "npm test (pass)",
7
+ "L3": "npm run test:live (pass)"
8
+ },
9
+ "summary": "Settings closes without ready gate; gear reopen keeps ready; denser drawers/shell."
10
+ }
@@ -0,0 +1,17 @@
1
+ # Feature Specification: Settings always closable + denser desk
2
+
3
+ ## Goal
4
+
5
+ Settings drawer must close via 关闭 / backdrop / gear toggle / Escape even when
6
+ the model is not configured. Make drawers and shell denser.
7
+
8
+ ## Cause
9
+
10
+ Close handlers gated on `state.ready`; gear toggle only closes when ready.
11
+ Escape did not dismiss drawers.
12
+
13
+ ## Acceptance
14
+
15
+ 1. Settings closes without `state.ready` (button, backdrop, gear, Escape).
16
+ 2. Drawers and shell spacing tighter than pre-fix.
17
+ 3. Targeted tests pass.
@@ -0,0 +1,5 @@
1
+ # Tasks — 288-settings-close-compact
2
+
3
+ - [x] Remove ready gate on settings close; Escape closes drawers
4
+ - [x] Densify drawers + shell tokens
5
+ - [x] Tests + docs + delivery + merge
@@ -0,0 +1,10 @@
1
+ {
2
+ "status": "accepted",
3
+ "acceptedAt": "2026-09-23T10:35:00.000Z",
4
+ "verification": {
5
+ "L0": "node --check web/live-dev/app.js",
6
+ "L1": "npm test (pass)",
7
+ "L3": "npm run test:live (pass)"
8
+ },
9
+ "summary": "Cache-bust app.js/styles.css; harden Settings close with closeSettingsDrawer + capture listener."
10
+ }
@@ -0,0 +1,16 @@
1
+ # Feature Specification: Settings close click must work
2
+
3
+ ## Goal
4
+
5
+ The Settings「关闭」button must dismiss the drawer on click.
6
+
7
+ ## Cause
8
+
9
+ Close was gated on `state.ready` in older builds; `app.js?v=perf-budget-1`
10
+ cache kept serving that gate after the logic fix.
11
+
12
+ ## Acceptance
13
+
14
+ 1. Clicking「关闭」hides `#settingsPanel` (with or without model ready).
15
+ 2. Cache-bust query on `app.js` / `styles.css` so operators get the fix.
16
+ 3. Tests assert no ready-gate and bumped asset version.
@@ -0,0 +1,4 @@
1
+ # Tasks — 289-settings-close-click
2
+
3
+ - [x] Bump asset cache + harden close (delegation)
4
+ - [x] Tests + docs + merge handoff
@@ -0,0 +1,10 @@
1
+ {
2
+ "status": "accepted",
3
+ "acceptedAt": "2026-09-23T10:40:00.000Z",
4
+ "verification": {
5
+ "L0": "node --check web/live-dev/app.js",
6
+ "L1": "npm test (pass)",
7
+ "L3": "npm run test:live (pass)"
8
+ },
9
+ "summary": "Removed chat column 导航 quick-nav control (HTML/CSS/JS)."
10
+ }
@@ -0,0 +1,11 @@
1
+ # Feature Specification: Remove chat 导航 button
2
+
3
+ ## Goal
4
+
5
+ Remove the chat-column「导航」quick-nav control.
6
+
7
+ ## Acceptance
8
+
9
+ 1. Desk HTML has no `#chatQuickNav` / `.chat-quicknav`.
10
+ 2. App does not wire quick-nav.
11
+ 3. Docs / E2E / smoke updated; cache bust applied.
@@ -0,0 +1,4 @@
1
+ # Tasks — 290-remove-quicknav
2
+
3
+ - [x] Remove HTML / CSS / JS for chat quick-nav
4
+ - [x] Tests + docs + delivery + merge
@@ -0,0 +1,12 @@
1
+ # Feature Specification: Release 0.27.3
2
+
3
+ ## Goal
4
+
5
+ Ship 0.27.3: desk theme/compact UX, bug-path module tabs, Settings close,
6
+ progress theme, remove chat 导航. Promote develop → main, GitHub Release,
7
+ npm Trusted Publishing.
8
+
9
+ ## Acceptance
10
+
11
+ 1. `package.json` is `0.27.3`; CHANGELOG has `0.27.3` and an empty Unreleased section.
12
+ 2. Tag `v0.27.3` is on `main`; GitHub Release is published; npm has 0.27.3.
@@ -0,0 +1,4 @@
1
+ # Tasks — 291-release-0273
2
+
3
+ - [x] Bump package.json to 0.27.3 and move CHANGELOG Unreleased
4
+ - [ ] Promote develop → main, tag, GitHub Release, npm
package/CHANGELOG.md CHANGED
@@ -2,6 +2,62 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.27.3 — 2026-09-23
6
+
7
+ ### Fix: remove chat「导航」control
8
+
9
+ - Drop the floating quick-nav button and menu from the chat column
10
+
11
+ ### Fix: Settings「关闭」click + cache bust
12
+
13
+ - Bump `app.js` / `styles.css` query so browsers drop the old ready-gated close
14
+ - Harden close via `closeSettingsDrawer` + capture-phase panel listener
15
+ - Larger close hit target; drop sticky-head clip that could swallow clicks
16
+
17
+ ### Fix: Settings always closable + denser drawers
18
+
19
+ - Close Settings without model ready (关闭 / backdrop / gear / Escape)
20
+ - Re-opening Settings from the gear no longer clears `ready`
21
+ - Tighter shell, buttons, and settings drawer spacing
22
+
23
+ ### Fix: progress theme + bug confirm keeps requirement tabs
24
+
25
+ - Confirming a defect merges into existing modules (API no longer returns
26
+ bug-only list that wiped prior tabs)
27
+ - Client hardens applyConfirmSuccess; restores a Main tab from originalCard
28
+ when an older wipe left only `bug`
29
+ - Progress run blocks / meters use inset tokens; denser progress + shell spacing
30
+
31
+ ### Fix: keep requirement modules clickable during bug path
32
+
33
+ -「改缺陷」appends a `bug` tab instead of wiping prior modules; tabs stay
34
+ visible; confirmed feature cards are readonly when selected
35
+ - Bug task pool prefers the `bug` module when feature modules are also confirmed
36
+ - Light theme wells/borders use `--inset*` / `--line` (no fixed near-black fills)
37
+
38
+ ### Fix: light theme contrast and denser compact spacing
39
+
40
+ - Replace leftover dark hardcodes (inputs, composer, bubbles, wells) with
41
+ theme tokens so light mode text/controls stay readable
42
+ - Primary/confirm buttons use on-accent / lock tokens; tighten shell density
43
+
44
+ ### Fix: regenerate dispatch graph on every improve wave
45
+
46
+ - Architecture confirm always starts a fresh task pool and unlocked confirm
47
+ - 「再改一版」clears the prior 派工图; button shows「重新确认并生成派工图」
48
+ - Stale / re-decompose clears the old graph URL so view cannot open a leftover
49
+
50
+ ### Feat: compact desk theme with light/dark toggle
51
+
52
+ - Tighter shell, header, columns, and field spacing
53
+ - Calmer slate palettes (soft blue accent; no orange glow / hatch)
54
+ - Top-bar light/dark toggle persists across reload (desk + dispatch center)
55
+
56
+ ### Fix: lock confirm-workers after dispatch graph builds
57
+
58
+ - After「确认人数并生成派工图」succeeds, the button stays locked (and worker
59
+ chips disable) until the graph is invalidated
60
+
5
61
  ## 0.27.2 — 2026-09-23
6
62
 
7
63
  ### Fix: bottom-via edge labels stay under the floor
@@ -113,6 +113,7 @@ import {
113
113
  clipActiveModuleId,
114
114
  modulesAllConfirmed,
115
115
  confirmModuleInList,
116
+ mergeBugModuleIntoList,
116
117
  aggregateModulesCard,
117
118
  buildTaskPoolFromModules,
118
119
  buildBugTaskPool,
@@ -6720,15 +6721,7 @@ async function handleApi(req, res) {
6720
6721
  "main";
6721
6722
  let modules =
6722
6723
  deskKind === "bug"
6723
- ? [
6724
- {
6725
- id: "bug",
6726
- title: "缺陷",
6727
- status: "draft",
6728
- card: acceptedCard,
6729
- dependsOn: [],
6730
- },
6731
- ]
6724
+ ? mergeBugModuleIntoList(incomingModules, acceptedCard)
6732
6725
  : clipModules(incomingModules, acceptedCard);
6733
6726
  if (!modules.length) {
6734
6727
  modules = [
@@ -6742,7 +6735,10 @@ async function handleApi(req, res) {
6742
6735
  ];
6743
6736
  }
6744
6737
  modules = confirmModuleInList(modules, moduleId, acceptedCard);
6745
- const allConfirmed = modulesAllConfirmed(modules);
6738
+ const allConfirmed =
6739
+ deskKind === "bug"
6740
+ ? modules.some((m) => m.id === "bug" && m.status === "confirmed")
6741
+ : modulesAllConfirmed(modules);
6746
6742
  // Per-module confirm never writes Brief / launches agents — kickoff owns that.
6747
6743
  send(res, 200, {
6748
6744
  ok: true,
@@ -6842,15 +6838,7 @@ async function handleApi(req, res) {
6842
6838
  "main";
6843
6839
  let modules =
6844
6840
  deskKind === "bug"
6845
- ? [
6846
- {
6847
- id: "bug",
6848
- title: "缺陷",
6849
- status: "draft",
6850
- card: acceptedCard,
6851
- dependsOn: [],
6852
- },
6853
- ]
6841
+ ? mergeBugModuleIntoList(incomingModules, acceptedCard)
6854
6842
  : clipModules(incomingModules, acceptedCard);
6855
6843
  if (!modules.length) {
6856
6844
  modules = [
@@ -6864,7 +6852,10 @@ async function handleApi(req, res) {
6864
6852
  ];
6865
6853
  }
6866
6854
  modules = confirmModuleInList(modules, moduleId, acceptedCard);
6867
- const allConfirmed = modulesAllConfirmed(modules);
6855
+ const allConfirmed =
6856
+ deskKind === "bug"
6857
+ ? modules.some((m) => m.id === "bug" && m.status === "confirmed")
6858
+ : modulesAllConfirmed(modules);
6868
6859
  send(res, 200, {
6869
6860
  ok: true,
6870
6861
  passed: true,
@@ -246,6 +246,25 @@ export function confirmModuleInList(modules, moduleId, card) {
246
246
  );
247
247
  }
248
248
 
249
+ /**
250
+ * Keep prior requirement modules when confirming a defect.
251
+ * Replaces only the `bug` slot (or appends it) instead of wiping the list.
252
+ */
253
+ export function mergeBugModuleIntoList(existing, bugCard, { title = "缺陷" } = {}) {
254
+ const kept = clipModules(existing).filter((m) => m.id !== "bug");
255
+ const card = clipCard(bugCard);
256
+ return [
257
+ ...kept,
258
+ {
259
+ id: "bug",
260
+ title: String(title || "缺陷").slice(0, 80),
261
+ status: "draft",
262
+ card,
263
+ dependsOn: [],
264
+ },
265
+ ];
266
+ }
267
+
249
268
  /** Aggregate confirmed modules into one Brief-shaped card. */
250
269
  export function aggregateModulesCard(modules) {
251
270
  const list = clipModules(modules).filter((m) => m.status === "confirmed");
@@ -276,11 +295,12 @@ export function aggregateModulesCard(modules) {
276
295
  */
277
296
  export function buildBugTaskPool(modules, { deployNeeded = false, deployTaskText = null } = {}) {
278
297
  const list = clipModules(modules).filter((m) => m.status === "confirmed");
298
+ const pick = list.find((m) => m.id === "bug") || list[0];
279
299
  const card =
280
- list[0]?.card ||
300
+ pick?.card ||
281
301
  ({ goal: "", outOfScope: "", acceptance: "", assumptions: "" });
282
- const modId = list[0]?.id || "bug";
283
- const title = String(list[0]?.title || "Bug").slice(0, 80);
302
+ const modId = pick?.id || "bug";
303
+ const title = String(pick?.title || "Bug").slice(0, 80);
284
304
  const tasks = [];
285
305
  let n = 1;
286
306
  const push = (partial) => {