# Manual Smoke Test Guide

Manual verification of the NL→DSL meta-prompt pipeline and skill-aware prompt wrapping in Claude Code and Codex.

## Prerequisites

1. **Build the plugin**:

   ```sh
   npm run build
   ```

2. **Install the plugin in Claude Code**:

   ```sh
   node bin/cli.mjs install
   ```

3. **Clean state** (remove any leftover session):

   ```sh
   rm -rf .prompt-language/
   ```

4. **Optional Codex scaffold**:

   ```sh
   node bin/cli.mjs codex-install
   ```

## Test Cases

## NL Meta-Prompt Cases

### Case 1: Basic until loop

- **Input**: `Run tests, keep fixing until they pass, max 5 tries`
- **Expected**: Claude responds with a valid `flow:` block containing an `until` node
- **Verify**: The response contains `Goal:`, `flow:`, `until`, and `end`
- [ ] PASS / FAIL

### Case 2: Retry pattern

- **Input**: `Retry the build up to 3 times`
- **Expected**: Claude responds with a `flow:` block containing a `retry max 3` node
- **Verify**: Response contains `retry` and `max 3`
- [ ] PASS / FAIL

### Case 3: If/else conditional

- **Input**: `If tests fail fix them, otherwise move on`
- **Expected**: Claude responds with a `flow:` block containing `if`/`else` branches
- **Verify**: Response contains `if`, `else`, and `end`
- [ ] PASS / FAIL

### Case 4: Try/catch with fallback

- **Input**: `Try running deploy. If it fails, roll back.`
- **Expected**: Claude responds with a `flow:` block containing `try`/`catch`
- **Verify**: Response contains `try`, `catch`, and `end`
- [ ] PASS / FAIL

### Case 5: While loop

- **Input**: `While tests fail, fix them and rerun. Max 3.`
- **Expected**: Claude responds with a `flow:` block containing a `while` node
- **Verify**: Response contains `while`, `max 3`, and `end`
- [ ] PASS / FAIL

### Case 6: Complex multi-step flow

- **Input**: `Run tests. If fail, fix. Then lint. Keep going until both pass.`
- **Expected**: Claude responds with a multi-node `flow:` block (possibly `until` wrapping multiple steps)
- **Verify**: Response contains `Goal:`, `flow:`, and multiple node types
- [ ] PASS / FAIL

### Case 7: Plain prompt (negative test)

- **Input**: `What is the capital of France?`
- **Expected**: Prompt passes through unchanged — no meta-prompt injection, no DSL
- **Verify**: Claude answers the question normally without any `[prompt-language]` prefix
- [ ] PASS / FAIL

### Case 8: Meta-prompt disabled globally

- **Setup**: run Claude or Codex with `PROMPT_LANGUAGE_META_PROMPT=0`
- **Input**: `Run tests, keep fixing until they pass, max 5 tries`
- **Expected**: Prompt passes through unchanged
- **Verify**: No confirmation prompt is injected and `.prompt-language/` does not record a pending NL prompt
- [ ] PASS / FAIL

### Case 9: Claude-only disable, Codex still enabled

- **Setup**: set `PROMPT_LANGUAGE_CLAUDE_META_PROMPT=0` and leave Codex unset
- **Input**: `Retry the build up to 3 times`
- **Expected**: Claude passes the prompt through, Codex still shows the confirmation/meta-prompt path
- **Verify**: Claude has no injected confirmation; Codex still emits the `[prompt-language]` control-flow-intent message
- [ ] PASS / FAIL

### Case 10: Already-valid DSL

- **Input**:

  ```
  Goal: Run tests

  flow:
    run: npm test

  done when:
    tests_pass
  ```

- **Expected**: DSL is parsed directly. Session state is created. Context block is injected.
- **Verify**: Response shows `[prompt-language] Active flow: Run tests` context, not a meta-prompt
- [ ] PASS / FAIL

### Case 11: Active flow + new NL input

- **Setup**: First run Case 8 to create an active flow
- **Input**: `Now fix the linting errors`
- **Expected**: Flow context is injected (showing active flow info), not a meta-prompt
- **Verify**: Response includes `[prompt-language] Active flow:` and `Status: active`
- [ ] PASS / FAIL

### Case 12: Gate enforcement

- **Setup**: Start a flow with `done when:` gates (e.g., Case 8)
- **Input**: Try to end the conversation or start a new unrelated task
- **Expected**: The agent should respect completion gates — it should not claim the flow is complete until gates are satisfied
- **Verify**: Agent continues working toward gate satisfaction rather than stopping early
- [ ] PASS / FAIL

## Skill Wrapper Cases

### Case 13: Skill-aware prompt wrapper on

- **Setup**: leave `PROMPT_LANGUAGE_SKILL_PROMPT_WRAPPER` unset
- **Input**: run a prompt-turn path that should use an installed repo skill or literal flow text
- **Expected**: the harness prompt envelope tells the runner to use relevant installed skills and preserve embedded prompt-language DSL literally
- **Verify**: inspect the prompt-runner tests or harness debug output and confirm the wrapper text is present
- [ ] PASS / FAIL

### Case 14: Skill-aware prompt wrapper off

- **Setup**: set `PROMPT_LANGUAGE_SKILL_PROMPT_WRAPPER=0`
- **Input**: rerun the same prompt-turn path
- **Expected**: the raw prompt is forwarded without the wrapper preamble
- **Verify**: harness debug output or runner instrumentation shows the plain prompt only
- [ ] PASS / FAIL

## Troubleshooting

### State file location

Session state is stored in `.prompt-language/session-state.json` relative to the working directory.

### Reset state

To clear the current flow and start fresh:

```sh
rm -rf .prompt-language/
```

### Debug: inspect hook output

Pipe input directly to the hook to see what it produces:

```sh
echo '{"prompt":"Run tests until they pass, max 5"}' | npx tsx src/presentation/hooks/user-prompt-submit.ts
```

Codex variant:

```sh
echo '{"prompt":"Run tests until they pass, max 5"}' | npx tsx src/presentation/hooks/codex-user-prompt-submit.ts
```

### Debug: verify stdin fail-open behavior

If you want to confirm the hook will not hang when a host keeps stdin open, run the focused regression tests:

```sh
npx vitest run src/presentation/hooks/read-stdin.test.ts src/presentation/hooks/hook-robustness.test.ts
```

The important behavior is:

- partial stdin is returned after a short idle timeout even without EOF
- empty still-open stdin resolves to `""`
- hook launcher failures show the real timeout/subprocess error instead of a generic shell status

### Debug: check if NL detection triggers

The hook detects NL intent using keyword matching. If a prompt is not being detected as NL:

1. Check the `NL_INTENT_WORDS` list in `src/application/inject-context.ts`
2. Run the hook manually (see above) and inspect the output

### Common issues

- **No meta-prompt injected for NL input**: The input may not match enough NL intent keywords, or `PROMPT_LANGUAGE_META_PROMPT` / the harness-specific override may be disabled.
- **Meta-prompt injected for plain text**: A keyword like "passes", "fails", or "until" may be triggering false positives.
- **Skill-aware wrapper missing**: Check `PROMPT_LANGUAGE_SKILL_PROMPT_WRAPPER` and the harness-specific override.
- **State file not created after DSL input**: Ensure the working directory is writable and not inside a read-only mount.
- **Hook appears idle or hung**: Hook stdin reads now fail open after a short idle timeout, so a still-open stdin stream should resolve to partial input or `""` rather than hanging forever. If the hook still fails, check stderr for the real subprocess or timeout message.
- **Hook errors silently**: The hook catches errors and exits 0 to avoid blocking the user. Check stderr for `[prompt-language] hook error:` messages.
