Closes five gaps in the ultrawork prompt versus codex-plugins' parallel
directive, applied to all three model variants (default/Claude, GPT, Gemini)
with prompt-engineering entropy gate (each addition encodes a distinct
binding boolean, not narrative reinforcement):
1. TDD-MANDATORY (was conditional "when test infrastructure exists"):
every production change follows RED -> GREEN -> SURFACE. Failing test
first, capture assertion msg, smallest change to flip green, exercise
real surface, capture artifact. Exemption whitelist: formatting /
comment-only / version bump / rename-only, each must be justified
in writing; unjustified exemption = rejection.
2. Scenario contract (was free-form Test Plan Template): require 3+
scenarios upfront covering happy path, edge (boundary / empty /
malformed / concurrent), adjacent-surface regression. Each scenario
binds a binary pass condition, a real-surface artifact source, and
a test file + test id written test-first.
3. RED->GREEN evidence capture (was "all tests pass"): every scenario
requires TWO captured artifacts -- RED assertion msg before the
change AND GREEN assertion msg after -- alongside the real-surface
artifact (tmux / curl / browser / Playwright / computer-use /
CLI stdout / parsed config / DB diff). Tests are the floor (always
required); surface artifact is the ceiling (also required).
4. Durable notepad: mktemp -t ulw-*.md with append-only sections
(Plan, Scenarios, Now, Todo, Findings, Learnings). Survives context
loss; resume by re-reading.
5. Reviewer gate: trigger when user said strictly / rigorously /
"deeply", or task touches 3+ files / 20+ turns / 30+ min, or it is
refactor / migration / perf / security work. Reviewer verdict is
binding ("looks good but..." = rejection). Loop until unconditional
approval.
Plus: TODO format upgraded from vague "track every step" to atomic
`path: <action> for <scenario-id> -- verify by <check>` with a GOOD
test-first / impl pair example and a BAD list including
"production code before its failing test".
Per-variant adaptation:
- default.ts (Claude): full structured sections.
- gpt.ts (GPT-5.x): outcome-first prose, shorter prose per gpt-5.5 guide.
- gemini.ts: explicit enforcement framing + anti-optimism checkpoint
upgraded with a TDD-violation question (#7).
Verified by:
- bun test src/hooks/keyword-detector/ (119 pass / 0 fail).
- lsp_diagnostics clean on all three files.
- Module-load smoke test confirms each exported message string parses
and contains the new section anchors (TDD MANDATORY, SCENARIO
CONTRACT, DURABLE NOTEPAD, REVIEWER GATE).
Char deltas (directive body only):
- default 13646 -> 17144 (+26%)
- gpt 6740 -> 9215 (+37%, was the leanest start)
- gemini 14196 -> 16136 (+14%)
Existing tests only assert presence of "ULTRAWORK MODE ENABLED!" which
is preserved verbatim in every variant.
The lead currently leaves teams alive after the task list drains because
none of the prompt surfaces tell it WHEN to close or HOW. omx-style
'self-closing' behavior was missing for four reasons (diagnosed via
prompt-engineering A/B/C: wrong / misframed / missing):
1. builtin team-mode skill 'Lifecycle' (B+C): 'phase ends / shape
outgrown' is qualitative, so the model maps it to 'wait for user'.
Step 6 jumped to team_delete without the request/approve pair the
tool contract requires. Replaced with a 'Closure Contract' (a
computable predicate over team_task_list + team_status) and an
explicit 'Closure Sequence' (request -> approve -> delete, with
force=true reserved for unrecoverable paths only).
2. TEAM_MESSAGE keyword injection (C): spent 100%% of its one-shot
budget on routing ('do not substitute delegate_task'), 0%% on
closure. Added the same closure rule in compressed form. Kept the
'NEVER substitute with delegate_task' literal that
keyword-detector/index.test.ts depends on.
3. team-mode-status-injector body (C): the only per-session injection
for team mode had no closure obligation. Replaced the optional
'load the team-mode skill ... otherwise use the team_* tools'
sentence with a 'Closure invariant' clause that ties the check to
every team_task_update.
4. member-guidance Wrap-up (A+B): step 3 said 'so the lead can decide
whether to request shutdown', but team_shutdown_request is
lead-only - members cannot initiate it. Step ordering also placed
the completion message before team_task_update, so the lead's
closable check would see stale data. Reordered to
task_update -> check task_list for new work -> if nothing left,
send a single 'closure-ready' message and idle. Test assertion
updated to match the new accurate contract.
Also: stripped Korean alternation from TEAM_PATTERN per directive
('절대로 코드 내에 한국어 적지 마라'). Pattern is now
/\\bteam[\\s_-]?mode\\b/i. Removed 4 Korean test cases
(2 positive triggers + 2 false-positive guards) that the pattern no
longer needs to defend, and updated the keyword-detector AGENTS.md
row.
Net: -71 lines across prompt surfaces. The Closure Contract is the
only addition; everything else tightened.
Tests: 428/428 pass across src/features/team-mode/,
src/features/builtin-skills/, src/hooks/keyword-detector/,
src/hooks/team-mode-status-injector/, src/hooks/team-mailbox-injector/,
src/hooks/team-tool-gating/, src/hooks/team-session-events/.
LSP: no errors introduced (one pre-existing error in
keyword-detector/index.test.ts confirmed pre-existing on dev).