diff --git a/tests/prose/cases/scoping-defines-the-quickfix/act.md b/tests/prose/cases/scoping-defines-the-quickfix/act.md new file mode 100644 index 000000000..80ca75b16 --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/act.md @@ -0,0 +1,4 @@ +Execute skills/workflow-scoping-entry/SKILL.md with arguments +$0=quick-fix, $1=support-email, and continue into the processing skill it +hands off to. Follow the whole scoping pass to its conclusion. Stop when +the prose reaches the pipeline continuation — do not invoke the bridge. diff --git a/tests/prose/cases/scoping-defines-the-quickfix/assert.md b/tests/prose/cases/scoping-defines-the-quickfix/assert.md new file mode 100644 index 000000000..f32ac7b6c --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/assert.md @@ -0,0 +1,46 @@ +The prose should have taken this path: + +1. the entry finds no scoping recorded, reads the carrier — the + description and the session log's exploration — and hands off with it; + the entry itself creates and asks nothing +2. no specification exists, so the pass starts fresh with no resume + choice put to the user +3. context gathering reads the seed and description first, and its + questions go to what the carrier does not answer — where the address + appears — not to the what and why it already holds. Two exchanges at + most +4. the complexity check passes silently: a mechanical single-purpose + change raises no warning and no promotion offer +5. the specification is written and registered through the engine — + started and completed — before any plan exists +6. with no project default recorded, the format choice is put to the + user, and the choice is recorded as the project default +7. tasks are written under the hard rules — at most two, no acceptance + criteria — and the plan is registered with its gates set to auto; + scoping itself is marked complete only after the plan is in place +8. the conclusion renders the completion display and reaches the bridge + handoff, where the walk stops without invoking it + +Further claims: + +- no agents are dispatched at any point — scoping writes its spec and + tasks directly +- nothing is implemented: no task is started, and nothing outside + `.workflows/` changes + +EXPECTED WORLD — from a work unit holding only its discovery carrier: + +- a specification at + `.workflows/support-email/specification/support-email/specification.md` + carrying the scoping shape — change description, scope, exclusions, + verification — and naming both the old and new addresses +- the scope reflecting what the user actually said: the checkout footer + and contact page as known sites, the transactional template as + suspected, with the exact locations left to implementation to confirm +- a plan at `.workflows/support-email/planning/support-email/planning.md` + with one or two task files beside it in local-markdown form, none of + them started +- the manifest holding specification, planning and scoping all completed, + the plan on the local-markdown format with its gates set to auto +- local-markdown recorded as the project's default plan format +- no implementation or review directories, and no second work unit diff --git a/tests/prose/cases/scoping-defines-the-quickfix/case.json b/tests/prose/cases/scoping-defines-the-quickfix/case.json new file mode 100644 index 000000000..7b9bb532a --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/case.json @@ -0,0 +1,53 @@ +{ + "origin": "quick-fix had no coverage anywhere — this walks its whole definition stage: entry, context, spec, format, tasks, conclusion, in the single pass scoping is", + "entry": "workflow-scoping-entry", + "world": "claims", + "files": [ + "skills/workflow-scoping-entry/SKILL.md", + "skills/workflow-scoping-entry/references/validate-phase.md", + "skills/workflow-scoping-entry/references/invoke-skill.md", + "skills/workflow-scoping-process/SKILL.md", + "skills/workflow-scoping-process/references/gather-context.md", + "skills/workflow-scoping-process/references/complexity-check.md", + "skills/workflow-scoping-process/references/write-specification.md", + "skills/workflow-scoping-process/references/select-format.md", + "skills/workflow-scoping-process/references/write-tasks.md", + "skills/workflow-scoping-process/references/conclude-scoping.md", + "skills/workflow-shared/references/seed-context.md", + "skills/workflow-knowledge/references/knowledge-usage.md", + "skills/workflow-knowledge/references/contextual-query.md", + "skills/workflow-planning-process/references/output-formats.md", + "skills/workflow-planning-process/references/output-formats/local-markdown/about.md", + "skills/workflow-planning-process/references/output-formats/local-markdown/authoring.md" + ], + "conduct": "The user knows exactly what the change is and why: the support@ mailbox is being retired at the end of the month and mail to it already bounces, so everything should say help@ instead. Asked where it appears, they are sure about the checkout footer and the contact page, think it may also be in a transactional email template, and do not know any file names. They have no exceptions or exclusions to name. When offered tooling or format choices they take the simplest option that adds no external dependencies — plain files in the repo. They answer the question asked, concretely, and say plainly when they do not know.", + "invariants": { + "engine_before_write": true, + "calls_include": [ + "manifest get support-email.scoping.support-email status", + "manifest get support-email description", + "topic start support-email specification support-email", + "topic complete support-email specification support-email", + "topic start support-email planning support-email", + "topic complete support-email planning support-email", + "topic complete support-email scoping support-email", + "project.defaults.plan_format local-markdown", + "render phase-completed support-email --phase scoping" + ], + "calls_in_order": [ + "manifest get support-email.scoping.support-email status", + "topic start support-email specification support-email", + "topic complete support-email specification support-email", + "topic start support-email planning support-email", + "topic complete support-email planning support-email", + "topic complete support-email scoping support-email", + "render phase-completed support-email --phase scoping" + ], + "calls_exclude": [ + "task start", + "task next", + "topic reopen", + "workflow-bridge" + ] + } +} diff --git a/tests/prose/cases/scoping-defines-the-quickfix/fixture-state.cjs b/tests/prose/cases/scoping-defines-the-quickfix/fixture-state.cjs new file mode 100644 index 000000000..a2b1be75b --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/fixture-state.cjs @@ -0,0 +1,12 @@ +'use strict'; + +// The quick-fix is captured and its definition stage has not begun. + +const m = require('../../mainlines/quickfix.cjs'); + +module.exports = { + build(h) { + m.init(h); + m.create(h); + }, +}; diff --git a/tests/prose/cases/scoping-defines-the-quickfix/fixture.md b/tests/prose/cases/scoping-defines-the-quickfix/fixture.md new file mode 100644 index 000000000..6a89d4544 --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/fixture.md @@ -0,0 +1,8 @@ +A quick-fix shaped in discovery: the retired support email address needs +replacing with the new one wherever it appears. The work unit exists with +its session log; scoping has not begun, and no specification or plan +exists anywhere. + +The context was cleared at the phase boundary — this session opens cold +at the entry skill with nothing but the two arguments and what is on +disk. diff --git a/tests/prose/cases/scoping-defines-the-quickfix/fixture/.claude/settings.json b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.claude/settings.json new file mode 100644 index 000000000..ae019ede5 --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.claude/settings.json @@ -0,0 +1,9 @@ +{ + "showClearContextOnPlanAccept": true, + "permissions": { + "allow": [ + "Edit(.workflows/**)", + "Bash(mv .workflows/:*)" + ] + } +} diff --git a/tests/prose/cases/scoping-defines-the-quickfix/fixture/.recipe-hash b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.recipe-hash new file mode 100644 index 000000000..e7b27d15d --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.recipe-hash @@ -0,0 +1 @@ +ddb2aec6b94ecc0e076a44f9f1cfb6293f30cca9dcc9f933a57276c03f1e8314 diff --git a/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/.state/migrations b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/.state/migrations new file mode 100644 index 000000000..3c7162acc --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/.state/migrations @@ -0,0 +1,52 @@ +001 +002 +003 +004 +005 +006 +007 +008 +009 +010 +011 +012 +013 +014 +015 +016 +017 +018 +019 +020 +021 +022 +023 +024 +025 +026 +027 +028 +029 +030 +031 +032 +033 +034 +035 +036 +037 +038 +039 +040 +041 +042 +043 +044 +045 +046 +047 +048 +049 +050 +051 +052 diff --git a/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/_gitignore.fixture b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/_gitignore.fixture new file mode 100644 index 000000000..779cbf28a --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/_gitignore.fixture @@ -0,0 +1,2 @@ +.cache/ +.manifest.json.*.tmp diff --git a/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/manifest.json b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/manifest.json new file mode 100644 index 000000000..7cb70c695 --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/manifest.json @@ -0,0 +1,7 @@ +{ + "work_units": { + "support-email": { + "work_type": "quick-fix" + } + } +} diff --git a/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/support-email/discovery/sessions/session-001.md b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/support-email/discovery/sessions/session-001.md new file mode 100644 index 000000000..2b2fb8f08 --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/support-email/discovery/sessions/session-001.md @@ -0,0 +1,40 @@ +# Discovery Session 001 + +Date: 2026-01-01 +Work unit: support-email + +## Description (as of session) + +Replace the retired support email address with the new one. + +## Seed + +(none) + +## Imports + +(none) + +## Map State at Start + +(n/a — single-topic work) + +## Exploration + +The support@ mailbox is being retired at the end of the month and +mail to it already bounces for some customers; everything should +point at help@ instead. Purely mechanical — same links, same copy, +different address. The user was not sure everywhere it appears and +wants that pinned down during scoping. Confirmed as a quick-fix. + +## Edits + +(none) + +## Topics Identified + +(none) + +## Conclusion + +(none) diff --git a/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/support-email/manifest.json b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/support-email/manifest.json new file mode 100644 index 000000000..d76322354 --- /dev/null +++ b/tests/prose/cases/scoping-defines-the-quickfix/fixture/.workflows/support-email/manifest.json @@ -0,0 +1,8 @@ +{ + "name": "support-email", + "work_type": "quick-fix", + "status": "in-progress", + "created": "2026-01-01", + "description": "Replace the retired support email address with the new one", + "phases": {} +} diff --git a/tests/prose/mainlines/quickfix.cjs b/tests/prose/mainlines/quickfix.cjs new file mode 100644 index 000000000..4c98b39b3 --- /dev/null +++ b/tests/prose/mainlines/quickfix.cjs @@ -0,0 +1,72 @@ +'use strict'; + +// Quick-fix mainline: the smallest pipeline shape. Discovery shapes the +// work and commits it; scoping is the whole definition stage in one pass. +// +// The Exploration deliberately holds the what and the why but not the +// where. Scoping's gather-context skips its questions when the carrier +// already captures all three, and that guard is a judgement call — a +// carrier that plainly lacks the where makes the questioning arm the only +// honest reading, which is what the scoping case needs to exercise. + +const WU = 'support-email'; + +function init(h) { + h.knowledge('setup', '--keyword-only'); + h.engine('boot'); +} + +function create(h) { + // Shape per workflow-discovery/references/template.md + confirm-trigger.md: + // single-phase work backfills Exploration at creation; Edits, Topics + // Identified, and Conclusion land as (none). + const log = `.workflows/${WU}/discovery/sessions/session-001.md`; + h.write(log, [ + '# Discovery Session 001', + '', + 'Date: 2026-01-01', + `Work unit: ${WU}`, + '', + '## Description (as of session)', + '', + 'Replace the retired support email address with the new one.', + '', + '## Seed', + '', + '(none)', + '', + '## Imports', + '', + '(none)', + '', + '## Map State at Start', + '', + '(n/a — single-topic work)', + '', + '## Exploration', + '', + 'The support@ mailbox is being retired at the end of the month and', + 'mail to it already bounces for some customers; everything should', + 'point at help@ instead. Purely mechanical — same links, same copy,', + 'different address. The user was not sure everywhere it appears and', + 'wants that pinned down during scoping. Confirmed as a quick-fix.', + '', + '## Edits', + '', + '(none)', + '', + '## Topics Identified', + '', + '(none)', + '', + '## Conclusion', + '', + '(none)', + '', + ].join('\n')); + h.engine('workunit', 'create', WU, 'quick-fix', + '--description', 'Replace the retired support email address with the new one', + '--session-log-file', log); +} + +module.exports = { WU, init, create };