mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
docs(autoplan): unattended contract and reply-unparsed fix move to rec, sealed results, settle and checkpoints (Lane B)
docs/unattended.md: rec/as-is/rec except grammar, --owner-reply and recommend/--rec-hash, unverified pairing and the shared-proposal rule for b, amend_pending and revise --settle, attempt-owned result paths with the sealed .bound.md copy, render --all, and the checkpoint/resume --from paragraph. GATE_REPLY_UNPARSED's fix names rec/as-is (DRIVER.md regenerated). Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
8eba8b322e
commit
46df7eb03f
3 files changed
+46
-33
No files matched your search
+1
-1
@@ -122,7 +122,7 @@ is the completion check. Copy the whole directory, never single files.
|
||||
- `MODEL_FAMILY_CONFLICT`: pass `--model <id>` of a different family (anthropic, openai, google, xai, deepseek, qwen, zai, moonshot, meta, mistral); a same-family result is not an outside voice
|
||||
- `CONSENSUS_MISSING`: resume the run so the phase closes through reconciliation; the Eng prompt is never sent without every prior phase summary
|
||||
- `GATE_REV_STALE`: render the current gate list, read it, and reply with its gate_rev
|
||||
- `GATE_REPLY_UNPARSED`: reply with `all`, `all as-is`, `<id><option>` tokens (for example `d3b uc1a`), or `all except <tokens>`; bare yes/no is ambiguous
|
||||
- `GATE_REPLY_UNPARSED`: reply with `rec`, `as-is`, `<id><option>` tokens (for example `d3b uc1a`), or `rec except <tokens>`; bare yes/no is ambiguous
|
||||
- `GATE_REC_STALE`: render the gate again (`gstack-gate render <dir>/gate.json --all`), relay it, and answer with the printed `--rec-hash`
|
||||
- `OWNER_REPLY_REQUIRED`: pass the owner's words exactly with `--owner-reply "<text>"`, `--owner-reply -` (stdin) or `--owner-reply-file <path>`
|
||||
- `GATE_OWNER_REPLY_MISMATCH`: relay exactly what the owner chose (or their reply itself, e.g. `--reply rec`); ask the owner when their words and the tokens disagree
|
||||
|
||||
+44
-31
@@ -111,14 +111,14 @@ JSON Schema for any of `findings`, `decisions`, `tasks`, `timing`, `run`,
|
||||
3. **List what is pending.**
|
||||
```bash
|
||||
jq -c 'select(.status=="pending")' <dir>/decisions.jsonl
|
||||
gstack-gate render <dir>/gate.json # the numbered list and reply grammar
|
||||
gstack-gate render <dir>/gate.json --all # the numbered list and reply grammar, every page
|
||||
```
|
||||
4. **Answer the gate** by composing the reply grammar (`all`, `<id><option>`
|
||||
tokens such as `d3b uc1a`, or `all except <tokens>`; bare yes/no is
|
||||
rejected) and feeding it back with the gate revision you read:
|
||||
4. **Answer the gate** by composing the reply grammar (`rec`, `as-is`,
|
||||
`<id><option>` tokens such as `d3b uc1a`, or `rec except <tokens>`; bare
|
||||
yes/no is rejected) and feeding it back with the gate revision you read:
|
||||
```bash
|
||||
gstack-gate parse <dir>/gate.json --reply "all except d3b" --gate-rev 1 --json
|
||||
gstack-gate decisions <dir>/gate.json --reply "all except d3b" --gate-rev 1 >> <dir>/decisions.jsonl
|
||||
gstack-gate parse <dir>/gate.json --reply "rec except d3b" --gate-rev 1 --json
|
||||
gstack-gate decisions <dir>/gate.json --reply "rec except d3b" --gate-rev 1 >> <dir>/decisions.jsonl
|
||||
```
|
||||
A stale revision is `GATE_REV_STALE` and a reply with unparsed tokens is
|
||||
`GATE_REPLY_UNPARSED`; both exit `1` and write nothing.
|
||||
@@ -150,8 +150,8 @@ $AP next --out <dir> --plan <plan.md> [--ui|--no-ui] [--developer-tool] [--no-dx
|
||||
# SCOPE: ui=yes (...) dx=yes (detected: ...) source=ui:detected,dx:detected
|
||||
# DRIVER: <root>/autoplan/DRIVER.md
|
||||
# Skipped sections: none (scope: ui=yes,dx=yes,source=ui:detected,dx:detected; checklist=loaded)
|
||||
# ATTEMPT: <run>-a1 phase=ceo voice=native prompt=<dir>/ceo-native-prompt.md result=<dir>/ceo-native.md model_family=...
|
||||
# ATTEMPT: <run>-a2 phase=ceo voice=outside prompt=<dir>/ceo-outside-prompt.md result=<dir>/ceo-outside.md model_family=differs from the native reviewer
|
||||
# ATTEMPT: <run>-a1 phase=ceo voice=native prompt=<dir>/ceo-native-prompt.md result=<dir>/ceo-native.a1.md model_family=...
|
||||
# ATTEMPT: <run>-a2 phase=ceo voice=outside prompt=<dir>/ceo-outside-prompt.md result=<dir>/ceo-outside.a2.md model_family=differs from the native reviewer
|
||||
# SPEND: spent=0.00 reserved=0.00 unknown=0(0.00) worst_case=0.00 cap=none
|
||||
# GSTACK_RESULT: skill=autoplan status=awaiting_result run=<dir>
|
||||
```
|
||||
@@ -173,18 +173,21 @@ the plan.
|
||||
`release --attempt <id>` returns its reservation).
|
||||
2. **Submit each result exactly once.**
|
||||
```bash
|
||||
$AP submit --out <dir> --phase ceo --voice native --result <dir>/ceo-native.md --model <id> --attempt <run>-a1
|
||||
$AP submit --out <dir> --phase ceo --voice outside --result <dir>/ceo-outside.md --model <id> --attempt <run>-a2 [--runner host-subagent] [--usage-usd <n>]
|
||||
$AP submit --out <dir> --phase ceo --voice native --result <dir>/ceo-native.a1.md --model <id> --attempt <run>-a1
|
||||
$AP submit --out <dir> --phase ceo --voice outside --result <dir>/ceo-outside.a2.md --model <id> --attempt <run>-a2 [--runner host-subagent (default)] [--usage-usd <n>]
|
||||
# BOUND: <run>-a1 phase=ceo voice=native model=<id> findings=7 sha256=<result hash prefix>
|
||||
# PHASE_CLOSED: ceo confirmed=4 disagree=1 new=2 native_only=1 coverage=both
|
||||
```
|
||||
Submit seals the bytes it bound as `<phase>-<voice>.<attempt>.bound.md`
|
||||
(read-only); a later write to the reviewer's file changes nothing bound,
|
||||
and another attempt's result file is refused (`ATTEMPT_MISMATCH`).
|
||||
Binding checks the receipt line against the phase snapshot
|
||||
(`RESULT_RECEIPT_MISSING`), parses the canonical findings fence
|
||||
(`RESULT_FINDINGS_MISSING`), refuses an outside model from the native
|
||||
family (`MODEL_FAMILY_CONFLICT`), and refuses a second bind of the same
|
||||
attempt or a bind while the phase is not awaiting it (`ATTEMPT_MISMATCH`,
|
||||
`PHASE_NOT_AWAITING`, exit 3). Both voices in closes the phase: the
|
||||
reconciliation (`confirmed` / `disagree` / `new` per outside finding, with
|
||||
reconciliation (`confirmed` / `unverified` / `disagree` / `new` per outside finding, with
|
||||
disagreement and resolution kept separate) is written to
|
||||
`<phase>-consensus.{json,md}`, and every later phase's prompts (DX, design
|
||||
and Eng alike) carry each closed predecessor's consensus as data; a phase
|
||||
@@ -194,40 +197,50 @@ the plan.
|
||||
disagreements as auto items and `p1` plan approval; nothing is approved.
|
||||
4. **Answer the gate** with the reply grammar and the revision you read:
|
||||
```bash
|
||||
$AP answer --out <dir> --gate-rev 1 --reply "all" --by human # every recommendation the owner may delegate; agreeing plan changes stay pending
|
||||
$AP answer --out <dir> --gate-rev 1 --reply "all as-is" --by human # APPROVED: keeps every direction, no new paid phase
|
||||
$AP answer --out <dir> --gate-rev 1 --reply "all except d1b" --by human # APPLY: <id> ...; REOPENED: ceo,eng; NEXT: gstack-autoplan revise ...
|
||||
$AP answer --out <dir> --gate-rev 1 --reply "rec" --by human # every recommendation, plan changes included (APPLY: ...; amend_pending)
|
||||
$AP answer --out <dir> --gate-rev 1 --reply "as-is" --by human # APPROVED: keeps every direction, no new paid phase
|
||||
$AP answer --out <dir> --gate-rev 1 --reply "rec except d1b" --by agent:<id> --owner-reply "<owner's words>"
|
||||
```
|
||||
`--by human` means the owner typed the tokens; `--by agent:<thread or id>`
|
||||
means an agent relayed or decided them. An unattended run refuses an answer
|
||||
without it (`ANSWER_BY_REQUIRED`, exit 3) and records the value as
|
||||
means an agent relayed them, and then `--owner-reply` (or `-` for stdin,
|
||||
`--owner-reply-file <path>`) stores the owner's words verbatim
|
||||
(`OWNER_REPLY_REQUIRED`); owner words that parse to different choices are
|
||||
refused (`GATE_OWNER_REPLY_MISMATCH`). An unattended run refuses an answer
|
||||
without `--by` (`ANSWER_BY_REQUIRED`, exit 3) and records the value as
|
||||
`answered_by` on every decision row and in the review record's gate line,
|
||||
so a gate an agent closed is distinguishable from one the owner closed.
|
||||
A user challenge both voices raised on a confirmed finding with the same
|
||||
`changes` value is recommended as `b`, and option b shows both voices'
|
||||
remedies (`recommended: b (both voices; remedies shown)`); a `--reconcile`
|
||||
record naming one shared `proposal` shows that instead. Disagreeing or
|
||||
missing remedies keep `a`. `all` never answers an item recommended `b`:
|
||||
that would change the owner's stated direction on their behalf, so those
|
||||
items stay pending (`GATE_PENDING: uc1 unanswered (reply with uc1a|uc1b; all
|
||||
does not answer items recommended b)`) until their own token arrives, and
|
||||
the rendered gate names them under the reply grammar. Every accepted plan change prints
|
||||
`gstack-autoplan recommend` changes one recommendation before relay; it
|
||||
bumps the gate's `rec_rev`, and a later `rec` needs the `--rec-hash` from
|
||||
the render the owner saw (`GATE_REC_STALE`).
|
||||
A user challenge both voices raised on a confirmed finding (a title match,
|
||||
not file:line proximity alone, which is `unverified`) with the same
|
||||
`changes` value is recommended as `b` only with one shared proposal: a
|
||||
`--reconcile` record naming it, or the same remedy from both voices.
|
||||
Different or missing remedies keep `a`, and option b shows both verbatim
|
||||
with the basis. `rec` (alias `all`) takes every recommendation, so it
|
||||
accepts the items recommended `b`. Every accepted plan change prints
|
||||
`APPLY: <decision id> <title> -> <chosen text>` and becomes a pending
|
||||
amendment: `next` refuses with `PLAN_AMEND_PENDING` and `export` refuses a
|
||||
`complete` run until `revise --incorporates` names it (see below).
|
||||
`complete` run until `revise --incorporates` names it, or `revise --settle
|
||||
<id>` settles a packaging or ordering change that needs no plan edit.
|
||||
A stale revision (`GATE_REV_STALE`, exit 3), bare `yes`/`no`, or a
|
||||
conflicting reply (`GATE_REPLY_UNPARSED`) writes nothing. A reply that
|
||||
leaves approval items pending records only the answered auto items and
|
||||
keeps the gate; a later reply never overwrites an earlier answer. A choice
|
||||
that changes the plan reopens that phase plus Eng, archives their bound
|
||||
files as `*.r<rev>.*`, and the next gate is `gate_rev + 1`; `p1d` reruns
|
||||
every phase on the current plan; `p1e` ends `incomplete`.
|
||||
keeps the gate; a later reply never overwrites an earlier answer. An
|
||||
accepted change reopens nothing at answer (status `amend_pending`); `revise`
|
||||
reopens each phase whose reviewed plan changed plus Eng, archives their
|
||||
prompts and consensus as `*.r<rev>.*` (sealed `*.bound.md` results stay in
|
||||
place), and the next gate is `gate_rev + 1`; `p1d` reruns every phase on the
|
||||
current plan; `p1e` ends `incomplete`.
|
||||
5. **Export and validate.** `$AP export --out <dir>` writes `plan.md` (with
|
||||
the `## URGENT, outside this plan` block first), `review-record.md`,
|
||||
`tasks.jsonl`, `decisions.jsonl`, `findings.jsonl`, `timing.json` and
|
||||
`run.json`; then `gstack-artifact validate <dir>/run.json` and the
|
||||
consumption steps above apply unchanged. `$AP status --out <dir>` and
|
||||
`resume` work after the run directory moves (paths are re-rooted).
|
||||
`resume` work after the run directory moves (paths are re-rooted; journal
|
||||
paths are run-relative). With `GSTACK_AUTOPLAN_CHECKPOINT_DIR` set, a run
|
||||
at rest is copied, hash-listed, to `<dir>/<run>/`; `$AP resume --out <new
|
||||
dir> --from <dir>/<run>` verifies and restores it (`CHECKPOINT_INVALID`).
|
||||
|
||||
Concurrency and recovery: every state write is a locked read-modify-write
|
||||
(`run.lock`; a second writer sees `RUN_LOCKED`), attempts are journaled to
|
||||
|
||||
+1
-1
@@ -112,7 +112,7 @@ export const RESULT_CODES = {
|
||||
GATE_REPLY_UNPARSED: {
|
||||
anchor: 'gate-reply-unparsed',
|
||||
summary: 'part of the reply matched no gate item or option, so nothing was applied',
|
||||
fix: 'reply with `all`, `all as-is`, `<id><option>` tokens (for example `d3b uc1a`), or `all except <tokens>`; bare yes/no is ambiguous',
|
||||
fix: 'reply with `rec`, `as-is`, `<id><option>` tokens (for example `d3b uc1a`), or `rec except <tokens>`; bare yes/no is ambiguous',
|
||||
},
|
||||
ANSWER_BY_REQUIRED: {
|
||||
anchor: 'answer-by-required',
|
||||
|
||||
Reference in new issue
Block a user