diff --git a/README.md b/README.md index 760238e8d..73252a4fd 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,7 @@ Three ways in — pick one: | --- | --- | --- | | 🧭 **Guided onboarding** | `/aidd-context:00-onboard` | First time, or unsure what to run — it inspects the project and routes you. | | 🧠 **Project memory** | `/aidd-context:02-project-memory` | Build the project memory bank by hand. | -| ⚙️ **Feature flow** | `/aidd-orchestrator:01-sdlc` | Autonomously ship a feature end to end (frame → deliver → check → PR). | +| ⚙️ **Feature flow** | `/aidd-orchestrator:01-sdlc` | Ship a feature end to end, autonomous by default or supervised with `interactive` (frame → deliver → check → PR). | The full loop, and how onboarding sets it up: diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/brainstorm.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/brainstorm.md new file mode 100644 index 000000000..f70e6682d --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/brainstorm.md @@ -0,0 +1,82 @@ +# SDLC : rendre le mode `interactive` à l'orchestrateur + +Le SDLC va aujourd'hui du besoin à la pull request sans jamais s'arrêter. Avant un refactor il +avait un mode `interactive` par défaut et `auto` sur demande ; le refactor a gardé l'autonomie et +jeté le reste. On veut l'inverse de l'ancien réglage : autonome par défaut, `interactive` sur +demande. Pour quelqu'un qui lance une vraie livraison et veut valider le contrat, la spec et le +plan avant que ça parte, mais qui n'a aucune envie d'arbitrer chaque agent lancé. + +La bascule qui évite la sur-ingénierie : on ne s'arrête pas à chaque délégation, on s'arrête là où +un artefact corrigible vient d'être produit. Quatre points, pas dix. Et ces quatre points sont un +seul comportement de l'orchestrateur, pas quatre mécaniques : aucune des étapes appelées ne change. + +## Ce qui est clair + +- Le mot est `interactive`, jamais `manual`. Il est déjà employé par `aidd-vcs:01-commit:29`, + `aidd-dev:01-plan/actions/04-plan.md:29`, `aidd-context:04-skill-generate/references/scope-frame.md:9` + et `aidd-orchestrator:02-backlog/references/modes.md:5`. Un `manual` serait le doublon que + `CLAUDE.md` interdit. +- Mot à l'invocation, rien de persisté : `` seul, ou `auto <...>`, ou + `interactive <...>`. Le frontmatter devient `argument-hint: request | auto | interactive`. +- Quatre arrêts en `interactive` : le contrat, la spec, le plan, le verdict. +- Aucune skill appelée ne change. `01-plan` lit déjà le contexte et bascule seul dès que + l'orchestrateur cesse de se déclarer autonome (`04-plan.md:29`). `04-spec` n'a pas de branche + interactive, donc son arrêt appartient à l'orchestrateur, qui s'arrête quand la spec lui revient. +- La boucle implement, assert, review, challenge tourne seule dans les deux modes. +- Un refus à un arrêt est un finding. `03-check.md` sait déjà renvoyer un finding vers Frame ou + vers Deliver et repasser ; le refus humain emprunte ces chemins au lieu d'en créer. +- Le commit reste local en fin de Deliver, à chaque passage. Le push part une seule fois, après un + verdict propre, dans les deux modes. Règle unique : le travail ne sort de la machine que validé, + que le validateur soit humain ou autonome. +- Le push revient à `aidd-vcs:02-pull-request`. Une PR sur une branche absente du remote est + impossible : cette skill a toujours eu cette précondition, tenue jusqu'ici par accident de + séquence. Son « Never commit, push, or branch here » devient « Never commit or branch here », + plus une ligne qui pousse la branche quand le remote ne l'a pas, jamais en `--force`. +- Ce n'est pas un choix de confort : la recette livrée `ship-a-feature.md` enchaîne + `/aidd-vcs:01-commit` puis `/aidd-vcs:02-pull-request` sans option `push`, et + `02-pull-request/actions/03-create.md` ouvre la PR sans jamais vérifier que la head existe sur + le remote. Aucune étape de la recette ne pousse, et rien dans le texte de la skill ne tient + cette précondition : elle repose entièrement sur ce que fait l'outil configuré, ce qui tient + ou casse selon qu'il est interactif ou non. Donner le push à la skill PR ferme ce trou. +- Garde-fou à ajouter en plus, pas à la place : `01-collect` vérifie que la head est sur le remote + et échoue clairement sinon. + +## Ce qui reste ouvert + +- Le déplacement du push est la seule décision de ce brief qui ne sert pas le mode interactif. + Elle vient d'une règle voulue explicitement : le travail ne sort de la machine que validé, que + le validateur soit humain ou autonome. Elle change donc aussi le mode auto, pour tout le monde, + et c'est le seul changement dont le périmètre dépasse `01-sdlc`. +- Reculer le push coûte la sauvegarde hors machine pendant tout Check, qui peut reboucler + plusieurs fois vers Deliver. Le travail est committé, donc rien n'est perdu ; ce qu'on perd est + la visibilité et la copie distante. Prix jugé acceptable, à écrire dans la référence plutôt qu'à + redécouvrir plus tard. +- La description du skill ouvre sur « Autonomously orchestrates », faux dès qu'un second mode + existe. Formulation à trouver. `CATALOG.md` et `README.md` en sont générés par hook et suivront, + et le frontmatter est contrôlé au pre-commit, donc `argument-hint` n'est pas décoratif. +- `aidd-context:00-onboard/references/run/tiers.md:12` affirme « `01-sdlc` is autonomous by + contract; do not downgrade it to `GUIDED` », à réconcilier. Et `flow.md:27` propose déjà + « walk with me, step by step » contre « hand the whole flow to sdlc » : les deux branches se + recouvrent en partie une fois `interactive` disponible. +- Reste à décider si les points d'arrêt s'écrivent une fois, en règle transversale du `SKILL.md`, + ou zone par zone dans les trois références. + +## Périmètre attendu + +| Fichier | Change | +| --- | --- | +| `plugins/aidd-orchestrator/skills/01-sdlc/SKILL.md` | le mode, l'`argument-hint`, la description | +| `plugins/aidd-orchestrator/skills/01-sdlc/references/02-deliver.md` | le commit ne pousse plus | +| `plugins/aidd-orchestrator/skills/01-sdlc/references/03-check.md` | le push après un verdict propre | +| `plugins/aidd-vcs/skills/02-pull-request/SKILL.md` | le push, et sa vérification dans `01-collect` | +| `01-plan`, `04-spec`, `01-commit` | rien | + +Les deux références changent pour le déplacement du push, qui est tranché. Où s'écrivent les +points d'arrêt, dans le `SKILL.md` ou dans chaque référence, reste ouvert et peut élargir ce +tableau. + +## Prochain pas + +Écrire la phrase de mode dans le `SKILL.md` du SDLC, puisque c'est elle qui fait basculer les +étapes appelées sans les toucher, et vérifier sur un run réel que `01-plan` prend bien sa branche +interactive quand l'orchestrateur ne se déclare plus autonome. diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/case-matrix.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/case-matrix.md new file mode 100644 index 000000000..b4d2467b7 --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/case-matrix.md @@ -0,0 +1,122 @@ +# Case matrix + +Every decision edge the orchestration declares, and the run that exercised it. Derived by reading the router and its three zone references end to end, not by recalling what was tested. + +The runs named here are this campaign's. The later batch, on the text as it stands, is in `w-batch.md`. + +Legend: `done` an observed run covered it · `flight` a run is covering it · `gap` nothing covers it yet · `n/a` unreachable in a sandbox. + +## Router, mode selection + +| # | Edge | State | +| --- | --- | --- | +| R1 | no mode word, so `auto` | done | +| R2 | `auto` beside the source names the default | done | +| R3 | `interactive` beside the source | done | +| R4 | the word inside the source's own text selects nothing | done | +| R4b | first word is literally the mode word, nothing beside it | done | +| R4c | both words passed, case variants, a leading dash, trailing position | done | + +## Router, autonomous behaviour + +| # | Edge | State | +| --- | --- | --- | +| R5 | `auto` stops only for money, an irreversible action, or user authority | done | +| R6 | a delegated step decides without asking | done | + +## Router, pauses + +| # | Edge | State | +| --- | --- | --- | +| R7 | pause on the contract | done | +| R8 | pause on the plan | done | +| R9 | pause on the outcome, before the request | done | +| R10 | `interactive` dispatch limited to producers of those three, clarifying and formalizing included | done | +| R11 | every other step dispatched in `auto` | done | +| R12 | a spec is how Frame formalizes the contract, never a fourth artifact | done | +| R13 | a dispatched step asks and waits as its own instructions say | done | +| R14 | a step that ends without waiting, so the orchestrator waits on its result | done | +| R15 | pause again on an artifact produced anew | done | + +## Router, refusals + +| # | Edge | State | +| --- | --- | --- | +| R16 | a refusal is a finding against the artifact | done | +| R17a | a refused spec goes to Frame | done | +| R17b | a refused contract goes to Frame | done | +| R18 | a refused plan goes to Deliver | done | +| R19a | a refused outcome goes to Deliver | done | +| R19b | a refused outcome goes to Frame when it changes what is built | done | +| R20 | nothing bounds the loop but the user | done | + +## Router, discipline + +| # | Edge | State | +| --- | --- | --- | +| R21 | read only the current zone reference | done | +| R22 | verify a provider is installed before calling it | done | +| R23 | spawn specialized agents for isolated work | done | +| R24 | parallelize independent work | done | +| R25 | repeat the responsible zone on an actionable gap | done | +| R26 | the step-end marker only once the draft request exists | done | + +## Frame + +| # | Edge | State | +| --- | --- | --- | +| F1 | the source references a ticket, so resolve it | done | +| F2 | no ticket, so the source as provided | done | +| F3 | planning-ready, so straight to the contract | done | +| F4 | intent can change what is built, so clarify | done | +| F5 | only contract requirements missing, so formalize | done | +| F6 | clarifying feeds formalizing | done | +| F7 | formalizing yields the contract | done | +| F8 | a resolved ticket is declared in the delivery folder | done | +| F9 | no ticket, so nothing is declared | done | + +## Deliver + +| # | Edge | State | +| --- | --- | --- | +| D1 | the contract becomes a proportional plan | done | +| D2 | the plan goes to one executor | done | +| D3 | implementing feeds asserting | done | +| D4 | architecture conformance whenever the project documents architecture | done | +| D5 | no journey required, so commit | done | +| D6 | a journey is required, so run it last | done | +| D7 | the journey succeeds, so commit | done | +| D8 | the journey fails, so back to the executor | done | +| D9 | commit the validated work | done | +| D10 | only a clean committed candidate reaches Check | done | +| D11 | the assert repair loop iterates until it passes | done | +| D12 | a blocking condition sets the plan blocked and stops | done | +| D13 | any mismatch with the plan reports a replan | done | +| D14 | the tree is never dirty at a phase boundary | done | + +## Check + +| # | Edge | State | +| --- | --- | --- | +| C1 | one fresh checker, independent from implementation | done | +| C2 | the review clears, so challenge the outcome | done | +| C3 | the review returns actionable findings | done | +| C4 | the outcome is trustworthy, so open the draft request | done | +| C5 | the challenge returns actionable findings | done | +| C6 | product or contract findings become the next Frame source | done | +| C7 | independent implementation findings go through Todo | done | +| C8 | dependent repairs stay together in Deliver | done | +| C9 | Todo feeds Deliver | done | +| C10 | Check is re-entered after every new candidate | done | +| C11 | the request opens only when nothing is actionable | done | + +## The six edges an earlier harness could not reach + +Each was unreachable because of a constraint the harness imposed, not because of anything the orchestration does. Three further sandboxes lift those constraints. + +| Edge | Constraint that hid it | How it is lifted | +| --- | --- | --- | +| `R23`, `C1` | subagents forbidden, so the orchestrator stayed observable and the checker was never independent | one sandbox requires spawning: delivery to one agent, review to a fresh one fed only the inputs the Check reference names | +| `C4`, `C11`, `R26` | no remote and no forge, so the request never opened and the step-end marker never fired | one sandbox carries a real bare remote with `main` already pushed, and a `gh` that answers `pr create` while logging every call | +| `R5` | no real cost and nothing irreversible | one sandbox declares a metered API with no free tier and a key it does not hold, and a module three external consumers depend on | +| `R24` | read as a performance clause rather than a behaviour | the same sandbox asks for three helpers that share nothing, with fan-out permitted | diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/codex-run.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/codex-run.md new file mode 100644 index 000000000..99d49e661 --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/codex-run.md @@ -0,0 +1,172 @@ +# Codex run — the interactive gates, with a human at them + +The three gates were never executed. A headless run cannot answer them: it would +have to invent the approval the gate exists to collect. This run puts a person +there, under a second AI tool, so what is measured is the text and not Claude +Code's own habits. + +## What is already in place + +| Piece | Where | +| ----- | ----- | +| Working copy for the delivery | `../test-sdlc-891-codex`, branch `fix/cli-setup-user-scope-plugins`, cut from `origin/next` | +| The issue to deliver | #891, `fix(cli): setup --scope user --plugins throws an uncaught UserScopePluginModeError instead of rendering a validation error` | +| The orchestration Codex will read | the shared build, rebuilt from this branch | + +The shared build was rebuilt with: + +```shell +aidd setup --ai codex --source local \ + --path /Users/baptistelafourcade/orca/workspaces/framework/fix-sdlc-manual \ + --plugins aidd-context,aidd-orchestrator,aidd-dev,aidd-pm,aidd-refine,aidd-vcs --yes +``` + +Verified served, not just cached: + +``` +~/.config/aidd/cache/built/5.3.0/aidd-framework/codex/plugins/aidd-orchestrator/skills/01-sdlc/SKILL.md:10 +The mode is `auto` unless the caller asks for `interactive`, named as the request's first whole word … +``` + +`03-check.md` there carries `would be routed a second time`, `02-deliver.md` +carries `when the plan calls for one, and none otherwise`, and `01-frame.md` +carries `A source is planning-ready when`. All three fixes are in what Codex will +read. + +## Before you start + +**The shared build is machine-wide.** Every project and every session on this +machine now resolves `aidd-*` from this branch instead of the published 5.3.0. +That is what makes the run meaningful, and it is also a change outside this +worktree. To put the published release back: + +```shell +aidd setup --ai codex --source remote --yes +``` + +Codex also refuses to run a plugin's hooks until each is trusted. Approve the +prompt once in the interactive session, or the session leaves no run journal and +nothing says why. + +## Run it + +```shell +cd /Users/baptistelafourcade/orca/workspaces/framework/test-sdlc-891-codex +codex +``` + +`aidd-orchestrator` ships no commands, so Codex has no `/` entry for this skill — +it is picked up by description. Give it the request as a quoted string, so the +first-whole-word rule has something defined to read: + +``` +Use the aidd-orchestrator 01-sdlc skill. The request is exactly, between the quotes: +"interactive #891" +``` + +## What to watch + +| Gate | Expected | A defect looks like | +| ---- | -------- | ------------------- | +| 1 | it presents the contract for #891 and waits | it starts planning without asking | +| between 1 and 2 | nothing asks you anything | a question about an implementation detail | +| 2 | it presents the plan and waits | the plan is written and executed in one move | +| between 2 and 3 | implement, assert, review and challenge run alone, repairs included | it asks you to confirm a repair | +| 3 | it presents the outcome and waits, before any pull request | a draft pull request exists before you approved | + +Also worth one line each: refuse at gate 1 with a change to what is being built +and check the revision comes back to the same gate; approve at gate 2 and check +the plan is reused rather than rewritten. + +## Known divergence from #910 + +The issue's own example of interactive intent is "run the SDLC interactively". +Under this text that is `auto`: the mode word must be the request's first whole +word. The keyword form was the decision taken while building it, so the issue is +what needs updating — but a Codex run typing the issue's phrasing will land in +`auto`, and that is the text behaving as specified, not a bug. + +## Observed — run 1, Codex, issue #891 + +Mode decided from the text, three gates announced before any work. The zone read +only `01-frame.md` while Frame was current. + +| Gate | What happened | +| ---- | ------------- | +| 1, contract | presented a five-point contract and stopped, naming the pause and what the approval releases | +| 2, plan | presented the revised plan, its confidence and what the approval releases, and stopped | +| between 2 and 3 | implementation started with no question asked | + +Two things worth keeping: + +- **A conditional approval is not covered.** At both gates the answer was "approved, + with corrections". The router says an approval ships what was presented, which + leaves no reading for an approval that changes it. Codex took the corrections and + moved on, which is the useful behaviour; the text does not say it is the right one. +- **It corrected the reviewer on a verifiable fact.** Told to drop Kilo, it answered + that Kilo exists in its checkout and gave the path. The reviewer was reading a + branch cut before Kilo landed on `next`. Following the instruction would have + dropped a shipped tool from the documentation. + +## The clause that run produced + +`An approval ships what was presented` had no reading for the answer the run +actually got twice, "approved, with corrections". Taken literally it made a +correction a refusal, which sends a one-line fix back through the zone and +presents the artifact again. Codex advanced instead, which is the useful +behaviour and not what the text said. + +The sentence now reads `An approval ships what was presented, with any correction +it carries.` Three readers traced the three answers a pause can get: + +| Answer | A, approved | B, approved with corrections | C, refused | +| ------ | ----------- | ---------------------------- | ---------- | +| 9-1 | ships as presented | ships corrected | routes to Frame, pauses again | +| 9-2 | ships as presented | ships corrected | routes to Frame, pauses again | +| 9-3 | ships as presented | ships corrected | routes to Deliver, pauses again | + +No reader answered `UNDECIDABLE`, and each quoted the clause for A and B and the +routing sentence for C. + +One reader of the three read a collision on B with `An artifact produced anew +pauses again`: a correction that cannot be applied as an edit makes the zone +produce the artifact again, and that sentence would pause for it. The other two +did not. One reading out of three is below the bar this work has used for +changing text — the defect it fixed was unanimous — so the sentence stays and the +reading is recorded here instead. + +## Run 2 — the same issue in `auto`, for comparison + +Same tool, same issue, same starting commit (`origin/next` 156f5432), a separate +worktree, and no mode word. `PR #966` opened as a draft on its own. + +| | interactive | auto | +| --- | ----------- | ---- | +| Pauses | 3, all answered by a person | 0 | +| Core fix | `new SetupFlow` moved into the existing `try` | identical | +| Documentation | a table in `cli/README.md` | the same, plus `aidd setup --help` generated from the registry | +| Other production change | none | `--scope` description reworded, help golden regenerated | +| Evidence recorded | plan, phase, review, challenge, validation | plan, phase, review, challenge | +| Commits | 3 | 2 | +| Draft pull request | withheld at the gate | opened | + +Both wrote the two things #891 says were over-claimed, and wrote them correctly: +PATH presence named as the cause of the missing cells rather than the scope, and +Cursor's mechanism sourced rather than guessed. `auto` added the recovery step +(`aidd sync --scope user`) that `interactive` left out, and generated its help +text from `supportsUserScopeActivation`, which already existed, so that text +cannot drift from the registry. + +Two honest conclusions, neither comfortable: + +- **The gates added no quality on this issue.** The autonomous run reached the + same fix with the same two traps avoided, and documented them in one more place. +- **The human at gate 1 made it worse.** Told to drop Kilo on the strength of a + stale checkout, the interactive run nearly lost a shipped tool from the + documentation and only kept it by contradicting the reviewer. The autonomous run + included Kilo unprompted. + +What the gates bought was the chance to withhold the pull request, and a record of +what was decided. What `auto` bought was a slightly wider change: the help text +and its golden snapshot are a surface the issue did not ask for, defensible under +"write the state down" but past the minimum. diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/design-fixes.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/design-fixes.md new file mode 100644 index 000000000..490562044 --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/design-fixes.md @@ -0,0 +1,26 @@ +# Design fixes + +Four defects the case battery surfaced in zones this change did not own, fixed here because leaving them left the mode promising something the flow could not deliver. Each is one sentence, and each is proved by the sandbox that first revealed it. + +## What was wrong, and what it is now + +| Defect | Fix | Proved by | +| --- | --- | --- | +| Frame's spec and Check's review had no committer, so a request could be opened without the contract it was built from or the review that cleared it | each zone commits what it wrote before handing over | a run through a real remote and a forge stub: both files committed, nothing untracked, both reachable on the pushed branch | +| Whether an end to end journey was required rested on a file no zone reference points at, so a run that obeyed the reading rule would skip it | a journey is required when the project's testing memory names one for a surface the change touches, and not otherwise | one run with that memory took the journey and cited the line; one without it took the other edge, both by text rather than by judgement | +| `planning-ready` decided whether a spec is written at all, and therefore how often a person is consulted, with no test behind it | three tests, all of which must hold: the source names the artifact to change, states the observable outcome, and leaves open no decision that changes what is built | the same request stayed on the direct branch in two runs with all three tests met, while a deliberately vague one took the clarify branch with two of three failing | +| The request gate read "no actionable finding", and a strict checker always had one, so two earlier runs looped four times each and never reached it | once the review has cleared, only a finding that contradicts the contract reopens a zone; any other is carried onto the request as a note | a run whose first finding contradicted its contract reopened delivery, whose second did not was carried as a note, and which then reached the gate | + +## Why the loop is bounded without a count + +A pass budget was considered and rejected: the number would be arbitrary, and a run that hit it would stop for a reason no one could defend. Severity needs no number. It also matches what the unbounded runs actually produced — their later rounds were about inputs their contracts never mentioned, a superscript digit, a vulgar fraction, the direction of a flag. None contradicted anything that had been agreed. The first round of each did, and under this rule it still reopens. + +## What the third test is careful not to say + +It reads "no decision that changes what is built", not "no decision". Every request leaves something open; demanding none would send the smallest change through formalizing, and twenty runs that had settled on the direct branch would have flipped. The qualifier is Frame's own wording, taken from the sentence one line below it, so the test introduces no new vocabulary. + +## Still not fixed, deliberately + +Delivery commits and pushes before the review runs, so a rejected candidate can already sit on the remote. Relocating that push was tried, challenged and reverted: on a feature branch nobody reads before the request exists, it bought almost nothing and cost another plugin's contract. The observation stands and the remedy did not. + +The phase commit is still claimed by two documents. The coverage hole is closed, which was the part that lost artifacts; what remains is one fact stated twice, and the implement skill is being rewritten elsewhere. diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/findings.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/findings.md new file mode 100644 index 000000000..587f41c82 --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/findings.md @@ -0,0 +1,64 @@ +# Findings + +What eight sandbox runs and six adversarial readings turned up, and what was done about each. + +## The push was reverted + +`02-deliver.md`, `aidd-vcs:02-pull-request` and its `03-create` action are back to their original text. The change had been agreed, then challenged, and the challenge held on four counts. + +| Count | Why it held | +| --- | --- | +| The benefit was near zero | it stopped a rejected candidate reaching the remote, on a feature branch nobody reads before the request exists | +| It duplicated a concern | pushing to an existing remote lived only in the commit skill; `00-repo-init` pushes while creating a remote, a different act | +| The file contradicted itself | the frontmatter still read `Not for committing, pushing, or merging a branch` beside a rule that pushed | +| The original already met the stated rule | it said `Commit and push the validated work`, and validation at that point is assert plus the journey | + +What survived from that phase is the real bug it uncovered: `ship-a-feature.md` committed and then asked for a request on a branch nothing had pushed. One option on one step fixes it, with no skill touched. + +## Fixed in the mode itself + +Every entry below is a defect in the orchestrator's own paragraph. The right-hand column says what caught it, because the split matters: reading the file found wording faults, and only running it found the faults that live between this file and the providers it dispatches. + +| Defect | Caught by | +| --- | --- | +| Mode propagation put a pause on the commit message, an artifact on no list | a run reaching the commit provider | +| The stand-in clause asserted a dispatched step supplies its own pause; the challenge provider has none | a run reaching the outcome | +| Clarifying the source ran in `auto` and answered its own questions, persisting nothing | a run on a deliberately vague source | +| The spec was counted as a fourth artifact, reversing Frame's own `Spec → Contract` order | the same run, plus two mode-selection runs | +| The paragraph forbade unnamed pauses while mandating a step whose defined behavior is to stop and ask | a run re-entering Frame after a refused spec | +| `the contract once it is framed` did not cover a source used directly, where nothing frames anything | a run on a planning-ready source | +| A refused outcome was routed by delegating to a three-way split with no rule for a lone finding | a run exercising a refusal | +| `four times` counted occurrences, which contradicted re-pausing after a refusal | a reading | +| A delegated pause on an unlisted artifact had no resolution | a reading | +| `auto` was offered by the argument hint and handled nowhere in the body | a reading | +| Mode selection matched the word anywhere in the request, so prose could flip it | a reading | +| Nothing bounded a repeated refusal | a reading | + +## What the runs established + +| Run | Result | +| --- | --- | +| no mode word | zero pauses to the request threshold, work committed locally | +| `interactive` on a planning-ready source | pauses on the contract, then the plan, then the outcome before the request | +| the plan pause | came from the planning provider itself, not from the orchestrator | +| a refused outcome | routed to Deliver, the zone replayed, the plan pause fired again | +| a refused spec | routed to Frame, unambiguous, and clarification re-ran in `interactive` | +| `make the helper interactive so callers can…` | `auto`, the word inside the source selects nothing | +| `auto add a truncate function…` | `auto`, the explicit word names the default | +| `interactive` on a vague source | Frame took its clarify then formalize branch and wrote a spec | + +## Open, and deliberately not fixed here + +| Item | Why it is left | +| --- | --- | +| `beside` has no delimiter, so a request whose first word is literally `interactive` is undecidable | every run landed on the right side; the case is untested, not broken | +| A refusal leaves no trace, and a re-entered zone writes over the refused artifact | recording it means a new artifact, and the folder reuse belongs to the spec skill | +| A repeated Deliver re-enters at its head, so a one-line repair re-plans | Deliver's existing shape; the refusal path only feeds it more often | +| `actionable` is undefined, and turned out to be settled by the user rather than by the checker | the same finding cleared the gate and then reopened the zone | +| `planning-ready` is undefined, and it decides whether a spec is written at all | belongs to `01-frame.md`, untouched by this change | +| A refusal cannot reach the spec skill's own refine action; no edge in Frame reaches it | routing to Frame re-enters at the source by design | +| `taking an irreversible action` is undefined, so the number of stops in `auto` is not decidable | the sentence predates the two modes | + +## Not verified + +Every dispatch in every run resolved to the installed build under `~/.config/aidd/cache/built/5.3.0/`, never to this worktree. The runs therefore prove the orchestrator's own paragraph, which they read from the worktree, against providers that are a published snapshot. diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/live-run.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/live-run.md new file mode 100644 index 000000000..2c1827986 --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/live-run.md @@ -0,0 +1,59 @@ +# The supervised flow, run with someone answering it + +Every earlier run was headless, so the three gates were only ever read. This one +had an interlocutor: the run stopped at each pause and reported what it was +presenting, the answer arrived as a message, and it continued from there. Nobody +invented an approval. + +The source was deliberately not planning-ready — `interactive add rate limiting +to the public API`, against a one-route API with no auth — so the clarify then +formalize path ran, which no headless run had ever counted. + +## What the run did + +| | | +| --- | --- | +| Pauses | 5, on 3 artifacts | +| Step waits that were not pauses | 2, both the clarifying step's own | +| Commits | 10, every zone committing what it wrote | +| Tests | 17, green under the project's own command | +| Pull request | not opened: the request itself was forbidden, so the run stopped at the gate | + +- **Contract**, once. Presented in full, approved with a correction: the contract + never said whether a request already refused counts, so a caller could buy + itself capacity by sending harder. The correction was carried into the spec and + the contract was not presented again. +- **Plan**, twice. Presented, then refused on a seam the plan itself had flagged — + an export whose only consumer was a test, against a contract whose non-goals + said there was no configuration surface. Reworked, re-presented, approved. +- **Outcome**, twice. Presented, then routed back to Deliver: the limiter kept one + entry per source address and nothing evicted it, so on an unauthenticated API an + attacker with address space turns a request limit into memory growth against the + process it protects. Swept, re-checked, re-presented, approved. + +Nothing asked anything between the plan's approval and the outcome, repairs +included. + +## Which rules this exercised + +| Rule | How | +| ---- | --- | +| A step's own waits are part of producing the artifact | the clarifying step asked twice and the run answered that neither was one of the three pauses, quoting the rule | +| The pause is on the finished artifact, taken by you where no step presents it | `aidd-pm:04-spec` returns a path and notes, so the orchestrator took the contract pause itself and said why | +| An approval ships what was presented, with any correction it carries | the contract's correction shipped without a second presentation | +| An artifact produced anew pauses again | both the plan and the outcome came back to their own pause | +| Three pauses, one per artifact | five stops, three artifacts, and the two re-presentations were the same artifact produced anew | +| An exception says what was withheld and what would release it | the isolated executor and the independent checker were both withheld by the no-subagent rule, and the run said its review's independence was therefore nominal rather than structural | +| A finding already acted on is a decision that requires user authority | the memory growth had been accepted as a line in Risks at the plan pause; the run asked again once it was running code, and did not decide for the user | + +## What the run got wrong, and said so + +- Three throwaway probe scripts were written outside the sandbox, then deleted. + Their evidence stood; their location did not. +- A mutation was measured twice against a tree whose implementation an intervening + `git checkout` of an uncommitted file had silently reverted, so the first result + proved nothing. Re-run against the committed file with an anchor assertion, it + failed two named tests, and the challenge record says which. + +Both were volunteered, not caught by the reviewer. A run that reports its own +invalid evidence is worth more than one whose record reads clean. diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/mass-campaign.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/mass-campaign.md new file mode 100644 index 000000000..562cd62f9 --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/mass-campaign.md @@ -0,0 +1,51 @@ +# Mass campaign + +Forty-one independent headless runs, grouped so that each group measures dispersion rather than presence. A behaviour observed once is an anecdote; a mode that pauses nine times out of ten is unusable. + +The text moved twice after this campaign, under the inline review and then under `03-check.md`'s reorder. What ran on the text as it stands is in `w-batch.md`. + +## Protocol + +Every run gets its own sandbox, built from one script so nothing differs between them, and reports in `KEY=value` lines so the aggregation is mechanical rather than a reading impression. No run may push, open a request, call the forge, or spawn agents, and none may invent a user approval. + +| Group | N | What it varies | What it measures | +| --- | --- | --- | --- | +| G1 | 10 | nothing, the same request in `interactive` | does the first pause land on the same artifact every time | +| G2 | 10 | nothing, the same request with no mode word | does the autonomous mode really never stop | +| G3 | 8 | the shape of the request, one form per run | does the mode sentence decide by text or by judgement | +| G4 | 6 | how a finding recurs | does the recurrence clause bound the loop, and can it be escaped | +| G5 | 7 | which artifact is refused and how | does a refusal always reach the same zone | + +G3's eight forms: the word inside the prose, a word that merely starts like it, the bare word alone, upper case with dashes, both words, the word trailing, surrounding whitespace, and a near-miss prefix. + +G4's six: a plain recurrence twice over, a recurrence whose repair failed, a recurrence reworded to escape the clause, a recurrence two passes back, and a recurrence under `interactive`. + +G5's seven: a refused contract, a refused plan, a refused outcome that changes what is built, a refused outcome that is a repair, a refusal naming what the artifact already carries, three refusals of the same plan in a row, and a refused outcome verified true before acting. + +## Why the mode words are measured this hard + +Three forms used to be decided by the reader rather than by the sentence, and one of them corrupted the source silently: a request opening with an ordinary word that merely starts like the default mode lost its first word on the way to framing. The sentence now matches a whole word, strips it from the source, and refuses a request that carries nothing else. Each of those three properties has its own run. + +## Results + +| Group | N | Outcome | +| --- | --- | --- | +| G1 | 10/10 | every run selected `interactive`, paused on the contract, and took Frame's direct branch | +| G2 | 10/10 | every run selected `auto`, paused zero times, took the direct branch, wrote one phase | +| G3 | 8/8 | the sentence decided every form by itself | +| G4 | 6/6 | the recurrence stopped the loop every time, including when the repair had failed and when the recurrence was two passes back | +| G5 | 7/7 | every refusal reached the zone the sentence names | +| T | 3/3 | the shortened text behaves as the long one did, and the request gate no longer contradicts it | + +Forty-four runs. No dispersion on anything load-bearing: the mode selected, the artifact a pause lands on, the branch Frame takes, the zone a refusal reaches. The one outlier in the whole series is a single run reporting three self-answered questions where nine reported none, and it concerns what that run counted as a question rather than what it did. + +## What the mass caught that a single run could not + +- A request opening with an ordinary word that merely starts like the default mode used to lose that word on the way to framing. Eight forms now resolve by the sentence alone, where seven of fourteen once needed the reader. +- A recurring finding whose repair had failed was covered by no wording, so the autonomous mode looped without bound. The clause now reads on the recurrence rather than on the repair. +- Two refusals of one artifact in a row leave the plan growing a phase per pass, with nothing bounding it but the person. That is what the text says, and it is now measured rather than assumed. +- Whether a refusal leaves any trace on disk is not deterministic: one run left one, another left none, from the same text. The gap is not only that no rule requires a trace, but that its absence cannot be read as meaning no refusal happened. + +## What stayed decided by the reader + +Two clauses, both resting on a distinction the Check reference leaves undefined for its own three routes. A refused outcome goes to Deliver or to Frame depending on whether it changes what is being built, and one run in seven judged that rather than read it. A finding reworded between passes is the same finding or a new one by the reader's call. Tightening either would invent a test its neighbours do not have. diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/open-items.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/open-items.md new file mode 100644 index 000000000..95cb819e8 --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/open-items.md @@ -0,0 +1,92 @@ +# Open items + +Every defect the case battery turned up that this change does not own. Four of them were fixed after the fact, and [`design-fixes.md`](./design-fixes.md) records those with the runs that prove them; the rows below are what remains. None was introduced by the interactive mode; each is recorded here because the mode made it visible, and several were reported independently by more than one run. + +## Reported by several runs + +| Item | Where | Runs | +| --- | --- | --- | +| Two owners claim the phase commit. The implement skill mandates one commit per phase as a transversal rule, while Deliver routes the commit through the commit skill. Neither says which wins, and a run that obeys both commits twice | `aidd-dev:02-implement` against `01-sdlc/references/02-deliver.md` | journey, architecture, refusals, blocked | +| What makes an end to end journey required is defined nowhere, and no zone reference points at the file that would say. One run only took the journey edge because it had read the testing memory while orienting, which the read-only-the-current-zone rule never sends it to | `01-sdlc/references/02-deliver.md` | journey, architecture, check routing | +| `planning-ready` has no test, and it is the fork that decides whether a spec is written at all, so it decides how many artifacts a person is shown | `01-sdlc/references/01-frame.md` | ticket, check routing, refusals, challenge | +| Delivery pushes before the review runs, so unreviewed work leaves the machine | `01-sdlc/references/02-deliver.md` | journey, and the challenge that reverted the relocation | + +## The Check zone + +| Item | Detail | +| --- | --- | +| No test separates a product finding from an implementation one | three outgoing edges partition on a word the reference never defines; one run classified a boundary defect as product, and the same defect reads as an implementation bug | +| No test separates an independent finding from a dependent one | the adjectives appear only inside the two edge labels; two findings in one function would be a coin flip | +| A finding that is neither has no edge at all | nothing covers a finding about the plan, about test quality, or about the shape of a commit | +| The Todo route and the Deliver route end at the same place | Todo's only exit is Deliver, and its one claimed difference is parallelism, which disappears wherever work cannot fan out | +| The prose admits contract findings to Frame, the diagram's edge label admits only product findings | one run followed the prose | +| `$validation_reports` is an input to the checker that no zone produces | one run substituted the raw assertion output | + +## The Frame zone + +| Item | Detail | +| --- | --- | +| A referenced ticket that cannot be resolved has no path | the ticket step has no failure exit, no fallback and no test row, and the degradation is recorded in no artifact | +| Frame says a backlog item is knowable only at resolution, never guessed later, while the planning step accepts a ticket id straight from the source reference | the two files disagree about the same file's contents | +| Formalizing never explores the codebase, by its own rule | so a contract can be formalized asking for what the documented architecture forbids, and the conflict cannot surface before planning | + +## The Deliver zone + +| Item | Detail | +| --- | --- | +| A request that conflicts with documented architecture has no handler | the conformance facet only reports, blocked means physically impossible so it cannot catch it, and the drift guard cannot either because the code matches the plan | +| A failed journey routes to the executor, which presumes the product code is at fault | nothing covers a journey whose own script is wrong | +| Neither a blocked run nor a drifting one has a destination | Deliver declares no edge for either | +| A blocked run and a drifting run are not distinguishable from the repository alone | the replan reason exists only in a report, and nothing writes it down | +| Preparing a run flips a blocked plan back to in progress | no unblock rule exists anywhere | +| Per-gate verdicts are lost | the code survives, which gate passed does not | +| The status lifecycle says workers never write the status, and the implement skill, run by the executor, writes it | the two statements cannot both hold | +| Finalizing marks a plan implemented on green validation even when half its contract is unbuilt | one run filed that against itself rather than correct it silently | + +## Refusal and artifact history + +| Item | Detail | +| --- | --- | +| A refusal leaves no trace | the spec is overwritten at its path, the plan passed through three revisions at one path, and the review file still reads approved after the outcome was refused | +| The status lifecycle has no refused state | and it says a review rejection does not move the status either | +| A spec is immutable once validated, with neither term defined | one run treated a refused spec as neither | +| Ambiguities are returned as notes rather than written into the spec | which is what one refusal then complained the contract was silent about | +| Repeated refusals can leave a plan incoherent | two refusals forced a split whose phases demand a test that cannot fail first, and nothing in the flow tells the person that | + +## The backlog declaration + +| Item | Detail | +| --- | --- | +| Whether a ticket whose identifier resolves but whose record cannot be fetched counts as already resolved | the clause that writes the declaration names a ticket already resolved, while its own test row asks only whether the request names a backlog item; one run wrote the file on the test row's weaker condition | +| The field naming the writer has two prescriptions that disagree | the prose asks for the skill's own name while the example shows it prefixed by its plugin, and the frontmatter carries the unprefixed form | +| Nothing carries the ticket across a zone boundary | Frame carries it in the resolved source, and Deliver hands the planning step only the contract; it worked in one run only because formalizing had created the folder first | +| Refining a spec declares nothing and preserves nothing | the folder is safe on that path only because refining writes no declaration either | +| Never invent collides with a request that delegates the decision | one run was told to decide what a behaviour means by a skill forbidden to guess, and nothing says which instruction wins | + +## Found once the request could actually open + +| Item | Detail | +| --- | --- | +| Nothing closes the plan's last status transition | the lifecycle says the review step writes `reviewed`, the review skill is read only and never writes it, so a plan stays `implemented` for good | +| The review never reaches the request | delivery commits and pushes before the review runs, the review file is written afterwards, and no step commits it, so neither the pushed branch nor the request carries it | +| The base came from the project's convention as a whole, not from resolving the branch prefix | the clause forbids assuming the production branch, and a project that declares one target for everything satisfies it without the prefix deciding anything | + +## A decided consequence, not a defect + +The request step is dispatched in `auto` even under `interactive`, because it produces none of the three artifacts. Its own instructions ask for the title, body and base to be approved before creation, and its test demands that approval, so that test cannot pass under `interactive`. This is the commit message case again and the answer is the same: the outcome pause sits immediately before the request, so the person has already approved what the request will carry. Reinstating a second approval on the title would put a pause where the list names none. + +## Found once agents could be spawned and money could be at stake + +| Item | Detail | Runs | +| --- | --- | --- | +| The check loop has no bound outside a refusal | two runs looped four times each, every repair raising the next finding; one repair introduced a defect that aborted the process on a non-finite width, and the request gate never opened. The router now pauses the outcome when a repeated zone raises a finding its predecessor already raised, which protects a person who is present and leaves the autonomous mode unbounded | independence, authority | +| The router says to parallelize while delivery says to give one executor the plan | both apply to the same work and neither yields; one run followed the more specific instruction and recorded the choice | authority | +| Parallel agents share one working tree and one test run | independent by file is not independent by validation. One executor read another's half-written test file mid-flight and reported the suite red for a file it had been told not to touch; neither agent was wrong. Nothing warns about it | authority | +| Independence is achievable for verification and not for isolation | a fresh checker can reach its verdict from the named inputs alone, but the review artifact lands in the shared task folder where the next checker finds it, and findings travel through the spec, which is a channel from one checker to the next | independence | +| The fresh checker earns its place | it found what the implementer had not claimed and had not seen: a word split that destroyed Indic and Thai text, and an orphan combining mark its own previous repair had introduced. It also caught a typo in a plan, which an author never catches in their own | independence | + +## Unreachable in a sandbox + +Nothing. Every one of the four items this section used to hold was unreachable because of a constraint the harness imposed, and three further sandboxes lifted all of them: one requires spawning and feeds a fresh checker only its named inputs, one carries a real remote and a forge stub that logs every call, and one declares a metered API with no key and a module three external consumers depend on. Sixty-four edges, sixty-four observed. + +Two caveats on validity, both declared by the runs themselves rather than found afterwards. Several agents left their sandbox for scratch files and said so. And in the authority run this repository's own memory bank bled into the sandbox: three executors reported falling short of a mutation rule that belongs here and not there, which the first checker caught as a misattribution. diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/phase-1.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/phase-1.md new file mode 100644 index 000000000..6c8805977 --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/phase-1.md @@ -0,0 +1,108 @@ +--- +status: done +--- + +# Instruction: the mode and its four pauses + +## Architecture projection + +> Tree of the final files. ✅ create · ✏️ modify · ❌ delete + +```txt +. +└── plugins/ + └── aidd-orchestrator/ + └── skills/ + └── 01-sdlc/ + └── ✏️ SKILL.md +``` + +## User Journey + +```mermaid +flowchart TD + A["the user names a source"] --> B{"the request names interactive"} + B -- no --> C["the flow runs to the draft pull request without asking"] + B -- yes --> D["the flow presents the contract and waits"] + D --> E["the flow presents the spec and waits"] + E --> F["the flow presents the plan and waits"] + F --> G["implement, assert, review and challenge run without asking"] + G --> H["the flow presents the verdict and waits"] + H --> I["the draft pull request is opened"] + D -- "the user refuses" --> J["the refusal is routed as a finding"] + E -- "the user refuses" --> J + F -- "the user refuses" --> J + H -- "the user refuses" --> J + J --> D +``` + +## Test Scope + +```mermaid +--- +title: Test scope +--- +journey + section Setup + prepare a scratch project with the flow installed and a written source => a project ready to run the flow: 5: cli + section Happy path + run the flow naming the source and the interactive mode => the flow presents the contract and waits: 5: cli + approve the contract => the flow presents the spec and waits: 5: cli + approve the spec => the flow presents the plan and waits: 5: cli + approve the plan => implement, assert, review and challenge run through without a question: 5: cli + the checker returns nothing actionable => the flow presents the verdict and waits: 5: cli + approve the verdict => a draft pull request exists: 5: cli + section Edge case - a refusal at a pause + the plan is wrong => refuse it with a correction => the delivery zone replays and a new plan is presented: 1: cli + section Edge case - no mode named + nothing names a mode => run the flow naming only the source => no pause occurs before the draft pull request: 1: cli + section Teardown + remove the scratch project => the machine is back to its previous state: 5: cli +``` + +## Tasks to do + +### `1)` State the two modes in the router + +> The flow reads its mode from the request, and nothing else has to be told. + +1. In `## Behavior`, make `auto` the mode when the request names none, and `interactive` the mode when it does. +2. Keep the `auto` branch declaring autonomy in the terms a called skill reads as such. No literal string is shared: `aidd-dev:01-plan` carries its own `Under an autonomous orchestrator` clause and infers the case from what the router declares, so the switch is inference, not a match. +3. Write the `interactive` branch: present what was produced and wait after the contract, after the plan, and after the outcome. +4. State that under `interactive` no zone and no delegated step claims autonomy, so a called skill takes its own interactive branch. +5. State that a refusal at a pause is a finding, routed the way the check zone already routes one. +6. Write every one of these in `## Behavior` only. The three references say nothing about the mode. + +### `2)` Name what the user brings + +> The frontmatter admits the mode word. + +1. Set `argument-hint` to `request | auto | interactive`. +2. Expect the mixed form to be questioned in review, and answer with the precedent: `aidd-vcs:01-commit` ships `paths | auto | push`, an artifact beside a mode and an option, and it passes the gate. + +### `3)` Make the description true for both modes + +> The only always-on text stops promising a single mode. + +1. Rewrite `description` so it no longer opens by promising autonomy alone. +2. Hold it to the contract: verb-led, third person, about 240 characters, an intent clause, an optional exclusion, no colon, no dash, no other skill named. + +### `4)` Prove it on a real run + +> A gate that passes says the file is well formed, not that the flow stops. + +1. Run the repository's pre-commit gate. +2. Run the flow twice against a scratch project, once with no mode word and once with `interactive`, and observe the pauses. +3. Confirm in the interactive run that the planning step asked for approval on its own score, which is how the switch is observed from outside. +4. Treat this observation as the only guard there is. No gate and no test covers the inference, so a later rewording of `## Behavior` can break the switch in silence. + +## Test acceptance criteria + +| Task | Acceptance criteria | +| ---- | -------------------------------- | +| 1 | A run naming no mode reaches the draft pull request without a single pause; a run naming `interactive` waits on the contract, on the plan, and on the outcome before the pull request, whether Frame yields the contract directly or through a spec | +| 1 | Refusing at any of the four pauses sends the run back through the zone that owns the artifact, and the run continues afterwards | +| 1 | No reference file mentions a mode | +| 2 | The argument-hint gate passes and the hint names the two mode words | +| 3 | The description reads true in both modes and satisfies the skill contract | +| 4 | The interactive run shows the planning step waiting for approval, which no code change caused | diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/phase-2.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/phase-2.md new file mode 100644 index 000000000..56e8752fd --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/phase-2.md @@ -0,0 +1,64 @@ +--- +status: done +--- + +# Instruction: the recipe that opens a request on a branch nobody pushed + +## Architecture projection + +> Tree of the final files. ✅ create · ✏️ modify · ❌ delete + +```txt +. +└── plugins/ + └── aidd-context/ + └── skills/ + └── 12-cook/ + └── assets/ + └── recipes/ + └── ✏️ ship-a-feature.md +``` + +## User Journey + +```mermaid +flowchart TD + A["a reader follows the ship recipe"] --> B["the commit step runs"] + B --> C{"was the branch pushed"} + C -- no --> D["the request step has no branch on the remote"] + C -- yes --> E["the request opens against a branch that exists"] +``` + +## Test Scope + +```mermaid +--- +title: Test scope +--- +journey + section Setup + read the ship recipe end to end => the two steps that produce a request: 5: cli + section Happy path + follow the commit step as written => the branch reaches the remote: 5: cli + follow the request step next => a request can exist against that branch: 5: cli + section Edge case - the option is missing + drop the option from the commit step => follow both steps => the request step has nothing on the remote to open against: 1: cli +``` + +## Tasks to do + +### `1)` Push in the step that commits + +> A recipe that ends in a request needs a branch the remote has. + +1. In `ship-a-feature.md`, make the commit step run the commit skill with its `push` option, in the prose and in the copyable block. +2. Say why in the step's own sentence, so the option does not read as decoration. +3. Change nothing else: the commit skill already pushes when that option is set, and the request skill keeps its rule against pushing. + +## Test acceptance criteria + +| Task | Acceptance criteria | +| ---- | -------------------------------- | +| 1 | Following the recipe as written leaves the branch on the remote before the request step runs | +| 1 | The commit skill and the request skill are unchanged | +| 1 | The step says why it pushes | diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/phase-3.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/phase-3.md new file mode 100644 index 000000000..9f124ac0f --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/phase-3.md @@ -0,0 +1,87 @@ +--- +status: done +--- + +# Instruction: the documents that claim one mode + +## Architecture projection + +> Tree of the final files. ✅ create · ✏️ modify · ❌ delete + +```txt +. +├── ✏️ README.md +├── docs/ +│ └── ✏️ CATALOG.md +└── plugins/ + └── aidd-context/ + └── skills/ + └── 00-onboard/ + └── references/ + └── run/ + └── ✏️ tiers.md +``` + +## User Journey + +```mermaid +flowchart TD + A["a reader asks how the flow runs"] --> B["the onboarding tiers"] + A --> C["the catalog"] + A --> D["the readme"] + B --> E["each says the flow runs on its own unless asked otherwise"] + C --> E + D --> E +``` + +## Test Scope + +```mermaid +--- +title: Test scope +--- +journey + section Setup + take the tree with the two earlier phases applied => a tree whose flow has two modes: 5: cli + section Happy path + search the tree for a document promising a single mode for the flow => no document promises one: 5: cli + run the repository gate over the whole tree => it passes: 5: cli + section Edge case - the onboarding walk + read the onboarding tiers => the flow may be handed over or walked through => the generic dual-mode line is the only rule that governs it: 1: cli +``` + +## Tasks to do + +### `1)` Drop the exception that forbids the walk + +> The generic rule already covers a skill with two modes. + +1. In `references/run/tiers.md`, delete the line making the flow autonomous by contract and forbidding its downgrade. +2. Keep the line above it, which already says a dual-mode skill runs the other way when the user asks and the skill supports it. +3. Read `references/flow.md` and decide whether the choice it offers between walking step by step and handing the whole flow over still reads right. Change it only if it now misleads. + +### `2)` Reword the two hand-written catalogs + +> Neither is generated, so neither fixes itself. + +1. In `docs/CATALOG.md`, reword the flow's row so autonomy is the default rather than the whole story. +2. In `README.md`, reword the flow's row the same way, without copying the sentence used in the catalog. +3. Leave every generated catalog alone: the pre-commit hook rewrites those from each skill's own description. + +### `3)` Prove nothing else still claims it + +> The claim may sit somewhere this plan did not look. + +1. Search the tree for the words promising autonomy about this flow, and read each hit. +2. Reword a hit that is now false; leave a hit that describes something else. +3. Run the repository's pre-commit gate over the whole tree. + +## Test acceptance criteria + +| Task | Acceptance criteria | +| ---- | -------------------------------- | +| 1 | The onboarding walk may offer the flow as a guided step, and no line forbids it | +| 2 | Both hand-written catalogs describe a flow that is autonomous by default and can be asked to pause | +| 2 | No generated catalog was edited by hand | +| 3 | No document in the tree states that the flow only runs autonomously | +| 3 | The whole-tree gate passes | diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/plan.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/plan.md new file mode 100644 index 000000000..9e5fa5be2 --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/plan.md @@ -0,0 +1,30 @@ +--- +objective: "The SDLC flow runs autonomously by default, stops at the contract, the spec, the plan and the verdict when asked, and pushes only once a verdict is clean." +status: implemented +--- + +# Plan: an interactive mode for the SDLC flow + +## Overview + +| Field | Value | +| ---------- | ----------------------- | +| **Goal** | give the SDLC flow a second mode that pauses where an artifact can still be corrected, and move the push behind the verdict | +| **Source** | [`brainstorm.md`](./brainstorm.md) | + +## Phases + +| # | Phase | File | +| --- | ------------ | ---------------------------- | +| 1 | the mode and its four pauses | [`phase-1.md`](./phase-1.md) | +| 2 | the push behind the verdict | [`phase-2.md`](./phase-2.md) | +| 3 | the documents that claim one mode | [`phase-3.md`](./phase-3.md) | + +## Decisions + +| Decision | Why | +| ---------- | ----- | +| The mode word is `interactive`, never `manual` | four places already carry that word, and the skill contract forbids a second home for one fact | +| The pauses are the orchestrator's own behavior, written once in its router | R9 and R17 of the skill contract; no called skill changes, and `aidd-dev:01-plan` already switches on the orchestrator's declared autonomy | +| A refusal at a pause is a finding | the check zone already routes a finding back to framing or delivery and re-enters; a refusal needs no second mechanism | +| The push belongs to the pull request skill | a request on a branch the remote lacks cannot exist, so that skill has always carried the precondition and no text held it | diff --git a/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/w-batch.md b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/w-batch.md new file mode 100644 index 000000000..12e07c334 --- /dev/null +++ b/aidd_docs/tasks/2026_09/2026_09_17_sdlc-interactive-mode/w-batch.md @@ -0,0 +1,118 @@ +# W batch, on the post-review text + +One sandbox per run, independent agent, output normalized as `KEY=value`. + +W1 to W5 ran on the text as the inline review left it, before `03-check.md` +reordered its two recurrence rules. Only the readers in the last section, and +the two runs it names, saw that order. Nothing else in this file does. + +## W1 — `interactive` as the first word (8 runs) + +| Run | MODE | DECIDED_BY | FIRST_PAUSE | FRAME_BRANCH | PLANNING_READY | +| --- | ---- | ---------- | ----------- | ------------ | -------------- | +| 1-1 | interactive | text | contract | direct | yes | +| 1-2 | interactive | text | contract | direct | yes | +| 1-3 | interactive | text | contract | direct | yes | +| 1-4 | interactive | text | contract | direct | yes | +| 1-5 | interactive | text | contract | direct | yes | +| 1-6 | interactive | text | contract | direct | yes | +| 1-7 | interactive | text | contract | direct | yes | +| 1-8 | interactive | text | contract | direct | yes | + +Zero dispersion. Every run that was asked for it quoted the planning-ready +sentence verbatim, so the test is read as text and not as judgement. No run wrote +anything before its pause. + +## W2 — the same request without the mode word + +| Run | MODE | PAUSES | FRAME_BRANCH | PR_GATE_REACHED | +| --- | ---- | ------ | ------------ | --------------- | +| 2-1 | auto | 0 | direct | stopped at the plan, which is where its prompt ended | +| 2-2 | auto | 0 | direct | yes | +| 2-3 | auto | 0 | direct | yes | +| 2-4 | auto | 0 | direct | yes | +| 2-5 | auto | 0 | direct | yes | +| 2-6 | auto | 0 | direct | yes | + +Every run that went the distance reached the request gate. Three re-entered Check +once after a repair and then cleared, which is the loop converging on severity +rather than on the pass counter that was rejected. + +## W3 — what counts as the mode word (one reader each) + +| Run | Request opens with | MODE | Correct | +| --- | ------------------ | ---- | ------- | +| 3-1 | `auto` | auto | yes | +| 3-2 | a plain request | auto | yes | +| 3-3 | `interactive` and nothing else | NOT_RUNNABLE | yes | +| 3-4 | `build an interactive diff viewer` | auto | yes, the word is not first | +| 3-5 | `Interactive rename …` | interactive | yes, case does not matter | +| 3-6 | `interactively walk me …` | auto | yes, not a whole word | + +The source handed to Frame never carried the mode word, and never lost a word +that belonged to it. + +## W4 — whether a journey runs + +| Run | PLAN_CALLS_FOR_A_JOURNEY | JOURNEY_RUN | POSITION | DECIDED_BY | +| --- | ------------------------ | ----------- | -------- | ---------- | +| 4-1 | yes | yes | last | text | +| 4-2 | yes | yes | last | text | +| 4-3 | yes | yes | last | text | +| 4-4 | no | no | n/a | text | + +Before the fix this was the agent's judgement in every run. After it, each of +these four quoted the Deliver sentence and pointed at the plan clause that +answered it. + +`2-1`, which stopped at the plan, reported the decision as judgement: the plan +writer still weighs whether the change needs a journey. That is where the design +puts it. What the fix moved is the zone's side of the question, which now reads +the plan instead of weighing the change a second time. + +## W5 — the stop paths + +| Run | What happened | Governed by | +| --- | ------------- | ----------- | +| 5-1 | a blocked validation stopped the run and named the missing credential | the zone that cannot proceed | +| 5-2 | same, same sentence, same resume condition | same | +| 5-3 | a contract finding reopened, a cosmetic one became a note, the recurrence stopped the run | three sentences, see below | +| 5-4 | contract finding reopens, the other two become notes | the reopening rule | +| 5-5 | same | same | + +Neither blocked run committed anything, because Deliver commits after its +validations and Frame had written nothing on a planning-ready source. + +## The defect this batch found + +`5-3` reported that two sentences disagreed, and three independent readers +confirmed it: a non-contract finding that a pass had already acted on was a +non-blocking note under one sentence and a blocking stop under the other, and +all three answered `UNDECIDABLE`. + +The reopening rule now comes first, and the recurrence rule speaks of a finding +that *would be routed a second time*, so a note never reaches it. Four readers +re-traced the same paths on the corrected text: + +| Reader | A cosmetic finding recurring after the review cleared | A contract finding whose repair failed | +| ------ | ---------------------------------------------------- | -------------------------------------- | +| 8-1 | note, the request opens | stops for user authority, no request | +| 8-2 | note, the request opens | stops for user authority, no request | +| 8-3 | note, the request opens | stops for user authority, no request | +| 8-4 | — | a finding recurring before any clear also stops, loop bounded | + +No reader answered `UNDECIDABLE`, and the sentence each quoted was the one the +order intends. + +Readers are not execution, and this defect was execution's find, not a reader's: +seven adversarial reads had missed it. So two full runs replayed both paths +against the new order, each in its own sandbox, writing the code and its test and +committing locally. + +| Run | Path | Pass 1 | Last pass | Request gate | Conflict reported | +| --- | ---- | ------ | --------- | ------------ | ----------------- | +| 5-6 | a cosmetic finding recurs after the review cleared | reopened a zone | carried as a note | reached | no | +| 5-7 | a contract finding recurs because the repair failed | reopened a zone | stopped for user authority | not reached | no | + +Both quoted the sentence the order intends, and neither found a second sentence +claiming the same finding. The bound survives, and a note no longer trips it. diff --git a/docs/CATALOG.md b/docs/CATALOG.md index 5bc2852a4..c169c926b 100644 --- a/docs/CATALOG.md +++ b/docs/CATALOG.md @@ -98,7 +98,7 @@ Runs synchronous feature delivery, optional async issue automation, and the prod | Skill | Role | Protocols | | ---------------- | ------------------------------------------------------- | --------------------------- | | `00-async-dev` | Single entry point for the async-dev pipeline | `setup`, `run`, `review` | -| `01-sdlc` | Autonomously drive the full development flow end to end | `frame`, `deliver`, `check` | +| `01-sdlc` | Drive the full development flow end to end, autonomous or supervised | `frame`, `deliver`, `check` | | `02-backlog` | Route backlog intake, refinement, lifecycle, and repair | `01-inspect` to `08-verify` | ## 🎨 aidd-ui diff --git a/plugins/aidd-context/skills/00-onboard/references/run/tiers.md b/plugins/aidd-context/skills/00-onboard/references/run/tiers.md index da28cedf2..fcace91b9 100644 --- a/plugins/aidd-context/skills/00-onboard/references/run/tiers.md +++ b/plugins/aidd-context/skills/00-onboard/references/run/tiers.md @@ -9,5 +9,5 @@ The tier is a default, overridable. | MANUAL | (you run this one yourself) | show the command, run nothing, leave it for the user | - A dual-mode skill runs the other way when the user asks and the skill supports it. -- `aidd-orchestrator:01-sdlc` is autonomous by contract; do not downgrade it to `GUIDED`. +- A skill that is autonomous by default runs `AUTO`, and `GUIDED` only when the user asks it to pause. - On the `OK` walk, state up front how many steps it covers and which need input. diff --git a/plugins/aidd-context/skills/12-cook/assets/recipes/ship-a-feature.md b/plugins/aidd-context/skills/12-cook/assets/recipes/ship-a-feature.md index e07f7c513..85c2b4644 100644 --- a/plugins/aidd-context/skills/12-cook/assets/recipes/ship-a-feature.md +++ b/plugins/aidd-context/skills/12-cook/assets/recipes/ship-a-feature.md @@ -52,12 +52,12 @@ Review checks the diff before it ships. #### 5) 📦 Commit -Commit records one atomic conventional change. +Commit records one atomic conventional change, and pushes it so the next step has a branch to open a request against. -1. Run `/aidd-vcs:01-commit`. +1. Run `/aidd-vcs:01-commit push`. ```text -/aidd-vcs:01-commit +/aidd-vcs:01-commit push ``` #### 6) ✅ Pull request diff --git a/plugins/aidd-orchestrator/CATALOG.md b/plugins/aidd-orchestrator/CATALOG.md index 345aa63f1..61a6aa78f 100644 --- a/plugins/aidd-orchestrator/CATALOG.md +++ b/plugins/aidd-orchestrator/CATALOG.md @@ -36,7 +36,8 @@ Auto-generated index of skills, agents, references and assets shipped by the `ai | `references` | [01-frame.md](skills/01-sdlc/references/01-frame.md) | - | | `references` | [02-deliver.md](skills/01-sdlc/references/02-deliver.md) | - | | `references` | [03-check.md](skills/01-sdlc/references/03-check.md) | - | -| `-` | [SKILL.md](skills/01-sdlc/SKILL.md) | `Autonomously orchestrates a request from framing to a draft pull request, isolating implementation, independent review, and final outcome challenge. Use when the user wants to deliver a change end to end. Not for running one development step.` | +| `references` | [mode.md](skills/01-sdlc/references/mode.md) | - | +| `-` | [SKILL.md](skills/01-sdlc/SKILL.md) | `Orchestrates a request from framing to a draft pull request, autonomous or supervised, isolating implementation, independent review, and final outcome challenge. Use when the user wants to deliver a change end to end. Not for one step.` | #### `skills/02-backlog` diff --git a/plugins/aidd-orchestrator/README.md b/plugins/aidd-orchestrator/README.md index 7c50f5bfe..279456cad 100644 --- a/plugins/aidd-orchestrator/README.md +++ b/plugins/aidd-orchestrator/README.md @@ -16,7 +16,7 @@ Composes capabilities into deterministic, auditable flows. Domain skills retain | Bracket ID | Skill | Description | |------------|-------|-------------| -| [6.1] | [sdlc](skills/01-sdlc/SKILL.md) | Autonomous orchestration through framing, delivery, independent review, outcome challenge, and PR creation. | +| [6.1] | [sdlc](skills/01-sdlc/SKILL.md) | Autonomous or supervised orchestration through framing, delivery, independent review, outcome challenge, and PR creation. | ### Use case: `async-dev` diff --git a/plugins/aidd-orchestrator/skills/01-sdlc/SKILL.md b/plugins/aidd-orchestrator/skills/01-sdlc/SKILL.md index 24c3114f3..3083149eb 100644 --- a/plugins/aidd-orchestrator/skills/01-sdlc/SKILL.md +++ b/plugins/aidd-orchestrator/skills/01-sdlc/SKILL.md @@ -1,14 +1,14 @@ --- name: 01-sdlc -description: Autonomously orchestrates a request from framing to a draft pull request, isolating implementation, independent review, and final outcome challenge. Use when the user wants to deliver a change end to end. Not for running one development step. -argument-hint: request +description: Orchestrates a request from framing to a draft pull request, autonomous or supervised, isolating implementation, independent review, and final outcome challenge. Use when the user wants to deliver a change end to end. Not for one step. +argument-hint: request | interactive request --- # Skill: sdlc ## Behavior -Operate autonomously from the request to a draft pull request: decide and act without confirmation, asking only before spending money, taking an irreversible action, or making a decision that requires user authority. Read only the current zone reference. Verify that every named provider is installed before calling it. +Decide the mode as `mode.md` says, then read only it and the current zone's reference. Verify that every named provider is installed before calling it. A zone that cannot proceed stops the run and says what it would take to resume. Spawn specialized agents for isolated work. Parallelize independent work when it is faster. Give each agent one focused task that a smaller model can execute. Repeat the responsible zone when delegated work returns an actionable gap. @@ -20,17 +20,17 @@ flowchart TD subgraph FrameStage["01 Frame"] direction TB Request["$request"] - Frame["01 Frame"] + Frame["01 Frame
interactive: pause on the contract"] end subgraph DeliverStage["02 Deliver"] direction TB - Deliver["02 Deliver"] + Deliver["02 Deliver
interactive: pause on the plan"] end subgraph CheckStage["03 Check"] direction TB - Check["03 Check"] + Check["03 Check
interactive: pause on the outcome"] PullRequest["$pull_request"] end @@ -63,6 +63,7 @@ it drove afterwards then reads as work that belonged to nothing. | # | Reference | | --- | --------------------------------------- | +| — | [Mode](references/mode.md) | | 01 | [Frame](references/01-frame.md) | | 02 | [Deliver](references/02-deliver.md) | | 03 | [Check](references/03-check.md) | diff --git a/plugins/aidd-orchestrator/skills/01-sdlc/references/01-frame.md b/plugins/aidd-orchestrator/skills/01-sdlc/references/01-frame.md index cb2f12338..ad30ae3c0 100644 --- a/plugins/aidd-orchestrator/skills/01-sdlc/references/01-frame.md +++ b/plugins/aidd-orchestrator/skills/01-sdlc/references/01-frame.md @@ -2,7 +2,9 @@ ## Behavior -Start from `$source` only. Resolve a ticket when the source references one. Use the source directly when it is planning-ready. Otherwise clarify only the intent that can change what is built, then formalize the missing contract requirements. Hand the resulting contract to Deliver. +Start from `$source` only. Resolve a ticket when the source references one. Use the source directly when it is planning-ready. Otherwise clarify only the intent that can change what is built, then formalize the missing contract requirements. Commit whatever this zone wrote before handing the resulting contract to Deliver. + +A source is planning-ready when it names the artifact to change, states the observable outcome, and leaves open no decision that changes what is built. Resolving the ticket here is the one moment its backlog item is knowable — never guessed later from a folder name or a commit message. Carry it in `$resolved_source` so whichever of Spec or Plan first creates the delivery folder can declare it there, in `backlog-link.json`; a source with no ticket carries none, and the folder simply declares nothing. diff --git a/plugins/aidd-orchestrator/skills/01-sdlc/references/02-deliver.md b/plugins/aidd-orchestrator/skills/01-sdlc/references/02-deliver.md index c2b1a817c..7e094d169 100644 --- a/plugins/aidd-orchestrator/skills/01-sdlc/references/02-deliver.md +++ b/plugins/aidd-orchestrator/skills/01-sdlc/references/02-deliver.md @@ -2,7 +2,7 @@ ## Behavior -Turn the contract into a proportional plan, then give one executor the plan. The executor implements it and calls the validation skills, which own their checks and repair loops. Include architecture conformance whenever the project documents architecture. Run a required end-to-end journey after every other validation. +Turn the contract into a proportional plan, then give one executor the plan. The executor implements it and calls the validation skills, which own their checks and repair loops. Include architecture conformance whenever the project documents architecture. Run an end-to-end journey after every other validation when the plan calls for one, and none otherwise. Commit and push the validated work through the commit skill. Send only the clean committed candidate to Check. diff --git a/plugins/aidd-orchestrator/skills/01-sdlc/references/03-check.md b/plugins/aidd-orchestrator/skills/01-sdlc/references/03-check.md index c871e419f..ca5657884 100644 --- a/plugins/aidd-orchestrator/skills/01-sdlc/references/03-check.md +++ b/plugins/aidd-orchestrator/skills/01-sdlc/references/03-check.md @@ -2,9 +2,22 @@ ## Behavior -Use one fresh checker, independent from implementation, to review the candidate against the contract, plan, and validation evidence. After the review clears, the same checker challenges whether the real outcome is trustworthy and serves the user. +- Use one fresh checker, independent from implementation, to review the candidate against the contract, plan, and validation evidence. +- After the review clears, the same checker challenges whether the real outcome is trustworthy and serves the user. -Use product or contract findings as the next Frame source. Dispatch independent implementation findings through Todo and keep dependent repairs together in Deliver. Re-enter Check after every new candidate. Open the draft pull request when the checker returns no actionable finding. +## Findings + +A checker's finding is routed by what it is about. A refusal the user gives at a pause is not one of these: `mode.md` routes that by artifact. + +- Product or contract findings are the next Frame source. +- Independent implementation findings go through Todo; dependent repairs stay together in Deliver. +- Re-enter Check after every new candidate. +- Once the review has cleared, only a finding that contradicts the contract reopens a zone: carry any other onto the request as a note. +- A finding already acted on is never routed twice. Repaired or not, it is a decision that requires user authority, and no request opens until that arrives. + +## Handoff + +- Commit whatever this zone wrote, then open the draft pull request when the checker returns no actionable finding. ```mermaid --- diff --git a/plugins/aidd-orchestrator/skills/01-sdlc/references/mode.md b/plugins/aidd-orchestrator/skills/01-sdlc/references/mode.md new file mode 100644 index 000000000..716ac6fe7 --- /dev/null +++ b/plugins/aidd-orchestrator/skills/01-sdlc/references/mode.md @@ -0,0 +1,28 @@ +# Mode + +## Behavior + +- The mode is `auto` unless the caller asks for `interactive`, named as the request's first whole word and no part of the source. +- A request carrying nothing else is not one to run: say so and stop. +- Ask only before spending money, taking an irreversible action, or making a decision that requires user authority. +- An exception stops the action it guards, not the rest of the request. Say what was withheld and what would release it. + +## Auto + +- Operate autonomously from the request to a draft pull request: decide and act without confirmation. + +## Interactive + +- Pause on the contract, on the plan, and on the outcome, before the pull request opens: present what was produced and wait. +- Three pauses, one per artifact: the steps that produce one share its single pause, and clarifying and formalizing both produce the contract. Everything else runs without pausing. +- A step's own waits are part of producing the artifact; the pause is on the finished one, taken by the step that presents it or by you where none does. +- An artifact produced anew pauses again. +- An approval ships what was presented, with any correction it carries. + +## Refusal + +- A refusal at a pause is a finding against that artifact. +- Contract or spec to Frame, plan to Deliver, outcome to Deliver or to Frame when it changes what is being built. +- It routes by artifact, never by a finding's kind, and travels with the source. +- Say so and wait again when it names what the artifact already carries. +- Only the user bounds this loop.