feat(intent): /trekplan halts without an approved intent; the approval is stamped on both paths
Veikart steg 1, økt 1 av 2. The three holes measured in the grounds: (1) ## Intent / ## Goal were only checked for existence, (2) no approval marker existed, (3) brief-approved was emitted only on the auto path. - lib/validators/intent-approval.mjs: --check / --stamp. The marker is intent_approved_hash (sha256 over normalized ## Intent + ## Goal) + intent_approved_at. Editing either section after approval → STALE. - /trekplan Phase 1 (Read the brief, both --brief and --project): runs --check and HALTS on BRIEF_INTENT_NOT_APPROVED / _STALE / _INVALID with the remedy spelled out; an unrunnable check halts too. - /trekbrief Phase 4h (before the Phase 5 fork, asked even in --quick): shows Intent + Goal verbatim, AskUserQuestion Approve / Revise / Leave; only "Approve" runs --stamp. --stamp emits brief-approved, so the manual (default) path records it; the auto path's own emission is removed. New mode /trekbrief --approve <project-dir> = Phase 4h alone. - README, CLAUDE.md, command-modes, HANDOVER-CONTRACTS §Handover 1, jsonl-schemas (trekbrief-stats gains intent_approved). Valgt ingen brief_version-bump fordi skjemaendringen er rent additiv (to valgfrie felt) og kravet sitter i /trekplan — enhver produsents brief kan godkjennes via /trekbrief --approve uten produsentendring. Valgt eget --check-kall i stedet for et flagg på brief-validator fordi --brief-stien i dag ikke kjører validatoren i det hele tatt; et nytt validatorkall der ville også stoppe på andre feil. Valgt fallback-datamappe = målestokkens (plugins/data/voyage-…) fordi CLAUDE_PLUGIN_DATA er tom i Bash-miljøet og event-emits egen fallback er stille skip — slik ble brief-approved 0 records. What the marker does NOT prove (module header, command prose, contract): same user, same machine — any session can stamp. A trace, not a signature. Suite 1183 → 1201 (1199/0/2). Mutants M1–M5 (stale check off, check always valid, gate line removed, stamp emits nothing, no normalization) each fell ≥ 1 test. yardstick unchanged: RED, 1 of 3 countable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f39e7ccf39
commit
f5dc08f660
9 changed files with 315 additions and 14 deletions
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
name: trekbrief
|
||||
description: Interactive interview that produces a task brief with explicit research plan. Feeds /trekresearch and /trekplan. Optionally orchestrates the full pipeline end-to-end.
|
||||
argument-hint: "[--quick] <task description>"
|
||||
argument-hint: "[--quick] <task description> | --approve <project-dir>"
|
||||
allowed-tools: Agent, Read, Glob, Grep, Write, Edit, Bash, AskUserQuestion
|
||||
---
|
||||
|
||||
|
|
@ -51,15 +51,25 @@ Parse `$ARGUMENTS`:
|
|||
by the autonomy-gate state machine via the CLI shim:
|
||||
`node ${CLAUDE_PLUGIN_ROOT}/lib/util/autonomy-gate.mjs --state X --event Y --gates {true|false}`.
|
||||
|
||||
If no task description is provided, output usage and stop:
|
||||
4. `--approve <project-dir>`: set **mode = approve**. No interview, no
|
||||
drafting. Set `PROJECT_DIR = <project-dir>` (trim trailing slash). If
|
||||
`{PROJECT_DIR}/brief.md` does not exist, print
|
||||
`Error: no brief at {PROJECT_DIR}/brief.md — run /trekbrief first.` and stop.
|
||||
Otherwise jump straight to **Phase 4h**, run it, print its report, and
|
||||
stop. This is the remedy `/trekplan` names when it halts on an unapproved
|
||||
or stale intent.
|
||||
|
||||
If no task description is provided (and mode is not approve), output usage and stop:
|
||||
|
||||
```
|
||||
Usage: /trekbrief <task description>
|
||||
/trekbrief --quick <task description>
|
||||
/trekbrief --approve <project-dir>
|
||||
|
||||
Modes:
|
||||
default Dynamic interview until quality gates pass — brief with research plan
|
||||
--quick Compact start; still escalates on weak sections — brief with research plan
|
||||
--approve Approve an existing brief's ## Intent + ## Goal so /trekplan will plan it
|
||||
|
||||
Examples:
|
||||
/trekbrief Add user authentication with JWT tokens
|
||||
|
|
@ -723,6 +733,52 @@ the tab and reopen the same file.
|
|||
────────────────────────────────────────────────────────────────────
|
||||
```
|
||||
|
||||
## Phase 4h — Intent approval (veikart steg 1)
|
||||
|
||||
`/trekplan` does not plan against an intent the operator has not approved
|
||||
(it halts on `BRIEF_INTENT_NOT_APPROVED`). This phase is where that approval
|
||||
is given. It runs on EVERY brief, before the Phase 5 manual/auto fork, so
|
||||
both paths pass through it — and it is **asked even in `--quick` mode**; there
|
||||
is no skip path and no default answer.
|
||||
|
||||
1. Show the operator the `## Intent` and `## Goal` sections of
|
||||
`{PROJECT_DIR}/brief.md` **verbatim** — the exact text the approval will
|
||||
bind to. Do not summarize them.
|
||||
2. Ask via `AskUserQuestion` — one question:
|
||||
**"Is this the intent /trekplan should plan against?"**
|
||||
|
||||
| Option | Effect |
|
||||
|--------|--------|
|
||||
| **Approve** | Stamp the brief (step 3). |
|
||||
| **Revise first** | The operator states the change; edit `## Intent` / `## Goal` in `brief.md`, re-run the Phase 4g validator, then return to step 1. |
|
||||
| **Leave unapproved** | Write nothing. `/trekplan` will halt on this brief until `/trekbrief --approve {PROJECT_DIR}` is run. |
|
||||
|
||||
3. **Only on an explicit "Approve"** — never inferred from silence, from an
|
||||
earlier answer, or from a "looks good" in free text — run:
|
||||
|
||||
```bash
|
||||
node ${CLAUDE_PLUGIN_ROOT}/lib/validators/intent-approval.mjs --stamp "{PROJECT_DIR}/brief.md"
|
||||
```
|
||||
|
||||
This writes `intent_approved_hash` (sha256 over the normalized `## Intent`
|
||||
+ `## Goal`) and `intent_approved_at` into the frontmatter, and emits the
|
||||
`brief-approved` lifecycle event. It prints JSON; if `stamped` is `false`
|
||||
(e.g. `## Goal` is empty), report the `reason` and return to step 1. Editing
|
||||
`## Intent` or `## Goal` afterwards makes the approval stale — `/trekplan`
|
||||
halts until the operator approves the new text.
|
||||
|
||||
What the stamp does NOT prove: any session on this machine could run the
|
||||
same command. It is a trace that this step ran against this text, not the
|
||||
operator's signature (see the header of `lib/validators/intent-approval.mjs`).
|
||||
|
||||
Report:
|
||||
```
|
||||
Intent: {approved (sha256:…12 hex) | left unapproved — /trekplan will halt}
|
||||
```
|
||||
|
||||
In `--approve` mode, stop after the report and print the next step:
|
||||
`/trekplan --project {PROJECT_DIR}` (only if approved).
|
||||
|
||||
## Phase 5 — Auto-orchestration opt-in (if research_topics > 0)
|
||||
|
||||
**Skip this phase if research_topics = 0.** Proceed directly to Phase 6.
|
||||
|
|
@ -763,16 +819,14 @@ Stop. Do not continue to Phase 6.
|
|||
|
||||
### Auto path
|
||||
|
||||
**Auto requires an approved intent.** If Phase 4h ended "Leave unapproved",
|
||||
the auto chain would halt at `/trekplan` anyway — print the manual-path
|
||||
output instead and stop.
|
||||
|
||||
Set `auto_research: true` in the brief's frontmatter (edit the file).
|
||||
|
||||
Emit the brief-approved lifecycle event so downstream observability sees
|
||||
the pipeline kick off (consumed by `lib/stats/event-emit.mjs`):
|
||||
|
||||
```bash
|
||||
node ${CLAUDE_PLUGIN_ROOT}/lib/stats/event-emit.mjs \
|
||||
--event brief-approved \
|
||||
--payload "{\"project\":\"${PROJECT_DIR}\"}"
|
||||
```
|
||||
The `brief-approved` lifecycle event was already emitted by the Phase 4h
|
||||
stamp — on both paths — so it is not emitted again here.
|
||||
|
||||
If `gates_mode == true`: pause here via `AskUserQuestion` —
|
||||
"Auto-mode confirmed. Proceed to research now? (yes/no)". If the user
|
||||
|
|
@ -902,10 +956,14 @@ Append one record to `${CLAUDE_PLUGIN_DATA}/trekbrief-stats.jsonl`:
|
|||
"research_topics": {N},
|
||||
"auto_research": {true | false},
|
||||
"auto_result": "{completed | cancelled | failed | manual}",
|
||||
"intent_approved": {true | false},
|
||||
"project_dir": "{path}"
|
||||
}
|
||||
```
|
||||
|
||||
`intent_approved` is `true` only when Phase 4h ran the stamp (the operator
|
||||
answered "Approve").
|
||||
|
||||
If `${CLAUDE_PLUGIN_DATA}` is not set or not writable, skip silently.
|
||||
Never let stats failures block the workflow.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue