From 21ef0f440ac387be3576dedcb096d28ba7fc2041 Mon Sep 17 00:00:00 2001 From: rpogula Date: Wed, 22 Jul 2026 09:23:50 -0400 Subject: [PATCH 1/2] feat(atd): add ATD SDLC schemas, change triage, and adoption collateral MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initial commit of the ATD adoption track on top of upstream v1.6.0 (additive only — no engine changes): - schemas/atd-sdlc: full pipeline ticket → analysis → (specs, design) → solution-doc → tasks; Jira/Confluence intake with grilling protocol, branch-alignment suggestion, confirmed idempotent write-back, code-as-truth analysis (SHA + file:line), AC traceability, scaled solution document, mandatory final task group (standards conformance, reconciliation, publication, Jira closure) - schemas/atd-sdlc-lite: three-artifact pipeline for low-risk corrections; semantically-gated triage sidecar (all-pass + lite recommendation + lite choice), embedded canonical 13-condition eligibility table, one-way escalation incl. late escalation via tasks.lite.md - atd-change-triage workflow (skill + /opsx:atd-triage command) in CORE_WORKFLOWS; registered across all enumerating surfaces incl. tool-detection - docs/atd: config template, standards-store conventions, lite-eligibility table, adoption track with pilot metrics, bootstrap - OpenSpec changes: add-atd-sdlc-schema and add-atd-sdlc-lite-triage (implemented), add-atd-docs-site and add-atd-workflow-facades (proposed) - tests: schema resolution/gates, instruction contracts, cross-surface condition-list parity (normalized ordered comparison), escalation status, instruction assembly with rules/references, triage-only detection — full suite 2095 passing External prerequisite: atd-standards store (placeholder seeded from the atd-angular skill; angular real, other three stacks pending stack leads). --- .gitignore | 23 ++ AGENTS.md | 60 ++++ docs/atd/adoption-track.md | 63 +++++ docs/atd/bootstrap.md | 40 +++ docs/atd/bootstrap.sh | 31 +++ docs/atd/config-template.yaml | 37 +++ docs/atd/lite-eligibility.md | 65 +++++ docs/atd/standards-store.md | 53 ++++ .../changes/add-atd-docs-site/.openspec.yaml | 2 + openspec/changes/add-atd-docs-site/design.md | 57 ++++ .../changes/add-atd-docs-site/proposal.md | 31 +++ .../specs/atd-developer-docs/spec.md | 65 +++++ openspec/changes/add-atd-docs-site/tasks.md | 35 +++ .../add-atd-sdlc-lite-triage/.openspec.yaml | 2 + .../add-atd-sdlc-lite-triage/design.md | 74 +++++ .../add-atd-sdlc-lite-triage/proposal.md | 33 +++ .../specs/atd-change-triage/spec.md | 94 +++++++ .../specs/atd-sdlc-lite-workflow/spec.md | 62 +++++ .../changes/add-atd-sdlc-lite-triage/tasks.md | 23 ++ .../add-atd-sdlc-schema/.openspec.yaml | 2 + .../changes/add-atd-sdlc-schema/design.md | 100 +++++++ .../changes/add-atd-sdlc-schema/proposal.md | 39 +++ .../specs/atd-sdlc-workflow/spec.md | 128 +++++++++ .../specs/solution-documentation/spec.md | 55 ++++ .../specs/standards-integration/spec.md | 39 +++ openspec/changes/add-atd-sdlc-schema/tasks.md | 34 +++ .../add-atd-workflow-facades/.openspec.yaml | 2 + .../add-atd-workflow-facades/design.md | 76 +++++ .../add-atd-workflow-facades/proposal.md | 40 +++ .../specs/atd-workflow-facades/spec.md | 98 +++++++ .../changes/add-atd-workflow-facades/tasks.md | 34 +++ schemas/atd-sdlc-lite/schema.yaml | 217 +++++++++++++++ schemas/atd-sdlc-lite/templates/analysis.md | 20 ++ schemas/atd-sdlc-lite/templates/tasks.md | 11 + schemas/atd-sdlc-lite/templates/ticket.md | 33 +++ schemas/atd-sdlc/schema.yaml | 259 ++++++++++++++++++ schemas/atd-sdlc/templates/analysis.md | 20 ++ schemas/atd-sdlc/templates/design.md | 17 ++ schemas/atd-sdlc/templates/solution.md | 35 +++ schemas/atd-sdlc/templates/spec.md | 11 + schemas/atd-sdlc/templates/tasks.md | 13 + schemas/atd-sdlc/templates/ticket.md | 35 +++ skills/atd-change-triage/SKILL.md | 127 +++++++++ src/core/profile-sync-drift.ts | 1 + src/core/profiles.ts | 3 +- src/core/shared/skill-generation.ts | 4 + src/core/shared/tool-detection.ts | 2 + src/core/templates/skill-templates.ts | 1 + src/core/templates/workflows/atd-triage.ts | 148 ++++++++++ test/commands/config-profile.test.ts | 7 +- test/commands/config.test.ts | 2 +- .../atd-sdlc-lite-schema.test.ts | 252 +++++++++++++++++ .../artifact-graph/atd-sdlc-schema.test.ts | 194 +++++++++++++ test/core/atd-triage-workflow.test.ts | 200 ++++++++++++++ test/core/profiles.test.ts | 7 +- test/core/shared/skill-generation.test.ts | 12 +- test/core/shared/tool-detection.test.ts | 24 +- test/core/update.test.ts | 6 +- 58 files changed, 3140 insertions(+), 18 deletions(-) create mode 100644 docs/atd/adoption-track.md create mode 100644 docs/atd/bootstrap.md create mode 100755 docs/atd/bootstrap.sh create mode 100644 docs/atd/config-template.yaml create mode 100644 docs/atd/lite-eligibility.md create mode 100644 docs/atd/standards-store.md create mode 100644 openspec/changes/add-atd-docs-site/.openspec.yaml create mode 100644 openspec/changes/add-atd-docs-site/design.md create mode 100644 openspec/changes/add-atd-docs-site/proposal.md create mode 100644 openspec/changes/add-atd-docs-site/specs/atd-developer-docs/spec.md create mode 100644 openspec/changes/add-atd-docs-site/tasks.md create mode 100644 openspec/changes/add-atd-sdlc-lite-triage/.openspec.yaml create mode 100644 openspec/changes/add-atd-sdlc-lite-triage/design.md create mode 100644 openspec/changes/add-atd-sdlc-lite-triage/proposal.md create mode 100644 openspec/changes/add-atd-sdlc-lite-triage/specs/atd-change-triage/spec.md create mode 100644 openspec/changes/add-atd-sdlc-lite-triage/specs/atd-sdlc-lite-workflow/spec.md create mode 100644 openspec/changes/add-atd-sdlc-lite-triage/tasks.md create mode 100644 openspec/changes/add-atd-sdlc-schema/.openspec.yaml create mode 100644 openspec/changes/add-atd-sdlc-schema/design.md create mode 100644 openspec/changes/add-atd-sdlc-schema/proposal.md create mode 100644 openspec/changes/add-atd-sdlc-schema/specs/atd-sdlc-workflow/spec.md create mode 100644 openspec/changes/add-atd-sdlc-schema/specs/solution-documentation/spec.md create mode 100644 openspec/changes/add-atd-sdlc-schema/specs/standards-integration/spec.md create mode 100644 openspec/changes/add-atd-sdlc-schema/tasks.md create mode 100644 openspec/changes/add-atd-workflow-facades/.openspec.yaml create mode 100644 openspec/changes/add-atd-workflow-facades/design.md create mode 100644 openspec/changes/add-atd-workflow-facades/proposal.md create mode 100644 openspec/changes/add-atd-workflow-facades/specs/atd-workflow-facades/spec.md create mode 100644 openspec/changes/add-atd-workflow-facades/tasks.md create mode 100644 schemas/atd-sdlc-lite/schema.yaml create mode 100644 schemas/atd-sdlc-lite/templates/analysis.md create mode 100644 schemas/atd-sdlc-lite/templates/tasks.md create mode 100644 schemas/atd-sdlc-lite/templates/ticket.md create mode 100644 schemas/atd-sdlc/schema.yaml create mode 100644 schemas/atd-sdlc/templates/analysis.md create mode 100644 schemas/atd-sdlc/templates/design.md create mode 100644 schemas/atd-sdlc/templates/solution.md create mode 100644 schemas/atd-sdlc/templates/spec.md create mode 100644 schemas/atd-sdlc/templates/tasks.md create mode 100644 schemas/atd-sdlc/templates/ticket.md create mode 100644 skills/atd-change-triage/SKILL.md create mode 100644 src/core/templates/workflows/atd-triage.ts create mode 100644 test/core/artifact-graph/atd-sdlc-lite-schema.test.ts create mode 100644 test/core/artifact-graph/atd-sdlc-schema.test.ts create mode 100644 test/core/atd-triage-workflow.test.ts diff --git a/.gitignore b/.gitignore index 1fb5c4a26a..fdadd07c93 100644 --- a/.gitignore +++ b/.gitignore @@ -166,3 +166,26 @@ opencode.json # Cursor .cursor/ +.agent/skills/openspec-apply-change/SKILL.md +.agent/skills/openspec-archive-change/SKILL.md +.agent/skills/openspec-explore/SKILL.md +.agent/skills/openspec-propose/SKILL.md +.agent/skills/openspec-sync-specs/SKILL.md +.agent/skills/openspec-update-change/SKILL.md +.agent/workflows/opsx-apply.md +.agent/workflows/opsx-archive.md +.agent/workflows/opsx-explore.md +.agent/workflows/opsx-propose.md +.agent/workflows/opsx-sync.md +.agent/workflows/opsx-update.md +.lavish/atd-sdlc-feasibility-review.html +.lavish/atd-sdlc-plan.html +.tokensave/branch-meta.json +.tokensave/config.json +.tokensave/tokensave.db +.tokensave/tokensave.db-shm +.tokensave/tokensave.db-wal +TRASH/docs-publishing-spec/spec.md +TRASH/telemetry-spec/spec.md +TRASH-FILES.md +.agent/ diff --git a/AGENTS.md b/AGENTS.md index e69de29bb2..a043ec18b8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -0,0 +1,60 @@ +# ATD-OpenSpec + +## What this project is + +ATD's fork of [Fission-AI/OpenSpec](https://github.com/Fission-AI/OpenSpec) (forked at v1.6.0). OpenSpec is a spec-driven development CLI: work is organized into **changes**, each change walks a **schema** (a DAG of artifacts — proposal, specs, design, tasks, …), and AI agents execute the workflow through generated **skills** and **slash commands**. + +The fork adds an ATD-specific SDLC on top of the unmodified engine. **Fork policy: additive only** — new schemas, new workflow templates, new docs, additive registry entries. Core engine code (artifact-graph, resolver, CLI behavior) is never modified, so upstream syncs stay cheap. + +## The goal + +One workflow every ATD developer follows from **Jira ticket to documented, standards-conformant code**, across all four stacks (Python, Spring Boot, Oracle EBS PL/SQL, Angular): + +1. **Triage** — classify a ticket as low-risk (lite) or full via a risk-based eligibility table; uncertainty always routes full. +2. **Ticket intake** — pull Jira + linked Confluence via the Atlassian MCP, gate on a completeness checklist, grill the developer one question at a time when data is missing, write clarified requirements back to Jira (confirmed, idempotent). +3. **Analysis** — code is the source of truth; every claim cites commit SHA + file:line; affected stacks named. +4. **Specs / Design / Solution doc** — every requirement traces to an acceptance-criterion ID; the enterprise solution document exists *before* implementation. +5. **Apply** — fetch the mapped coding standards per stack from the external `atd-standards` store, implement, then a mandatory final task group: standards conformance, solution-doc reconciliation, publication (Confluence/repo/both), idempotent Jira closure. +6. **Escalation** — lite changes escalate one-way to full when wider impact surfaces (never downgrade). + +## Structure + +``` +schemas/ Workflow schemas (resolved built-in → user-global → project-local) +├── spec-driven/ Upstream default (untouched) +├── atd-sdlc/ Full ATD pipeline: ticket → analysis → (specs, design) → solution-doc → tasks +└── atd-sdlc-lite/ Lite pipeline for low-risk corrections: ticket → analysis → tasks +src/ +├── core/artifact-graph/ Schema engine: resolver, graph, state, instruction assembly (DO NOT fork-modify) +├── core/templates/workflows/ One module per workflow skill/command (atd-triage.ts is the ATD pattern) +├── core/shared/ skill-generation.ts (registries), tool-detection.ts (SKILL_NAMES/COMMAND_IDS) +├── core/profiles.ts CORE_WORKFLOWS / ALL_WORKFLOWS +└── core/profile-sync-drift.ts WORKFLOW_TO_SKILL_DIR +skills/ COMMITTED generated artifacts (skills.sh distribution) — regenerate, + never hand-edit (.claude/ is local per-machine config, gitignored) +docs/atd/ ATD rollout collateral: config template, standards-store conventions, + lite-eligibility table, adoption track, bootstrap +openspec/changes/ In-flight OpenSpec changes (the fork dogfoods itself): + add-atd-sdlc-schema (implemented), add-atd-sdlc-lite-triage (implemented), + add-atd-docs-site (proposed), add-atd-workflow-facades (proposed) +test/ Vitest suite (~2,090 tests) +``` + +External: the `atd-standards` OpenSpec store (separate repo, registered per machine) holds the four standards specs. Stack mapping: python → python-service-standards, spring-boot → spring-boot-standards, oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards. + +## Commands + +```bash +node build.js # build dist/ +./node_modules/.bin/vitest run # full test suite (pnpm test) +node scripts/generate-skillssh.mjs # regenerate committed skills/ from templates +node bin/openspec.js # run the repo's own CLI +``` + +## Rules for agents working here + +- **Work through OpenSpec.** Changes to fork behavior get a change under `openspec/changes/` first (proposal → specs → design → tasks → apply). Don't patch schemas or workflows ad hoc. +- **Adding a workflow touches every enumerating surface** — template module + `skill-templates.ts` export + both registries in `skill-generation.ts` + `ALL_WORKFLOWS`/`CORE_WORKFLOWS` + `WORKFLOW_TO_SKILL_DIR` + `SKILL_NAMES`/`COMMAND_IDS` in `tool-detection.ts` + regenerated `skills/` and `.claude/` artifacts + test count bumps. Missing one is the known bug class here. +- **Parity tests are contracts.** Shared instruction blocks between `atd-sdlc` and `atd-sdlc-lite` must match byte-for-byte; every deployed template must contain the `STORE_SELECTION_GUIDANCE` block; committed `skills/` must match generator output. +- **Schema instructions are the product.** Anti-slop rules are deliberate: omit inapplicable sections, no boilerplate, diagrams only when the flow is non-trivial, uncertainty routes to the heavier path. +- **Never ship references to unpackaged files** — npm `files` includes `dist`, `bin`, `schemas` only; `docs/` does not ship, so schema/skill instructions must embed what they need. diff --git a/docs/atd/adoption-track.md b/docs/atd/adoption-track.md new file mode 100644 index 0000000000..f50fb4be3e --- /dev/null +++ b/docs/atd/adoption-track.md @@ -0,0 +1,63 @@ +# ATD adoption track + +Changes in the ATD fork's adoption sequence, their status, and pilot metrics. + +## Shipped / in flight + +1. **add-atd-sdlc-schema** — the `atd-sdlc` built-in schema (this repo). +2. **add-atd-sdlc-lite-triage** — `atd-sdlc-lite` schema plus `atd-change-triage` + entry-point skill (companion change). + +## Prerequisite: establish-atd-standards-store (separately owned) + +Owned outside this repository by the stack leads. Pilot wave 1 is **blocked** +until every acceptance check passes. + +A **placeholder store** exists at `~/git/ATD-AI/atd-standards` (local; no +approved ATD remote yet): `angular-standards` is seeded from the internal +`atd-angular` skill; the other three specs are strict-valid placeholders +awaiting stack-lead content. + +- [x] Standalone `atd-standards` repository exists (local placeholder; remote pending). +- [x] All four mapped specs present and strict-valid: + `python-service-standards`, `spring-boot-standards`, + `oracle-ebs-plsql-standards`, `angular-standards` + (angular seeded with real content; the other three are placeholders). +- [ ] Stack-lead owners named per spec; CODEOWNERS enforces review. + Owners: python — TBD; spring-boot — TBD; oracle-ebs — TBD; angular — TBD. +- [ ] Registration/bootstrap instructions verified on a clean machine. +- [x] A pilot machine passes `openspec store doctor atd-standards` and + successfully fetches every mapped spec + (`openspec show --type spec --store atd-standards`). + +## Follow-up changes (to be proposed) + +1. **atlassian-integration-hardening** — idempotency helpers for managed + sections and closure comments, retry/error guidance, data governance for + what may be written to Jira/Confluence. +2. **telemetry-opt-in-default** — flip fork telemetry to opt-in for internal + distribution. +3. **internal-package-identity** — `@atd/openspec` rename and internal release + pipeline: changesets, pack checks, registry auth, workflow guards. +4. **standards-ci-enforcement** — promote recurring pilot deviation classes + into deterministic CI checks (lint rules, custom analyzers). Sourced from + pilot metrics below. + +## Pilot metrics + +Captured per pilot wave (wave 1: one Python or Angular repo → Spring Boot → +Oracle EBS → org-wide): + +| Metric | Source | +|--------|--------| +| Clarification count per ticket | grilling Q/A trace in ticket.md | +| Artifact rework | change history | +| Standards deviations (by class) | conformance tasks in tasks.md | +| Documentation completion | published solution.md per closed ticket | +| External-write failures | Jira/Confluence task outcomes | +| Cycle time | ticket → archive | +| Lite/full selection rate | triage.md records (lite-triage change) | +| Lite→full escalation rate | triage.md escalation entries | + +Recurring standards-deviation classes and missing-documentation findings feed +**standards-ci-enforcement**. diff --git a/docs/atd/bootstrap.md b/docs/atd/bootstrap.md new file mode 100644 index 0000000000..2b58ebcd8f --- /dev/null +++ b/docs/atd/bootstrap.md @@ -0,0 +1,40 @@ +# ATD developer bootstrap (draft) + +One-time machine setup for the ATD OpenSpec workflow. **Draft** — package name +and registry finalize when the `internal-package-identity` change lands. + +## Steps + +1. **Internal npm configuration** — point the ATD scope at the internal + registry (exact scope/registry TBD by internal-package-identity): + + ```bash + npm config set @atd:registry + ``` + +2. **Install the CLI**: + + ```bash + npm install -g @atd/openspec # placeholder name until package-identity lands + ``` + +3. **Register the standards store**: + + ```bash + git clone ~/atd-standards + openspec store register ~/atd-standards + openspec store doctor atd-standards + ``` + +4. **Verify the Atlassian MCP** is configured in your agent tool (Claude Code, + Cursor, …) and can read a Jira issue. The ticket artifact falls back to + pasted content when the MCP is unavailable, but write-back and closure + comments require it. + +5. **Health check**: + + ```bash + openspec doctor + ``` + +See `bootstrap.sh` for the scripted skeleton of the same steps. diff --git a/docs/atd/bootstrap.sh b/docs/atd/bootstrap.sh new file mode 100755 index 0000000000..e4723cadec --- /dev/null +++ b/docs/atd/bootstrap.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# ATD developer bootstrap — DRAFT SKELETON. +# Finalized when the internal-package-identity change lands (package name, +# registry URL, and store remote are placeholders). +set -euo pipefail + +REGISTRY_URL="${ATD_NPM_REGISTRY:?set ATD_NPM_REGISTRY to the internal registry URL}" +STANDARDS_REMOTE="${ATD_STANDARDS_REMOTE:?set ATD_STANDARDS_REMOTE to the atd-standards git remote}" +STANDARDS_DIR="${ATD_STANDARDS_DIR:-$HOME/atd-standards}" + +echo "==> Configuring internal npm registry" +npm config set @atd:registry "$REGISTRY_URL" + +echo "==> Installing OpenSpec CLI" +npm install -g @atd/openspec # placeholder until package-identity lands + +echo "==> Registering atd-standards store" +if [ ! -d "$STANDARDS_DIR" ]; then + git clone "$STANDARDS_REMOTE" "$STANDARDS_DIR" +else + git -C "$STANDARDS_DIR" pull --ff-only +fi +openspec store register "$STANDARDS_DIR" +openspec store doctor atd-standards + +echo "==> Atlassian MCP: verify manually in your agent tool (read a Jira issue)." + +echo "==> Health check" +openspec doctor + +echo "Bootstrap complete." diff --git a/docs/atd/config-template.yaml b/docs/atd/config-template.yaml new file mode 100644 index 0000000000..e391d61237 --- /dev/null +++ b/docs/atd/config-template.yaml @@ -0,0 +1,37 @@ +# ATD per-repo openspec/config.yaml template +# Copy to /openspec/config.yaml and edit the stack block + rules for your repo. + +schema: atd-sdlc + +# Reference the shared standards store (register once per machine: +# openspec store register ) +references: + - atd-standards + +# Free-text project context injected into every artifact instruction. +# Keep ONE stack block (delete the others) and fill in your repo's specifics. +context: | + Stack: python # one of: python | spring-boot | oracle-ebs | angular + Service: + Domain notes: + Team conventions: + +# Per-artifact rules. Keys MUST be artifact IDs of the atd-sdlc schema +# (ticket, analysis, specs, design, solution-doc, tasks) — unknown keys are +# warned and never injected. There is no "apply" or "docs" key. +rules: + # Documentation destination rides the tasks rules and lands in the generated + # publication tasks. Pick one form: + tasks: + - "Documentation destination: repo" + # - "Documentation destination: confluence — space , parent page " + # - "Documentation destination: both — repo docs/ plus Confluence space , parent " + + # Optional: name code-index/code-graph tooling the agent should prefer over + # raw file reads during analysis. + # analysis: + # - "Prefer the tokensave MCP tools for symbol lookup and call-path tracing" + + # Optional: disable the confirmed Jira write-back for this repo. + # ticket: + # - "Jira write-back is disabled for this repository" diff --git a/docs/atd/lite-eligibility.md b/docs/atd/lite-eligibility.md new file mode 100644 index 0000000000..ff8ba9e0ef --- /dev/null +++ b/docs/atd/lite-eligibility.md @@ -0,0 +1,65 @@ +# Lite eligibility decision table + +`atd-change-triage` evaluates every condition below. **Lite applies only when +ALL conditions pass. Any failure or uncertainty routes to the full `atd-sdlc` +schema.** + +| # | Condition | +|---|-----------| +| 1 | Single repository and single component | +| 2 | Small, localized file impact | +| 3 | Restores existing intended behavior (no new behavior) | +| 4 | Existing acceptance criteria, specification, or test already defines the behavior | +| 5 | No API contract change | +| 6 | No database/schema/data migration | +| 7 | No authentication, authorization, security, privacy, or compliance impact | +| 8 | No cross-service integration behavior change | +| 9 | No new dependency | +| 10 | No deployment or infrastructure change | +| 11 | Straightforward automated regression test exists or is easy to add | +| 12 | Trivial rollback | +| 13 | No new functional or technical documentation needed (localized corrections to existing docs stay lite-eligible) | + +Note on condition 13: "new documentation" means a new solution document or +durable doc set. Localized corrections to existing documentation remain +lite-eligible only while they do not reveal a full-workflow impact. + +## Risk, never line count + +Classification is risk-based. A one-line change is NOT automatically lite. +One-liners that always route full: + +- **Authorization conditions** — a flipped `&&`/`||` in an access check. +- **SQL predicates** — a changed `WHERE` clause. +- **Financial calculations** — rounding, rates, totals. + +## Bounded preflight (mandatory before recommending lite) + +Conditions 1, 2, 4, 5–11 cannot be reliably determined from Jira text alone. +Before classifying, inspect the codebase — scoped to the ticket, lighter than +a full `analysis.md`, only enough to classify safely: + +- Locate the owning component. +- Inspect the relevant entry points and call path. +- Identify existing tests or specifications covering the behavior. +- Check for API contract, data, security, dependency, integration, and + deployment impact. + +Anything not verifiable from the ticket or the inspected code is **uncertain** +and routes full. + +## Monotonic override policy + +- Triage recommends **lite** → developer may choose lite or strengthen to full. +- Triage recommends **full** → full is mandatory. A downgrade request is + declined, quoting the failed or uncertain conditions. +- After creation, escalation is one-way: lite → full only (see the lite + schema's analysis and apply instructions). Full → lite is never supported + once planning artifacts exist. + +## Audit trail + +Every triage decision is recorded in a `triage.md` sidecar in the change +directory: the recommendation, each condition's evaluation, and the confirmed +choice. Escalations append their trigger and schema transition. Pilot metrics +(lite/full selection rate, escalation rate) are sourced from these records. diff --git a/docs/atd/standards-store.md b/docs/atd/standards-store.md new file mode 100644 index 0000000000..f93732c8e1 --- /dev/null +++ b/docs/atd/standards-store.md @@ -0,0 +1,53 @@ +# atd-standards store conventions + +The `atd-standards` store is a standalone OpenSpec root (its own repository) +holding ATD's coding standards as specs. Every ATD repo references it via +`references: [atd-standards]` in `openspec/config.yaml`. + +## Stack → spec mapping (explicit, exhaustive) + +| Stack | Standards spec | +|-------|----------------| +| `python` | `python-service-standards` | +| `spring-boot` | `spring-boot-standards` | +| `oracle-ebs` | `oracle-ebs-plsql-standards` | +| `angular` | `angular-standards` | + +The `atd-sdlc` schema uses this mapping in two places: + +- **Apply time** — before implementing any task, the agent fetches the spec + mapped to each stack listed in `analysis.md` and conforms to it. +- **Tasks** — the mandatory final task group contains one conformance task per + affected stack, naming the mapped spec. + +## Registering the store + +```bash +git clone ~/atd-standards +openspec store register ~/atd-standards +``` + +With the store registered and the repo's config declaring +`references: [atd-standards]`, generated instructions carry an index of the +standards specs (one-line summaries plus fetch recipes). If the store is not +registered, instruction generation degrades to a warning diagnostic — it does +not fail — but apply-time standards consultation is impossible, so +registration is part of developer bootstrap. + +## Updating standards + +Standards are specs; changes to them go through the store's own OpenSpec +workflow (propose → review → sync). One edit propagates to every ATD repo on +the next instruction generation — no fork release, no per-repo copying. +Stack leads own their spec (see CODEOWNERS in the store repository). + +Propagation reads YOUR LOCAL CLONE: refresh it to pick up upstream edits — +`git -C ~/atd-standards pull --ff-only` (the bootstrap script does this on +re-run). A stale clone silently serves stale standards. + +## Adding a new stack + +1. Add `-standards` spec to the store. +2. Extend the explicit mapping in the `atd-sdlc` schema's `analysis`, `tasks`, + and `apply` instructions (fork change required — the mapping is deliberately + explicit, never inferred). diff --git a/openspec/changes/add-atd-docs-site/.openspec.yaml b/openspec/changes/add-atd-docs-site/.openspec.yaml new file mode 100644 index 0000000000..7250f8fbf8 --- /dev/null +++ b/openspec/changes/add-atd-docs-site/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-07-22 diff --git a/openspec/changes/add-atd-docs-site/design.md b/openspec/changes/add-atd-docs-site/design.md new file mode 100644 index 0000000000..e896266774 --- /dev/null +++ b/openspec/changes/add-atd-docs-site/design.md @@ -0,0 +1,57 @@ +# Design: ATD Developer Docs Site + +## Context + +`add-atd-sdlc-schema` and `add-atd-sdlc-lite-triage` shipped the workflow; their proposal/design documents and `docs/atd/*.md` are accurate but written for maintainers of this fork. Developers joining pilot waves need consumer-facing onboarding: purpose, setup, the flows their tickets take, and worked examples. The destination decision is already made with the user: MkDocs Material, docs-as-code in this repo, GitHub Pages via Actions. + +## Goals / Non-Goals + +**Goals** + +- One browsable site covering why → architecture → getting started → flows → standards → examples → reference. +- Docs live next to the schemas they describe, so a schema change and its docs change share one PR (anti-drift). +- Zero operational burden beyond editing markdown — CI builds and deploys. + +**Non-Goals** + +- Documenting upstream OpenSpec generally (link out to upstream docs). +- Site versioning before a second major workflow version exists. +- CI machinery that content-checks docs against schema instructions. +- Replacing `docs/atd/` rollout collateral — it stays the maintainer source of truth. + +## Decisions + +### D1: MkDocs Material, not Confluence and not a README tree + +Material gives markdown-in-repo, native mermaid rendering (superfences), instant search, and a one-step CI build. Alternative: Confluence as the primary home — rejected because WYSIWYG edits happen outside PR review, which breaks the same-PR anti-drift rule and reintroduces the docs/code divergence this site exists to prevent; Confluence survives only as the publishing fallback (D6). Alternative: a plain `README.md`/`docs/` tree — rejected; no navigation or search, and it is essentially what `docs/atd/` already is, which demonstrably does not onboard consumers. + +### D2: Same repo, not a separate docs repo + +The anti-drift rule is only enforceable when the schema diff and the docs diff are reviewable in one PR. A separate docs repo needs cross-repo coordination for every schema change and recreates the drift problem with extra ceremony. Rejected. + +### D3: No versioning (no mike) yet + +`mike` adds version-selector machinery to serve multiple doc versions; there is exactly one workflow version. Latest-on-main is correct until a breaking schema revision ships, at which point adopting mike is a small, isolated change. Alternative: setting up mike now "to be ready" — rejected as machinery ahead of need. + +### D4: Anti-drift via PR checklist + strict build, not content-checking CI + +A CI job that verifies "docs describe the schemas" would have to parse instruction prose and diff semantics — over-engineering for a docs site. Instead: (a) `mkdocs build --strict` runs on every PR touching `docs-site/`, so broken nav and dead internal links fail fast; (b) a PR-template checklist item — "schema/skill/config-contract change → docs-site updated in this PR" — puts the rule in front of every reviewer. Alternative considered: a path-based gate failing PRs that touch `schemas/` without touching `docs-site/` — deferred; it punishes comment fixes and refactors that change no documented behavior, and the pilot will show whether the checklist suffices before adding friction. + +### D5: Flow diagrams lifted from the change design documents, not generated + +The mermaid diagrams in `add-atd-sdlc-schema/design.md` and `add-atd-sdlc-lite-triage/design.md` are the reviewed source of truth for the shipped flows; flow pages carry them (adapted only for page context), and any change altering a flow updates the page diagram in the same PR per D4. Alternative: generating diagrams from `schema.yaml` DAGs — rejected; the DAG alone cannot express the grilling gate, the final task group, or escalation semantics, so generation would produce emptier diagrams plus generator machinery. + +### D6: Examples are real pilot artifacts; stubs until then + +`examples/example-full.md` and `examples/example-lite.md` (including one escalation walk-through) are populated from pilot wave 1's real change artifacts, redacted as needed. Synthetic examples drift from real agent output and teach the wrong texture. Until pilot artifacts exist, the pages ship as explicit "pending pilot wave 1" stubs — an honest gap beats invented content presented as real. + +## Risks / Trade-offs + +- [Access-controlled Pages on private repos requires GitHub Enterprise Cloud; the org's plan is unverified] → recorded as a rollout prerequisite with its own verification task; fallback is exporting the site content to Confluence. Authoring and CI validation proceed either way. +- [Docs drift from shipped schemas] → same-repo same-PR rule, PR checklist item, strict build, and a named diagram source of truth (the change design documents); pilot onboarding questions will surface stale pages quickly. +- [Screenshot rot] → prefer text and mermaid over screenshots; where a screenshot is genuinely needed, caption it with the CLI version it shows so staleness is detectable. +- [Example pages blocked on pilot wave 1] → the dependency is stated on the stub pages; every other section is useful without them. + +## Rollout + +Author the site and CI first — both work regardless of Pages licensing (`mkdocs build --strict` needs no deployment target). Verify the Pages prerequisite before the first deploy; if unsupported, publish via the Confluence-export fallback and keep the prerequisite open. Announce the site to pilot wave 1 participants and treat their onboarding questions as FAQ input; populate the example pages from the pilot's real artifacts once wave 1 completes. diff --git a/openspec/changes/add-atd-docs-site/proposal.md b/openspec/changes/add-atd-docs-site/proposal.md new file mode 100644 index 0000000000..3a0b1e90bd --- /dev/null +++ b/openspec/changes/add-atd-docs-site/proposal.md @@ -0,0 +1,31 @@ +# Add ATD Developer Docs Site + +## Why + +The ATD SDLC now spans two schemas (`atd-sdlc`, `atd-sdlc-lite`), a triage skill, an external standards store, and per-repo config — but the knowledge lives in two change directories and maintainer-facing collateral under `docs/atd/`, all shaped for people evolving this fork, not for the developers consuming the workflow. Pilot wave 1 participants need one browsable answer to "why this workflow, how do I get set up, which path does my ticket take, what does a real change look like". Without it, onboarding happens over Slack and the answers drift. + +Depends on `add-atd-sdlc-schema` and `add-atd-sdlc-lite-triage` for content (both implemented); example pages additionally depend on pilot wave 1 producing real artifacts. + +## What Changes + +- Add a MkDocs Material documentation site under `docs-site/`, docs-as-code in this repo: markdown pages, mermaid diagrams rendered natively, instant search, no server-side machinery. +- Site structure: `index` (why: one workflow, ticket → documented, standards-conformant code), `architecture` (schema engine, 3-tier resolution, artifact DAG, stores, config/rules injection), `getting-started` (bootstrap, store registration, `openspec/config.yaml`, Atlassian MCP check), `flows/` (triage, full-sdlc, lite, escalation — diagrams lifted from the two shipped changes' design documents), `standards` (store, stack mapping, apply-time fetch, conformance tasks), `examples/` (example-full and example-lite incl. an escalation example, sourced from pilot wave 1's real redacted artifacts — stubs until then), `reference/` (config keys, FAQ). +- Add a GitHub Actions workflow: `mkdocs build --strict` on PRs touching the site (broken nav/links fail), build-and-deploy to GitHub Pages on push to main. +- Anti-drift rule: documentation is updated in the same PR as any schema, skill, or config-contract change. Enforced lightly — a PR-template checklist item plus the strict build; no bespoke content-diffing CI. +- Record one honest rollout prerequisite: verify the org's GitHub plan supports access-controlled Pages on private repositories (GitHub Enterprise Cloud). Fallback destination is Confluence export. This gates publishing, not authoring. + +## Capabilities + +### New Capabilities + +- `atd-developer-docs`: the developer-facing documentation site — strict-buildable source in this repo, the required section set, flow diagrams matching the shipped schemas, examples from real pilot artifacts, the same-PR docs rule, and automated deployment. + +### Modified Capabilities + +None. + +## Impact + +- New: `docs-site/mkdocs.yml` + `docs-site/docs/**` (markdown pages only), `.github/workflows/docs.yml`, PR-template checklist item. +- No changes to schemas, templates, CLI, or core code — purely additive files; upstream sync cost stays minimal. +- `docs/atd/` collateral remains the maintainer-facing source for adoption tracking and prerequisites; the site lifts from it and links to it, never the reverse. diff --git a/openspec/changes/add-atd-docs-site/specs/atd-developer-docs/spec.md b/openspec/changes/add-atd-docs-site/specs/atd-developer-docs/spec.md new file mode 100644 index 0000000000..41f46e79e6 --- /dev/null +++ b/openspec/changes/add-atd-docs-site/specs/atd-developer-docs/spec.md @@ -0,0 +1,65 @@ +# atd-developer-docs Specification (delta) + +## ADDED Requirements + +### Requirement: Site source builds strictly from this repository +The system SHALL provide a MkDocs Material documentation site whose source lives in this repository under `docs-site/`, buildable with `mkdocs build --strict` such that a missing navigation target or broken internal link fails the build. + +#### Scenario: Strict build passes +- **WHEN** `mkdocs build --strict` runs against `docs-site/` +- **THEN** the build completes with zero warnings + +#### Scenario: Broken link fails the build +- **WHEN** a page links to a nonexistent internal page or the nav references a missing file +- **THEN** `mkdocs build --strict` fails + +### Requirement: Required section set +The site navigation SHALL contain: an index page stating the workflow purpose (one workflow: ticket → documented, standards-conformant code); an architecture page covering the schema engine, 3-tier schema resolution, artifact DAG, stores, and config/rules injection; a getting-started page covering bootstrap, `atd-standards` store registration, per-repo `openspec/config.yaml`, and the Atlassian MCP check; flow pages for triage, full SDLC, lite, and escalation; a standards page covering the store, the explicit stack mapping, apply-time fetch, and conformance tasks; example pages for a full change and a lite change including an escalation example; and reference pages for config keys and FAQ. + +#### Scenario: Navigation completeness +- **WHEN** the site is built +- **THEN** the navigation resolves index, architecture, getting-started, flows/{triage, full-sdlc, lite, escalation}, standards, examples/{example-full, example-lite}, and reference/{config-keys, faq} + +### Requirement: Flow pages carry diagrams matching the shipped schemas +Each flow page SHALL carry a mermaid diagram consistent with the corresponding shipped schema or skill behavior, sourced from the approved change design documents (`add-atd-sdlc-schema`, `add-atd-sdlc-lite-triage`). + +#### Scenario: Full SDLC flow page +- **WHEN** a developer opens the full-sdlc flow page +- **THEN** it renders a mermaid diagram showing `ticket → analysis → (specs, design) → solution-doc → tasks → apply`, including the grilling gate and the mandatory final task group, consistent with `schemas/atd-sdlc/` + +#### Scenario: Triage and escalation flow pages +- **WHEN** a developer opens the triage or escalation flow page +- **THEN** it renders a mermaid diagram covering eligibility evaluation with monotonic confirmation, and both pre-tasks escalation and late escalation via `tasks.lite.md`, consistent with `schemas/atd-sdlc-lite/` and the `atd-change-triage` skill + +### Requirement: Examples sourced from real pilot artifacts +The example pages SHALL be populated from pilot wave 1's real change artifacts, redacted as needed, with example-lite including one escalation walk-through. Until those artifacts exist, each example page SHALL state that it is pending pilot wave 1; synthetic content SHALL NOT be presented as a real example. + +#### Scenario: Before pilot wave 1 +- **WHEN** the site is published before pilot wave 1 completes +- **THEN** each example page states the pilot dependency and contains no invented ticket content presented as real + +#### Scenario: After pilot wave 1 +- **WHEN** pilot wave 1 completes +- **THEN** example-full shows the pilot ticket's redacted artifacts end to end and example-lite includes a redacted escalation example + +### Requirement: Documentation updated in the same PR +The contributor documentation SHALL require docs-site updates in the same PR as any schema, skill, or config-contract change, backed by a PR-template checklist item, and the CI workflow SHALL run `mkdocs build --strict` on pull requests touching `docs-site/`. + +#### Scenario: Schema-changing PR +- **WHEN** a PR modifies a schema or skill in a way that alters a documented flow +- **THEN** the PR-template checklist requires the corresponding docs-site pages and diagrams to be updated in that same PR + +#### Scenario: Docs-touching PR is validated +- **WHEN** a PR modifies files under `docs-site/` +- **THEN** CI runs `mkdocs build --strict` and the PR fails on build warnings + +### Requirement: Automated deployment with recorded publishing prerequisite +A GitHub Actions workflow SHALL build and deploy the site to GitHub Pages on push to main. The rollout documentation SHALL record the prerequisite that the org's GitHub plan supports access-controlled Pages on private repositories (GitHub Enterprise Cloud), with Confluence export named as the fallback destination; this prerequisite SHALL gate deployment only, not authoring. + +#### Scenario: Push to main +- **WHEN** a commit touching `docs-site/` lands on main and Pages is available +- **THEN** the workflow builds the site and publishes it to GitHub Pages + +#### Scenario: Pages licensing unavailable +- **WHEN** the org plan does not support access-controlled Pages on private repositories +- **THEN** the site content is delivered via the Confluence-export fallback and the prerequisite remains recorded as open diff --git a/openspec/changes/add-atd-docs-site/tasks.md b/openspec/changes/add-atd-docs-site/tasks.md new file mode 100644 index 0000000000..565a990bab --- /dev/null +++ b/openspec/changes/add-atd-docs-site/tasks.md @@ -0,0 +1,35 @@ +# Tasks: Add ATD Developer Docs Site + +## 1. Scaffold and CI + +- [ ] 1.1 Create `docs-site/` with `mkdocs.yml`: Material theme, mermaid via `pymdownx.superfences`, search, and the nav skeleton for the full section set (index, architecture, getting-started, flows/, standards, examples/, reference/); verify `mkdocs build --strict` succeeds from a clean checkout +- [ ] 1.2 Add `.github/workflows/docs.yml`: on PRs touching `docs-site/` run `mkdocs build --strict`; on push to main build and deploy to GitHub Pages; verify with `actionlint` and one PR dry run +- [ ] 1.3 Verify the org's GitHub plan supports access-controlled Pages on private repositories (GitHub Enterprise Cloud); record the outcome in the rollout notes — if unsupported, mark the Confluence-export fallback as the active destination and keep the prerequisite open +- [ ] 1.4 Add the same-PR docs checklist item to the PR template: "schema/skill/config-contract change → docs-site updated in this PR" + +## 2. Core pages + +- [ ] 2.1 Write `index.md`: why — one workflow from ticket to documented, standards-conformant code; link into the flow pages +- [ ] 2.2 Write `architecture.md`: schema engine, 3-tier schema resolution, artifact DAG, stores, config/rules injection — lifted from the `add-atd-sdlc-schema` design context, written for consumers +- [ ] 2.3 Write `getting-started.md`: bootstrap (from `docs/atd/bootstrap.md`), `atd-standards` store registration, per-repo `openspec/config.yaml` (from `docs/atd/config-template.yaml`), Atlassian MCP check; verify every command shown runs on a clean machine + +## 3. Flow pages + +- [ ] 3.1 Write `flows/triage.md`: eligibility decision table summary, bounded preflight, monotonic confirmation, `triage.md` sidecar; diagram lifted from `add-atd-sdlc-lite-triage/design.md` +- [ ] 3.2 Write `flows/full-sdlc.md`: six-artifact pipeline with grilling gate, AC traceability, solution-doc, and the mandatory final task group; diagram lifted from `add-atd-sdlc-schema/design.md` +- [ ] 3.3 Write `flows/lite.md`: three-artifact pipeline and the standard lite task shape +- [ ] 3.4 Write `flows/escalation.md`: pre-tasks escalation and late escalation via `tasks.lite.md`, one-way only +- [ ] 3.5 Verify every flow diagram renders (`mkdocs serve` visual check) and matches the shipped behavior in `schemas/atd-sdlc/` and `schemas/atd-sdlc-lite/` + +## 4. Standards, examples, reference + +- [ ] 4.1 Write `standards.md`: the `atd-standards` store, explicit stack mapping (python → python-service-standards, spring-boot → spring-boot-standards, oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards), apply-time fetch, conformance tasks — from `docs/atd/standards-store.md` +- [ ] 4.2 Create `examples/example-full.md` and `examples/example-lite.md` as stubs explicitly stating the pilot wave 1 dependency +- [ ] 4.3 (blocked on pilot wave 1) Populate the example pages from the pilot's real, redacted change artifacts; example-lite includes one escalation walk-through +- [ ] 4.4 Write `reference/config-keys.md`: every `openspec/config.yaml` key with meaning and example; verify against `docs/atd/config-template.yaml` +- [ ] 4.5 Write `reference/faq.md` seeded from questions raised in the schema dry-runs; extend with pilot onboarding questions as they arrive + +## 5. Verification + +- [ ] 5.1 Full site check: `mkdocs build --strict` clean, navigation matches the required section set in the spec, all mermaid diagrams render +- [ ] 5.2 First deploy reachable by an ATD developer account on GitHub Pages (or the Confluence fallback per 1.3); announce to pilot wave 1 participants diff --git a/openspec/changes/add-atd-sdlc-lite-triage/.openspec.yaml b/openspec/changes/add-atd-sdlc-lite-triage/.openspec.yaml new file mode 100644 index 0000000000..c0a8162549 --- /dev/null +++ b/openspec/changes/add-atd-sdlc-lite-triage/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-07-21 diff --git a/openspec/changes/add-atd-sdlc-lite-triage/design.md b/openspec/changes/add-atd-sdlc-lite-triage/design.md new file mode 100644 index 0000000000..b10517826e --- /dev/null +++ b/openspec/changes/add-atd-sdlc-lite-triage/design.md @@ -0,0 +1,74 @@ +# Design: ATD SDLC Lite and Change Triage + +## Context + +`add-atd-sdlc-schema` establishes the full six-artifact pipeline. Pilot risk identified: disproportionate ceremony for small, low-risk corrections. OpenSpec schemas are static DAGs — a schema cannot conditionally skip artifacts — but the CLI already supports schema selection at change creation (`openspec new change --schema `), so a two-schema model with an entry-point triage step needs no core changes. + +## Goals / Non-Goals + +**Goals** + +- A genuinely light path for low-risk corrections without losing traceability, standards checks, or Jira closure. +- Risk-based routing decided before change creation, with the developer confirming. +- Safe escalation whenever lite analysis or implementation uncovers wider impact. + +**Non-Goals** + +- Conditional artifacts inside one schema (requires core engine changes). +- Downgrading full changes to lite after planning begins. +- Deterministic CI enforcement of standards (separate follow-up change; triage and pilot metrics feed it). + +## Decisions + +### D1: Two schemas + entry triage, not one conditional schema + +Routing happens at change creation via the existing `--schema` flag; an `atd-change-triage` skill evaluates the eligibility table and creates the change after developer confirmation. Confirmation is monotonic: a full recommendation cannot be weakened to lite; a lite recommendation can be strengthened. Triage rationale (recommendation, condition evaluations, confirmed choice) is written to a non-artifact `triage.md` sidecar in the change directory — never to `ticket.md`, because artifact completion is output-file existence and a partial `ticket.md` would mark the ticket artifact done, silently skipping Jira/Confluence intake, completeness checking, grilling, and write-back. The ticket instructions read `triage.md` and fold the record into the completed `ticket.md`; escalations append trigger, previous schema, new schema, and reason to `triage.md`. Alternative: triage fully generating the ticket artifact itself — rejected; it would make triage responsible for intake and grilling. Alternative: extending the artifact-graph engine with conditional nodes — rejected as a core change with upstream divergence for a problem routing already solves. + +Honest impact note: shipping triage requires TypeScript source additions — workflow template exports, skill-generation registry AND command-generation registration (both delivery paths: `atd-change-triage` skill plus `/opsx:atd-triage` command, so command-only agent tools receive triage too), workflow profile/selection mappings, init/update synchronization, parity tests, and committed generated artifacts. These are additive registrations with no artifact-graph or CLI behavior changes, but this change is not schema-files-only. + +Default installation: `atd-triage` is added to the fork's CORE_WORKFLOWS so `openspec init` installs it for every ATD developer without profile selection. Alternative: leaving it in ALL_WORKFLOWS (selectable only) with the bootstrap configuring a custom profile — rejected; org-wide entry-point tooling should not depend on per-machine profile setup. + +### D2: Full-compatible lite artifacts, kept in sync by parity tests + +Schemas cannot include or inherit instruction content from one another, so "shared" rules (AC IDs, SHA + file:line citations, code as source of truth, affected-stack set) are duplicated text in both schema files, guarded by a parity test that asserts the shared rule blocks match. Lite `ticket.md` and `analysis.md` satisfy the full schema's content contract — shorter content, same required data (notably affected stacks, which the standards mapping needs after escalation) — so escalation retains both artifacts without regeneration. Alternatives: independent lite instructions (escalation becomes lossy) or a build-time fragment generator (machinery ahead of need; revisit if a third schema appears) — both rejected. + +### D3: One-way escalation by editing schema metadata and invalidating lite tasks + +Before `tasks.md` exists, escalation updates the change's `.openspec.yaml` to `schema: atd-sdlc`. Schema metadata is reread on subsequent commands, so ticket and analysis remain done, specs and design become ready, solution-doc and tasks remain blocked. + +If a full-workflow trigger appears after `tasks.md` exists or during apply, continuing under lite is unsafe. The agent stops implementation, leaves further lite boxes unchecked, moves `tasks.md` to `tasks.lite.md` as audit history (removing the tracked path), appends the trigger and schema transition to `triage.md`, updates `ticket.md` and `analysis.md` for the wider scope, and switches `.openspec.yaml` to `atd-sdlc`. With no `tasks.md`, full apply is blocked while specs/design become ready and solution-doc/tasks remain blocked. The new full task list must account for and verify or revert any partial implementation. Alternative: switching schemas while retaining `tasks.md` — rejected because filesystem completion would falsely mark the full tasks artifact complete and leave apply available. Alternative: recreating the change and copying artifacts — rejected; adds preservation risk for no benefit. Downgrade is unsupported. + +### D4: Eligibility is a documented table the skill quotes, evaluated against code, not just ticket text + +The decision table lives in `docs/atd/` and the triage skill evaluates each condition explicitly, quoting failed/uncertain conditions in its recommendation. Classification requires a bounded codebase preflight (owning component, entry points/call path, covering tests/specs, contract/data/security/dependency/integration/deployment impact) because localization, coverage, and impact conditions cannot be reliably determined from Jira text alone; anything unverifiable from ticket or code is uncertain and routes full. The preflight is deliberately lighter than `analysis.md` — just enough to classify safely. Implementation detail: the change is created with `--json` and `triage.md` is written under the returned change path, never an assumed repo-local `openspec/changes/`, since the CLI can resolve another planning root or store. This makes routing auditable and gives pilot metrics (selection rate, escalation rate) a stable denominator. Recurring deviation classes observed in pilots are candidates for promotion into deterministic CI checks (follow-up enforcement change). + +## Solution Flow + +```mermaid +flowchart TD + DEV[Developer provides Jira ticket] --> TRI[atd-change-triage:\nevaluate eligibility table] + TRI --> REC[Recommendation + reasons\ndeveloper confirms] + REC -->|lite confirmed| L["openspec new change --schema atd-sdlc-lite"] + REC -->|full confirmed| F["openspec new change --schema atd-sdlc"] + L --> LT[ticket → analysis] + LT --> CHK{full-workflow trigger\nfound in analysis?} + CHK -->|yes, before tasks| ESC[escalate to atd-sdlc\nticket + analysis retained] + CHK -->|no| LTASK[tasks → apply] + LTASK --> LATE{full-workflow trigger\nduring tasks or apply?} + LATE -->|no| CLOSE[Jira closure] + LATE -->|yes| PRESERVE[stop · move tasks.md to tasks.lite.md\nupdate ticket, analysis, triage] + PRESERVE --> ESC + ESC --> FULL[specs → design → solution-doc → new tasks] + F --> FULL +``` + +## Risks / Trade-offs + +- [Triage misclassifies a risky ticket as lite] → all-conditions-must-pass with uncertainty→full default; risk-based rules name the dangerous one-liner classes (authorization, SQL predicates, financial calculations); escalation catches what triage misses; escalation rate is a tracked pilot metric. +- [Lite becomes the default through developer pressure] → confirmation records the quoted conditions; selection and escalation rates surface abuse patterns for the enforcement follow-up. +- [Duplicated shared instruction text drifts between schemas] → parity test asserts the shared rule blocks match; drift fails CI. +- [A full-workflow trigger appears after lite tasks already exist] → the late-escalation procedure preserves the old checklist as `tasks.lite.md`, removes the tracked `tasks.md` path before switching schemas, refreshes ticket/analysis, and tests that full apply is blocked until a new full task list is generated. + +## Rollout + +Ships with or immediately after `add-atd-sdlc-schema`; pilot metrics extended with lite/full selection rate and lite→full escalation rate. Recurring standards deviations and missing-documentation findings from pilots feed the deterministic CI enforcement follow-up change. diff --git a/openspec/changes/add-atd-sdlc-lite-triage/proposal.md b/openspec/changes/add-atd-sdlc-lite-triage/proposal.md new file mode 100644 index 0000000000..767524a6b2 --- /dev/null +++ b/openspec/changes/add-atd-sdlc-lite-triage/proposal.md @@ -0,0 +1,33 @@ +# Add ATD SDLC Lite Schema and Change Triage + +## Why + +The full `atd-sdlc` pipeline (six artifacts) is right for feature work but is disproportionate ceremony for small, low-risk corrections — a null guard, a log fix, a config correction. Forcing every ticket through specs, design, and solution-doc threatens adoption. OpenSpec schemas are static DAGs, so one schema cannot conditionally skip artifacts; the right mechanism is routing between two schemas at change creation via the existing `--schema` option. + +Depends on `add-atd-sdlc-schema` (shares its ticket and analysis instruction content). + +## What Changes + +- Add a built-in schema `schemas/atd-sdlc-lite/` with the pipeline `ticket → analysis → tasks` (apply tracks tasks.md; closure is a task). +- Lite `ticket` is the compact form: Jira source, problem statement, acceptance criteria, confirmation that the change restores existing intended behavior. +- Lite `analysis` is a short impact assessment: root cause, target files, the existing specification/test covering intended behavior, risk assessment, and why the change qualifies for lite processing. +- Lite `tasks` follows a standard shape: implement correction, add/update regression test, run verification, verify applicable coding standards, record that no new solution document or durable documentation set is needed, apply any localized correction to existing documentation, and add an idempotent Jira closure comment. +- Add an `atd-change-triage` skill: given a Jira ticket, evaluate the documented eligibility decision table, recommend lite or full with reasons, and create the change with the chosen `--schema` only after developer confirmation. Confirmation is monotonic — a lite recommendation may be strengthened to full, but a full recommendation cannot be weakened to lite; declines quote the failed or uncertain conditions. Triage rationale is written to a non-artifact `triage.md` sidecar (never a partial `ticket.md`, which would falsely complete the ticket artifact and skip intake/grilling); the ticket artifact folds the record into `ticket.md`, and escalations append to `triage.md`. +- Eligibility is risk-based, never line-count-based: all conditions must pass (single repo/component, localized impact, restores specified behavior, no API/data/security/integration/dependency/infra impact, straightforward regression test, trivial rollback, and no need for a new solution document or durable functional/technical documentation set). Localized corrections to existing documentation remain lite-eligible when they do not reveal a full-workflow impact. Any failure or uncertainty → full. +- Triage performs a bounded codebase preflight before classifying — owning component, entry points and call path, covering tests/specs, contract/data/security/dependency/integration/deployment impact — because these conditions cannot be reliably determined from Jira text alone. Unverifiable from ticket or code → uncertain → full. Lighter than analysis.md: only enough to classify safely. +- One-way escalation applies whenever a full-workflow trigger is discovered. Before tasks exist, update `.openspec.yaml` to `schema: atd-sdlc` and retain the full-compatible ticket and analysis. After `tasks.md` exists or during apply, stop lite work, move `tasks.md` to `tasks.lite.md` so it cannot falsely satisfy the full schema, append the escalation record, update ticket/analysis for the wider scope, switch schemas, and generate specs → design → solution-doc → a new full `tasks.md` that reconciles any partial implementation. Downgrading full to lite after planning begins is not supported. + +## Capabilities + +### New Capabilities + +- `atd-sdlc-lite-workflow`: the three-artifact lite pipeline, its compact artifact rules, and the one-way escalation to the full schema. +- `atd-change-triage`: the entry-point skill that classifies a ticket against the eligibility table and creates the change with the confirmed schema. + +## Impact + +- New: `schemas/atd-sdlc-lite/schema.yaml` + templates. Shared instruction text is duplicated from `atd-sdlc` (schemas cannot include content) and guarded by a parity test. +- Modified: `schemas/atd-sdlc/schema.yaml` — the full schema's ticket instruction reads `triage.md` when present and includes the routing record in `ticket.md` (proceeds normally when absent). +- New: `atd-change-triage` delivered through both generation paths — skill template and `/opsx:atd-triage` command template — requiring additive TypeScript source changes (workflow template exports, skill and command generation registries, profile/selection mappings, init/update synchronization, parity tests, committed generated artifacts). Added to the fork's CORE_WORKFLOWS so init installs triage by default. Eligibility decision table in `docs/atd/`. +- No artifact-graph or CLI behavior changes; routing uses the existing `--schema` flag and escalation uses the supported schema-metadata reread. +- Pilot metrics extended with lite/full selection rate and lite→full escalation rate. diff --git a/openspec/changes/add-atd-sdlc-lite-triage/specs/atd-change-triage/spec.md b/openspec/changes/add-atd-sdlc-lite-triage/specs/atd-change-triage/spec.md new file mode 100644 index 0000000000..55e59bd392 --- /dev/null +++ b/openspec/changes/add-atd-sdlc-lite-triage/specs/atd-change-triage/spec.md @@ -0,0 +1,94 @@ +# atd-change-triage Specification (delta) + +## ADDED Requirements + +### Requirement: Documented eligibility decision table +The system SHALL document the lite-eligibility decision table: single repository and component; small localized file impact; restores existing intended behavior; existing acceptance criteria, specification, or test already defines the behavior; no API contract change; no database/schema/data migration; no authentication, authorization, security, privacy, or compliance impact; no cross-service integration behavior; no new dependency; no deployment or infrastructure change; straightforward automated regression test; trivial rollback; and no need for a new solution document or new durable functional/technical documentation set. A localized correction to existing documentation remains lite-eligible when it does not indicate API, data, security, integration, dependency, deployment, or other full-workflow impact. Lite applies only when ALL conditions pass; any failure or uncertainty routes to the full schema. + +#### Scenario: All conditions pass +- **WHEN** a ticket satisfies every eligibility condition +- **THEN** triage recommends `atd-sdlc-lite` + +#### Scenario: Localized existing-document correction +- **WHEN** a low-risk correction requires updating an existing README or operational note and no other full-workflow trigger applies +- **THEN** the documentation update does not by itself disqualify the change from `atd-sdlc-lite` + +#### Scenario: New durable documentation required +- **WHEN** the change requires a new solution document, API contract documentation, or another new durable functional/technical documentation set +- **THEN** triage recommends the full `atd-sdlc` schema + +#### Scenario: Uncertain condition +- **WHEN** any condition cannot be confidently evaluated +- **THEN** triage recommends the full `atd-sdlc` schema + +### Requirement: Risk-based classification, never line count +The triage instructions SHALL forbid classifying by change size alone: a one-line change touching authorization conditions, SQL WHERE clauses, or financial calculations SHALL route to the full schema regardless of size. + +#### Scenario: One-line authorization change +- **WHEN** the ticket describes a one-line change to an authorization condition +- **THEN** triage recommends the full `atd-sdlc` schema with the security condition as the reason + +### Requirement: Monotonic confirmation before creation +The triage skill SHALL present its recommendation with the specific conditions that drove it and obtain developer confirmation before any change is created. Governance is monotonic: when triage recommends lite, the developer may choose lite or full; when triage recommends full, full is mandatory — a weaker workflow SHALL NOT be selectable through ordinary confirmation. The change SHALL then be created via `openspec new change --schema `. + +#### Scenario: Developer confirms lite recommendation +- **WHEN** triage recommends lite and the developer confirms +- **THEN** the change is created with `--schema atd-sdlc-lite` + +#### Scenario: Developer strengthens to full +- **WHEN** triage recommends lite and the developer chooses full +- **THEN** the change is created with `--schema atd-sdlc` + +#### Scenario: Downgrade declined +- **WHEN** triage recommends full and the developer requests lite +- **THEN** the workflow declines and identifies the failed or uncertain conditions that require the full schema + +### Requirement: Auditable triage record via sidecar +The triage skill SHALL create the change with `openspec new change --schema --json` and write its recommendation, the quoted condition evaluations, and the developer's confirmation to a non-artifact sidecar file `triage.md` under the change path returned in the JSON output — never assuming the change lives under the current repository's `openspec/changes/`, since the CLI can resolve another planning root or store. The triage skill SHALL NOT create or modify `ticket.md` — artifact completion is determined by output-file existence, and a partial `ticket.md` would mark the ticket artifact complete and skip intake, completeness checking, grilling, and write-back. The ticket artifact instructions of BOTH `atd-sdlc` and `atd-sdlc-lite` SHALL read `triage.md` when present and include the routing record in the completed `ticket.md`. When no sidecar exists, the full schema proceeds normally; the lite schema SHALL treat a missing, empty, or structurally incomplete record (one lacking the recommendation, the confirmed choice, or an evaluation for every condition) as a mandatory gate — run the eligibility evaluation (bounded preflight plus condition table) at ticket intake and write `triage.md` marked as self-triage. Structural completeness SHALL NOT suffice: lite processing continues only when every condition evaluation passes AND the recommendation is `atd-sdlc-lite` AND the confirmed choice is `atd-sdlc-lite`; any FAIL or UNCERTAIN evaluation, a full recommendation, or an inconsistent confirmed choice SHALL switch the change to `atd-sdlc`. The lite ticket instructions SHALL embed the canonical condition list, since packaged schemas cannot reference repository docs or assume the triage skill is installed. Lite processing without a valid, all-pass triage record SHALL NOT be allowed. Escalation SHALL append to `triage.md`: the trigger discovered, previous schema, new schema, and reason. + +#### Scenario: Sidecar written at creation +- **WHEN** a change is created through triage +- **THEN** `triage.md` exists under the change path returned by `--json` with the recommendation, each condition's evaluation, and the developer's confirmed choice, and `ticket.md` does not exist + +#### Scenario: Ticket artifact still pending after triage +- **WHEN** triage has created the change and written `triage.md` +- **THEN** `openspec status` reports the `ticket` artifact as ready-to-create, not done + +#### Scenario: Full schema selected through triage +- **WHEN** triage routes a change to `atd-sdlc` and the agent completes the `ticket` artifact +- **THEN** the full schema's `ticket.md` includes the routing record read from `triage.md` + +#### Scenario: Lite schema selected through triage +- **WHEN** triage routes a change to `atd-sdlc-lite` and the agent completes the `ticket` artifact +- **THEN** the lite `ticket.md` includes the routing record read from `triage.md` + +#### Scenario: Full change created directly without triage +- **WHEN** a change is created directly with `--schema atd-sdlc` and no `triage.md` exists +- **THEN** ticket generation proceeds normally without a routing record + +#### Scenario: Lite change created directly without triage +- **WHEN** a change is created directly with `--schema atd-sdlc-lite` and no `triage.md` exists +- **THEN** the ticket instructions direct the agent to run the eligibility evaluation before intake continues, write `triage.md` marked as self-triage, and switch the change to `atd-sdlc` if any condition fails or is uncertain + +#### Scenario: Empty or incomplete sidecar treated as missing +- **WHEN** a lite change's `triage.md` exists but lacks the recommendation, the confirmed choice, or an evaluation for any condition +- **THEN** the ticket instructions direct the agent to treat it exactly like a missing record and run the self-triage gate + +#### Scenario: Complete sidecar containing a failed condition +- **WHEN** a lite change's `triage.md` is structurally complete but any condition evaluation is FAIL or UNCERTAIN, or the recommendation or confirmed choice is not `atd-sdlc-lite` +- **THEN** the ticket instructions direct the agent to inform the developer, append the escalation to `triage.md`, and switch the change's `.openspec.yaml` to `schema: atd-sdlc` before proceeding + +#### Scenario: Escalation history appended +- **WHEN** a lite change escalates to the full schema +- **THEN** `triage.md` gains an escalation entry with the trigger, previous schema, new schema, and reason + +### Requirement: Bounded codebase preflight before classification +Before recommending lite, the triage skill SHALL perform a bounded codebase preflight scoped to the ticket: locate the owning component, inspect the relevant entry points and call path, identify existing tests or specifications covering the behavior, and check for API contract, data, security, dependency, integration, and deployment impact. Any condition not verifiable from the Jira ticket or the code SHALL be treated as uncertain and route to the full schema. The preflight SHALL remain lighter than `analysis.md` — only enough investigation to classify safely. + +#### Scenario: Preflight confirms lite eligibility +- **WHEN** the preflight locates the owning component, finds a covering test, and finds no contract, data, security, dependency, integration, or deployment impact +- **THEN** triage may recommend lite, citing the preflight findings in the condition evaluations + +#### Scenario: Condition unverifiable from ticket and code +- **WHEN** a condition (e.g. integration impact) cannot be confirmed from the Jira ticket or the inspected code +- **THEN** triage treats it as uncertain and recommends the full schema diff --git a/openspec/changes/add-atd-sdlc-lite-triage/specs/atd-sdlc-lite-workflow/spec.md b/openspec/changes/add-atd-sdlc-lite-triage/specs/atd-sdlc-lite-workflow/spec.md new file mode 100644 index 0000000000..bcd427f715 --- /dev/null +++ b/openspec/changes/add-atd-sdlc-lite-triage/specs/atd-sdlc-lite-workflow/spec.md @@ -0,0 +1,62 @@ +# atd-sdlc-lite-workflow Specification (delta) + +## ADDED Requirements + +### Requirement: Lite schema availability +The system SHALL provide a built-in schema named `atd-sdlc-lite` with the artifact pipeline `ticket → analysis → tasks` and an apply phase tracked by `tasks.md`, resolvable through the same three-tier schema resolution as other built-in schemas. + +#### Scenario: Creating a lite change +- **WHEN** a change is created with `--schema atd-sdlc-lite` +- **THEN** `openspec status` lists exactly the artifacts `ticket`, `analysis`, `tasks` in dependency order + +### Requirement: Compact lite ticket +The lite `ticket` artifact instructions SHALL require the Jira source link, problem statement, acceptance criteria with stable IDs, and an explicit confirmation that the change restores existing intended behavior rather than introducing new behavior. + +#### Scenario: Lite ticket for a defect +- **WHEN** the agent creates the lite `ticket` artifact +- **THEN** `ticket.md` records the Jira link, problem statement, AC IDs, and the statement of which existing intended behavior is being restored + +### Requirement: Lite impact assessment, full-schema compatible +The lite `analysis` artifact instructions SHALL require: root cause with commit SHA and file:line citation, target files, affected stacks from the explicit set {python, spring-boot, oracle-ebs, angular}, the existing acceptance criteria, specification, or test that covers the intended behavior, a risk assessment, and the reason the change qualifies for lite processing. Lite `ticket.md` and `analysis.md` SHALL satisfy the full schema's content contract (shorter content permitted) so escalation retains both artifacts without regeneration. + +#### Scenario: Lite analysis content +- **WHEN** the agent creates the lite `analysis` artifact +- **THEN** `analysis.md` names the root cause with citation, target files, affected stacks, the covering spec/test, the risk assessment, and the lite-eligibility justification + +#### Scenario: Escalated artifacts need no regeneration +- **WHEN** a lite change escalates to `atd-sdlc` +- **THEN** the retained `ticket.md` and `analysis.md` already satisfy the full schema's requirements, including affected stacks needed for standards mapping + +### Requirement: Standard lite task shape +The lite `tasks` artifact instructions SHALL produce tasks covering, in order: implement the correction, add or update a regression test, run the relevant verification command, verify the applicable coding standards using the explicit stack mapping, record that no new solution document or durable functional/technical documentation set is required, apply any localized correction to existing documentation, and add an idempotent Jira closure comment. An existing-document update remains lite-compatible only while it does not reveal API, data, security, integration, dependency, deployment, or other full-workflow impact. + +#### Scenario: Generated lite task list +- **WHEN** the agent creates `tasks.md` for a lite change +- **THEN** the checklist contains the correction, regression test, verification, standards check, documentation determination or localized update, and Jira closure tasks + +### Requirement: One-way escalation to the full schema +The lite `analysis` and apply instructions SHALL require escalation to `atd-sdlc` whenever a full-workflow trigger is discovered. Before `tasks.md` exists, escalation updates `.openspec.yaml` to `schema: atd-sdlc`, appends the transition to `triage.md`, and retains the full-compatible ticket and analysis artifacts. After `tasks.md` exists or during apply, the agent SHALL stop lite implementation, leave further lite tasks unchecked, move `tasks.md` to `tasks.lite.md` for audit history so the full tasks artifact is not falsely complete, append the escalation to `triage.md`, update `ticket.md` and `analysis.md` for the wider scope, and update `.openspec.yaml` to `schema: atd-sdlc`. The full workflow SHALL then generate specs, design, solution-doc, and a new `tasks.md` that verifies, reconciles, or reverts any partial implementation. Downgrading a full change to lite after planning begins SHALL NOT be supported. + +#### Scenario: Lite analysis uncovers wider impact +- **WHEN** lite analysis reveals an API contract change before `tasks.md` exists +- **THEN** the agent stops, informs the developer, updates `.openspec.yaml` to `schema: atd-sdlc`, retains ticket and analysis, and appends the trigger, previous schema, new schema, and reason to `triage.md` + +#### Scenario: Lite apply uncovers wider impact +- **WHEN** implementation reveals an API contract, data, security, integration, dependency, deployment, or other full-workflow impact after `tasks.md` exists +- **THEN** the agent stops lite work, moves `tasks.md` to `tasks.lite.md`, appends the escalation record, updates ticket and analysis, switches to `atd-sdlc`, and does not resume implementation until the full planning artifacts and a new full task list exist + +#### Scenario: Status after pre-tasks escalation +- **WHEN** a lite change is switched to `atd-sdlc` before `tasks.md` exists +- **THEN** status reports ticket and analysis as done, specs and design as ready, solution-doc and tasks as blocked, and apply as blocked + +#### Scenario: Status after late escalation +- **WHEN** a lite change with `tasks.md` is escalated using the late-escalation procedure +- **THEN** `tasks.lite.md` preserves the old checklist, the tracked `tasks.md` path is absent, status reports specs and design as ready and solution-doc and tasks as blocked, and apply is blocked + +#### Scenario: Partial implementation carried into full planning +- **WHEN** code was changed before the full-workflow trigger was discovered +- **THEN** the regenerated full task list includes explicit tasks to verify and reconcile that partial implementation with the approved full design, or revert it + +#### Scenario: No downgrade +- **WHEN** a developer asks to convert an in-progress `atd-sdlc` change to lite after planning artifacts exist +- **THEN** the workflow declines and the change continues under the full schema diff --git a/openspec/changes/add-atd-sdlc-lite-triage/tasks.md b/openspec/changes/add-atd-sdlc-lite-triage/tasks.md new file mode 100644 index 0000000000..3aedfb214b --- /dev/null +++ b/openspec/changes/add-atd-sdlc-lite-triage/tasks.md @@ -0,0 +1,23 @@ +# Tasks: Add ATD SDLC Lite and Change Triage + +## 1. Lite schema + +- [x] 1.1 Create `schemas/atd-sdlc-lite/schema.yaml` with ticket → analysis → tasks (apply tracks tasks.md); verify `openspec status` on a test change lists exactly three artifacts +- [x] 1.2 Write lite `ticket` instruction (compact: Jira source, problem statement, AC IDs, restores-intended-behavior confirmation, triage record section) — duplicate the full schema's shared intake/grilling rule blocks verbatim +- [x] 1.3 Write lite `analysis` instruction (root cause with SHA + file:line, target files, affected stacks from explicit set, covering spec/test, risk assessment, lite-eligibility justification — full-schema content contract) and lite `tasks` instruction (standard six-task shape incl. standards check via explicit mapping, no-new-solution-doc determination with localized existing-doc updates allowed, idempotent Jira closure) +- [x] 1.4 Implement pre-tasks escalation as `.openspec.yaml` edit to `schema: atd-sdlc` in the lite analysis instruction; test post-switch status: ticket/analysis done, specs/design ready, solution-doc/tasks blocked, apply blocked +- [x] 1.5 Implement late escalation in the lite apply instruction for triggers found after `tasks.md` exists or during apply: stop; move `tasks.md` to `tasks.lite.md`; append `triage.md`; update ticket/analysis; switch to `atd-sdlc`; require the regenerated full task list to reconcile partial code. Test `tasks.lite.md` preserved, tracked `tasks.md` absent, specs/design ready, solution-doc/tasks blocked, and apply blocked +- [x] 1.6 Create `schemas/atd-sdlc-lite/templates/` (ticket.md, analysis.md, tasks.md); verify instruction-loader resolves without diagnostics +- [x] 1.7 Update `schemas/atd-sdlc/schema.yaml` ticket instruction: read `triage.md` when present and include the routing record in ticket.md; proceed normally when absent; verify both paths in the dry-run +- [x] 1.8 Add instruction parity test asserting the shared rule blocks (intake incl. branch-alignment suggestion, grilling, citation, affected-stack set) match between `atd-sdlc` and `atd-sdlc-lite`, AND a template-compatibility test asserting generated lite ticket.md/analysis.md contain every mandatory field of the full schema's contract; drift or missing fields fail `pnpm test` + +## 2. Triage skill + +- [x] 2.1 Author the eligibility decision table in `docs/atd/lite-eligibility.md` (all-must-pass conditions, risk-not-linecount rule with authorization/SQL/financial examples, uncertainty→full default, monotonic override policy, bounded-preflight checklist, and documentation rule: no new solution document/durable doc set; localized updates to existing docs remain lite-eligible unless they reveal a full-workflow impact) +- [x] 2.2 Add `atd-change-triage` through BOTH delivery paths — skill template and `/opsx:atd-triage` command template — with additive TypeScript changes: workflow template exports, skill-generation registry, command-generation registration, workflow profile/selection mappings, init/update synchronization, committed generated artifacts. Behavior: bounded codebase preflight, evaluate table, present recommendation with quoted conditions, enforce monotonic confirmation, run `openspec new change --schema --json`, write `triage.md` sidecar under the returned change path (never ticket.md, never assume repo-local openspec/changes/) +- [x] 2.3 Add `atd-triage` to the fork's CORE_WORKFLOWS so triage installs by default for ATD tools (bootstrap profile configuration rejected as second-class onboarding); verify init installs it without profile selection +- [x] 2.4 Add tests, split by what is executable in this repo: (a) instruction-contract tests — monotonic confirmation, uncertainty→full, risk-not-linecount, doc rule, sidecar/`--json` path rules, escalation format, lite self-triage gate vs full proceed-normally — assert the shipped instruction text on both delivery surfaces; (b) graph-level tests — triage.md is not an artifact output, sidecar leaves ticket pending in both schemas, pre-tasks and late escalation status; (c) init/update delivery for skills-only, commands-only, and both. Agent-behavior scenarios (actual routing decisions, live Jira flow, non-repo-local sidecar writes) WILL be verified against the pilot wave 1 transcript — pending, tracked as task 5.2 of add-atd-sdlc-schema; verify `pnpm test` for the repository-testable coverage + +## 3. Pilot metrics + +- [x] 3.1 Extend pilot metric capture (docs/atd/adoption-track.md) with lite/full selection rate, lite→full escalation rate (sourced from the auditable triage records), and recurring standards-deviation classes flagged as CI-check candidates diff --git a/openspec/changes/add-atd-sdlc-schema/.openspec.yaml b/openspec/changes/add-atd-sdlc-schema/.openspec.yaml new file mode 100644 index 0000000000..c0a8162549 --- /dev/null +++ b/openspec/changes/add-atd-sdlc-schema/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-07-21 diff --git a/openspec/changes/add-atd-sdlc-schema/design.md b/openspec/changes/add-atd-sdlc-schema/design.md new file mode 100644 index 0000000000..ad33956b19 --- /dev/null +++ b/openspec/changes/add-atd-sdlc-schema/design.md @@ -0,0 +1,100 @@ +# Design: ATD SDLC Schema + +## Context + +This fork (`ATD-ONP/ATD-OpenSpec`) currently mirrors upstream `Fission-AI/OpenSpec` v1.6.0 with zero divergence. ATD teams work single-repo (one team per codebase) across Python, Spring Boot, Oracle EBS ERP, and Angular. Work starts from Jira tickets that are frequently incomplete; requirements sometimes live in linked Confluence pages. Developers use AI agents (Claude Code and others) with the Atlassian MCP already available. + +Upstream's schema system resolves workflow definitions in three tiers (`src/core/artifact-graph/resolver.ts`): built-in `schemas/`, user-global data dir, project-local `openspec/schemas/`. Instructions assembly injects per-repo `context:`/`rules:` from `openspec/config.yaml` (`src/core/project-config.ts`) and an index of referenced stores' specs (`src/core/references.ts`). + +An external design review (Codex, 2026-07-21) validated the extension-point approach and drove three revisions incorporated here: a pre-implementation `solution-doc` artifact with post-implementation reconciliation, confirmed idempotent Jira write-back, and splitting distribution concerns into follow-up changes. + +## Goals / Non-Goals + +**Goals** + +- One workflow every ATD developer uses from Jira ticket to published documentation. +- Zero core-code changes — additive schema files only, keeping upstream syncs cheap. +- Coding standards centrally maintained, consulted at apply time, and verified as a task. +- Functional and technical documentation as a mandatory, auditable part of delivery — existing before code, reconciled after. +- Artifacts that are detailed but targeted: traceable to acceptance criteria, cited against code, no boilerplate. + +**Non-Goals** + +- Multi-repo/initiative changes (each repo has its own team; upstream's workspace work may cover this later). +- Building Jira/Confluence API calls into the CLI — the agent does integration via the Atlassian MCP. +- Executable CI enforcement of standards (agent review provides conformance evidence; CI enforcement is a future change). +- Telemetry default change and package identity — split into follow-up changes 3 and 4. + +## Decisions + +### D1: Workflow as a built-in schema, not core changes + +The pipeline ships as `schemas/atd-sdlc/schema.yaml` + templates, riding the existing artifact-graph engine. Alternative considered: extending CLI commands with ticket/docs logic — rejected because it duplicates the Atlassian MCP, adds upstream divergence, and the instruction layer already reaches the agent. + +### D2: Grilling protocol embedded verbatim in the ticket instruction + +The interrogation protocol (checklist gate; explore codebase before asking; one question at a time with a recommended answer) is written directly into the schema instruction rather than referencing an external skill. Alternative: depend on a separately installed `grill-me` skill — rejected because schema instructions are the only distribution channel guaranteed present for every developer and agent tool. + +### D3: Documentation as a pre-implementation artifact with reconciliation tasks + +`solution.md` is generated after specs/design and before tasks (`tasks` requires `solution-doc` in the artifact graph — a real structural gate). Finalization is part of apply: the mandatory final task group reconciles the document against implemented code, records deviations with evidence, publishes to the configured destination, and posts an idempotent Jira closure comment. This replaces the earlier post-apply `docs` artifact whose gate could only live in instruction text; the graph structurally enforces docs-before-code, while docs-after-code is tracked — apply completion depends on the final group's checkboxes, though their content is generated through instructions. Alternative: post-apply docs artifact — rejected because apply is not a graph node, making its gate advisory. + +### D4: Standards via referenced store, index-plus-fetch + +Standards live in a standalone `atd-standards` OpenSpec repo referenced by every ATD repo, with the explicit mapping python → python-service-standards, spring-boot → spring-boot-standards, oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards. The reference index (summary + fetch recipe) keeps standards one tool call away without flooding context. Alternatives: baking standards into the fork package (requires a release per standards edit) or pasting them into each repo's config context (duplicated, drifts) — both rejected. + +### D5: Scaled solution document, not fixed template + +`solution.md` defines the full enterprise section set but instructions scale depth to change size and omit inapplicable sections. Alternative: mandatory full template per Codex review — rejected as boilerplate generation for small fixes, violating the anti-slop stance. The audit value is preserved: applicable sections are mandatory and reconciliation is always required. + +### D6: Confirmed, idempotent external writes + +All Jira/Confluence writes follow the same pattern: developer confirmation before the first write, and managed sections / updated-in-place comments so re-runs are idempotent. Alternative: silent default-on write-back — rejected after review; external writes to shared systems need explicit consent and must never clobber human content. + +### D7: Delivery split into four changes + +This change ships the schema and solution documentation only. Follow-ups: (2) Atlassian integration hardening — idempotency helpers and data governance; (3) telemetry opt-in default; (4) `@atd/openspec` package identity and internal release pipeline (changesets, pack checks, registry auth, workflow guards). Alternative: one combined change — rejected; the package rename alone touches the release path and deserves isolated review and rollback. + +### D8: Analysis reads code as the source of truth, token-efficiently + +At ATD the business logic lives in code, not documentation, so `analysis.md` derives current behavior from code and records doc/code conflicts in code's favor. The instruction carries a tool-agnostic reading strategy (entry-point location per AC, call-path tracing, targeted reads only) because schema instructions serve every agent tool; repo-specific accelerators (code-graph/index MCPs, EBS package tracing) are named per repo in `rules: analysis:`. Alternative: mandating a specific code-index tool in the schema — rejected because tool availability varies across agent environments and repos. + +### D9: Standards store readiness is a hard pilot prerequisite + +This repository defines how ATD projects reference and consume standards, but it does not own the external `atd-standards` repository or author its stack content. The separately owned `establish-atd-standards-store` prerequisite must be complete before pilot wave 1: the repository exists; all four mapped specs pass strict validation; stack leads and CODEOWNERS are assigned; registration/bootstrap instructions work; and a pilot machine passes `openspec store doctor atd-standards` and can fetch every mapped spec. Alternative: allowing the pilot to proceed on unresolved-reference warnings — rejected because standards consultation and conformance tasks would be untestable. + +## Solution Flow + +```mermaid +flowchart TD + J[Jira ticket + linked Confluence] -->|Atlassian MCP pull| T[ticket.md] + T --> G{completeness\nchecklist} + G -- gaps --> Q[grill: 1 question at a time\nwith recommended answer] --> T + G -- complete --> WB[confirmed Jira write-back\ninto managed section] + T --> A[analysis.md\nSHA + file:line cited, stacks named] + A --> S[specs/** — every requirement\ntraces to an AC id] + A --> D[design.md — diagram when\nflow is non-trivial] + S --> SOL[solution.md — scaled sections,\nas-built pending] + D --> SOL + SOL --> K[tasks.md — files + AC ids +\nverify command per task] + K --> AP[apply — fetch stack standards first] + AP --> FIN[final task group:\nstandards verify · reconcile solution.md ·\nrecord deviations · publish confluence/repo/both ·\nidempotent Jira closure] + FIN --> AR[archive] +``` + +## Risks / Trade-offs + +- [Instruction-level rules are advisory — an agent could skim the standards fetch or scaling rules] → the graph gate (tasks requires solution-doc) is structural and the final task group is tracked (apply completion depends on its checkboxes); per-repo `rules:` reinforce the rest; human review remains. +- [Atlassian MCP availability varies by agent tool] → ticket instruction includes a fallback: developer pastes ticket content, checklist still runs. +- [Upstream schema engine evolves (workspace/initiatives work in flight)] → fork diff is additive; re-sync before building on any in-flight upstream change. +- [Grilling can annoy developers on genuinely small tickets] → checklist passes trivially when the ticket is adequate; grilling only triggers on gaps. +- [Solution-doc scaling judgment varies across agents] → the instruction enumerates which sections are mandatory-when-applicable and the reconciliation task forces a second pass; pilot metrics (artifact rework, documentation completion) will show drift. +- [The schema ships before the external standards store is usable] → `establish-atd-standards-store` is a named rollout prerequisite with ownership and executable readiness checks; pilot wave 1 is blocked until it passes. + +## Rollout + +First complete `establish-atd-standards-store` and verify its repository, four strict-valid specs, ownership, registration path, store health, and mapped-spec fetches. Only then pilot progressively: one Python or Angular repo → Spring Boot → Oracle EBS → org-wide. Track clarification count per ticket, artifact rework, standards deviations, documentation completion, external-write failures, and cycle time. + +## Resolved during review + +- `rules:` keys accept artifact IDs only — `apply` is not an artifact and a `docs` key would target a nonexistent artifact (unknown-artifact warning, never injected). Consequences applied: documentation destination lives under `rules: tasks:` and lands in the generated publication tasks; the standards-fetch mandate lives in the schema's `apply.instruction`, the generated conformance tasks, and the referenced-store index already present in instructions. diff --git a/openspec/changes/add-atd-sdlc-schema/proposal.md b/openspec/changes/add-atd-sdlc-schema/proposal.md new file mode 100644 index 0000000000..cb96723f3f --- /dev/null +++ b/openspec/changes/add-atd-sdlc-schema/proposal.md @@ -0,0 +1,39 @@ +# Add ATD SDLC Schema + +## Why + +ATD developers start work from Jira tickets (requirements sometimes in linked Confluence pages, often incomplete) and ship across four stacks: Python, Spring Boot, Oracle EBS ERP, and Angular. The default `spec-driven` schema assumes a developer-authored proposal and has no ticket intake, no coding-standards enforcement, and no mandatory functional/technical documentation. This fork exists to give every ATD team one workflow from ticket to documented, standards-conformant code. + +This is the first change in the ATD adoption track. Companion change (proposed): `add-atd-sdlc-lite-triage` — lightweight schema for low-risk corrections plus risk-based entry triage. Follow-up changes (to be proposed): Atlassian integration hardening (idempotency and data governance), telemetry opt-in default, internal package identity/release pipeline, developer bootstrap tooling, and deterministic CI enforcement of recurring standards deviations. Pilot rollout additionally depends on the separately owned `establish-atd-standards-store` prerequisite described below. + +## What Changes + +- Add a new built-in schema `schemas/atd-sdlc/` with the artifact pipeline: `ticket → analysis → (specs, design) → solution-doc → tasks → apply`. +- `ticket` artifact pulls the Jira issue and linked Confluence pages via the Atlassian MCP, then gates on a completeness checklist; when data is missing it runs an embedded grilling protocol (one question at a time, each with a recommended answer, codebase-answerable questions explored instead of asked). Clarified requirements are written back to the Jira ticket only after developer confirmation, into an idempotent managed section so re-runs never clobber human-authored content. Intake also compares the current git branch with the ticket key and, when they differ, suggests a branch named after the ticket — advisory only: never blocks, never creates or switches a branch without developer confirmation. +- `analysis` artifact treats code as the source of truth: current behavior is derived from the code (documentation is a hint, verified against code; conflicts resolve in code's favor and are noted), cited with commit SHA plus file:line ranges, with affected stacks identified. Reading is token-efficient by instruction — entry-point and call-path tracing scoped to the acceptance criteria, no whole-file sweeps; per-repo `rules: analysis:` may name code-index tooling to prefer over raw reads. +- `specs` artifacts require every requirement to trace to a ticket acceptance-criterion ID. +- `design` artifact records decisions, alternatives, and risks; includes a mermaid Solution Flow diagram when the change spans components or the flow is non-trivial — never merely to satisfy the template. +- `solution-doc` artifact (`solution.md`): the enterprise-facing functional and technical document, created before implementation and reconciled after. Sections scale with change size and are omitted when not applicable — no boilerplate. +- `tasks` artifact requires each task to name target files/modules, the acceptance criteria it serves, and a verification command. The mandatory final group: standards conformance per affected stack, reconciliation of `solution.md` against implemented code (as-built deviations recorded), publication to the configured destination (Confluence, `docs/` in repo, or both), and an idempotent Jira closure comment. Apply is complete only when these are checked. +- Add per-repo `openspec/config.yaml` template documenting stack context, `references: [atd-standards]`, and the documentation destination declared under `rules: tasks:` (rules are injected per artifact ID; there is no docs artifact, so destination details ride the tasks rules and land in the generated publication tasks). +- Document `atd-standards` store conventions with the explicit stack mapping: python → python-service-standards, spring-boot → spring-boot-standards, oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards. +- Declare `establish-atd-standards-store` as a hard pilot prerequisite, owned by the stack standards leads: the standalone repository, all four strictly valid standards specs, CODEOWNERS, developer registration/bootstrap instructions, and a successful `openspec store doctor atd-standards` plus mapped-spec fetch check must exist before a real pilot starts. + +## Capabilities + +### New Capabilities + +- `atd-sdlc-workflow`: the ticket-to-solution-doc artifact pipeline, including the grilling gate, confirmed idempotent Jira write-back, and anti-slop artifact rules. +- `standards-integration`: referencing the `atd-standards` store and the mandatory conformance verify task at apply time. +- `solution-documentation`: the scaled enterprise solution document, its post-implementation reconciliation, configurable publication destination, and Jira closure. + +### Modified Capabilities + +None. (Telemetry default and package identity move to follow-up changes.) + +## Impact + +- New: `schemas/atd-sdlc/schema.yaml` + `schemas/atd-sdlc/templates/*` (ticket.md, analysis.md, spec.md, design.md, solution.md, tasks.md). +- New: rollout collateral under `docs/atd/` (config template, standards-store conventions, adoption-track prerequisite and readiness checklist). +- No changes to core artifact-graph, resolver, CLI, or telemetry code in this change — the schema rides the existing 3-tier schema resolution. +- Upstream sync cost stays minimal: this change is purely additive files. diff --git a/openspec/changes/add-atd-sdlc-schema/specs/atd-sdlc-workflow/spec.md b/openspec/changes/add-atd-sdlc-schema/specs/atd-sdlc-workflow/spec.md new file mode 100644 index 0000000000..598aab6dd2 --- /dev/null +++ b/openspec/changes/add-atd-sdlc-schema/specs/atd-sdlc-workflow/spec.md @@ -0,0 +1,128 @@ +# atd-sdlc-workflow Specification (delta) + +## ADDED Requirements + +### Requirement: ATD SDLC schema availability +The system SHALL provide a built-in schema named `atd-sdlc` with the artifact pipeline `ticket → analysis → (specs, design) → solution-doc → tasks` and an apply phase tracked by `tasks.md`, resolvable through the same three-tier schema resolution as `spec-driven`. + +#### Scenario: Selecting the schema +- **WHEN** a project's `openspec/config.yaml` declares `schema: atd-sdlc` +- **THEN** `openspec status` lists the artifacts `ticket`, `analysis`, `specs`, `design`, `solution-doc`, `tasks` with their dependency order, with `tasks` requiring `solution-doc` + +#### Scenario: Project-local override still wins +- **WHEN** a project defines its own `openspec/schemas/atd-sdlc/schema.yaml` +- **THEN** the project-local schema is used instead of the built-in one + +### Requirement: Ticket intake from Jira and Confluence +The `ticket` artifact instructions SHALL direct the agent to pull the Jira issue named by the change (change names use the ticket key, e.g. `abc-1234-add-export`) and all linked Confluence pages via the Atlassian MCP, and record the normalized problem statement, acceptance criteria, and source links in `ticket.md`. When the Atlassian MCP is unavailable, the instructions SHALL direct the agent to ask the developer to paste the ticket content and continue with the same checklist. + +#### Scenario: Ticket with documented requirements +- **WHEN** the agent creates the `ticket` artifact for a change named after a Jira key +- **THEN** `ticket.md` contains the problem statement, acceptance criteria with stable IDs (AC-1, AC-2, …), affected systems, and links to the Jira issue and Confluence sources + +#### Scenario: Atlassian MCP unavailable +- **WHEN** the agent cannot reach the Atlassian MCP +- **THEN** the agent asks the developer to paste the ticket content and proceeds with the completeness checklist + +### Requirement: Completeness gate with embedded grilling protocol +The `ticket` artifact instructions SHALL define a completeness checklist (problem statement, acceptance criteria, affected systems, edge cases, constraints, out-of-scope) and, when any item is missing, direct the agent to interrogate the developer using the embedded grilling protocol: explore the codebase first for questions the code can answer, otherwise ask exactly one question at a time with a recommended answer attached, looping until the checklist passes. + +#### Scenario: Empty Jira ticket +- **WHEN** the pulled Jira issue has no acceptance criteria +- **THEN** the agent asks the developer one targeted question at a time, each with a recommended answer, until acceptance criteria are established and recorded in `ticket.md` under "Clarified Requirements" with the question/answer trace + +#### Scenario: Codebase-answerable gap +- **WHEN** a checklist gap can be resolved by reading the repository (e.g. which module owns the behavior) +- **THEN** the agent answers it by exploring the codebase and does not ask the developer + +### Requirement: Confirmed, idempotent Jira write-back +The `ticket` artifact instructions SHALL direct the agent to offer updating the Jira issue with clarified requirements after grilling, proceed only after the developer confirms, and write into a clearly delimited managed section of the issue description so repeated runs replace only that section and never human-authored content. A project's `rules: ticket:` config MAY disable write-back entirely. + +#### Scenario: Write-back after confirmation +- **WHEN** grilling produced clarified requirements and the developer confirms the write-back +- **THEN** the agent updates only the managed section of the Jira issue description via the Atlassian MCP and notes the update in `ticket.md` + +#### Scenario: Re-run does not clobber +- **WHEN** the ticket artifact is regenerated for an issue that already has a managed section +- **THEN** the agent replaces the managed section content and leaves the rest of the description untouched + +#### Scenario: Write-back declined or disabled +- **WHEN** the developer declines, or the project config contains a `ticket` rule disabling write-back +- **THEN** the agent records clarified requirements only in `ticket.md` + +### Requirement: Branch alignment suggestion +The `ticket` artifact instructions SHALL direct the agent to compare the current git branch name with the Jira ticket key during intake and, when the branch does not reference the key, suggest creating or switching to a branch named after the ticket (e.g. `abc-1234-add-export`). The suggestion SHALL be advisory: the developer may decline and work continues on the current branch; the agent SHALL NOT create or switch branches without explicit developer confirmation. The branch used SHALL be recorded in `ticket.md`. + +#### Scenario: Branch already references the ticket +- **WHEN** the current branch name contains the Jira ticket key +- **THEN** the agent proceeds without a suggestion and records the branch in `ticket.md` + +#### Scenario: Branch unrelated to the ticket +- **WHEN** the current branch is `main` or otherwise does not reference the ticket key +- **THEN** the agent suggests a branch named after the ticket, and on confirmation creates or switches to it before continuing + +#### Scenario: Suggestion declined +- **WHEN** the developer declines the branch suggestion +- **THEN** the agent continues on the current branch and records the declined suggestion and chosen branch in `ticket.md` + +### Requirement: Evidence-cited analysis +The `analysis` artifact instructions SHALL require every claim about current behavior to cite the repository commit SHA (recorded once per document) and `file:line` ranges, and require the artifact to name the affected stacks from the explicit set {python, spring-boot, oracle-ebs, angular}. + +#### Scenario: Analysis of current behavior +- **WHEN** the agent creates `analysis.md` +- **THEN** the document records the commit SHA it was written against, each statement about existing code carries a `file:line` citation, and the artifact lists the affected stacks + +### Requirement: Code as the source of truth +The `analysis` artifact instructions SHALL direct the agent to derive current behavior from the code itself, treating documentation (Confluence, comments, wikis) as hints to be verified. When documentation and code disagree, the code's behavior SHALL be recorded as current truth and the discrepancy noted in `analysis.md`. + +#### Scenario: Documentation contradicts code +- **WHEN** a Confluence page describes behavior that the cited code does not implement +- **THEN** `analysis.md` records the code's actual behavior as current truth and lists the documentation discrepancy for the developer + +#### Scenario: Undocumented business rule +- **WHEN** the code contains business logic no documentation mentions +- **THEN** `analysis.md` captures the rule from the code with its citation + +### Requirement: Token-efficient code reading +The `analysis` artifact instructions SHALL define a reading strategy scoped to the ticket's acceptance criteria: locate entry points (endpoint, job, UI action) relevant to each AC, trace the call path from there, and read only the sections that path touches — never whole-directory or whole-file sweeps when a targeted read answers the question. When the project's `rules: analysis:` config names code-index or code-graph tooling, the instructions SHALL direct the agent to prefer it over raw file reads. + +#### Scenario: Tracing an endpoint change +- **WHEN** an acceptance criterion concerns one API endpoint's behavior +- **THEN** the agent traces controller → service → data access for that endpoint and does not read unrelated modules + +#### Scenario: Repo declares code-index tooling +- **WHEN** the project's `rules: analysis:` config names a code-index tool available in the developer's agent +- **THEN** the agent uses that tool for symbol lookup and call-path tracing instead of reading raw files + +### Requirement: Spec traceability to acceptance criteria +The `specs` artifact instructions SHALL require every requirement to reference at least one acceptance-criterion ID from `ticket.md`, and SHALL forbid requirements without a corresponding acceptance criterion. + +#### Scenario: Requirement with traceability +- **WHEN** the agent writes a requirement in a delta spec +- **THEN** the requirement text references the acceptance-criterion IDs it satisfies (e.g. "Covers: AC-2") + +#### Scenario: Scope invention rejected +- **WHEN** a candidate requirement has no matching acceptance criterion +- **THEN** the instructions direct the agent to either drop it or return to the ticket artifact to add the criterion with the developer + +### Requirement: Design with purposeful diagrams +The `design` artifact instructions SHALL require a mermaid Solution Flow diagram when the change spans multiple components or the flow is otherwise non-trivial, SHALL permit omitting it for single-component changes, and SHALL direct the agent to omit empty sections instead of filling them with boilerplate. + +#### Scenario: Cross-component change +- **WHEN** the agent creates `design.md` for a change touching more than one component or system +- **THEN** it contains a Solution Flow section with a mermaid diagram whose nodes tasks can reference + +#### Scenario: Trivial single-component change +- **WHEN** the change is confined to one component with a straightforward flow +- **THEN** `design.md` omits the diagram rather than drawing one to satisfy the template + +### Requirement: Verifiable tasks +The `tasks` artifact instructions SHALL require each task to name the target files or modules, the acceptance-criterion IDs it serves, and a verification command or check, so both developers and agents can confirm completion. Governance tasks in the mandatory final group (standards conformance, reconciliation, publication, Jira closure) MAY omit code files and AC IDs but SHALL still state their verification evidence. + +#### Scenario: Task format +- **WHEN** the agent writes a task +- **THEN** the task names the files/modules it touches, references the AC IDs it serves, and states how completion is verified (test command, CLI invocation, or observable output) + +#### Scenario: Governance task format +- **WHEN** the agent writes a final-group governance task +- **THEN** the task states its verification evidence (e.g. deviation list recorded, published URL noted) even though it names no code files or AC IDs diff --git a/openspec/changes/add-atd-sdlc-schema/specs/solution-documentation/spec.md b/openspec/changes/add-atd-sdlc-schema/specs/solution-documentation/spec.md new file mode 100644 index 0000000000..b679dccc6f --- /dev/null +++ b/openspec/changes/add-atd-sdlc-schema/specs/solution-documentation/spec.md @@ -0,0 +1,55 @@ +# solution-documentation Specification (delta) + +## ADDED Requirements + +### Requirement: Solution document before implementation +The `solution-doc` artifact SHALL generate `solution.md` — the enterprise-facing functional and technical document — after specs and design and before tasks, so documentation exists before code. Its instructions SHALL define the full section set (executive summary; functional problem and proposed behavior; scope and business rules; acceptance-criteria traceability; current and proposed technical architecture; APIs, data, security, observability; migration and rollback; testing strategy; standards applied; as-built implementation and deviations; publication and release metadata) and SHALL direct the agent to scale depth to the change size and omit sections that do not apply — a section is never filled with boilerplate to satisfy the template. + +#### Scenario: Substantial cross-component change +- **WHEN** the agent creates `solution.md` for a change affecting multiple components +- **THEN** the document covers the applicable sections with content specific to the change, and the as-built section is initialized as pending implementation + +#### Scenario: Small single-component fix +- **WHEN** the change is a small fix with no API, data, migration, or security surface +- **THEN** `solution.md` contains only the applicable sections (summary, behavior, traceability, testing, standards) and omits the rest entirely + +#### Scenario: Tasks gated on solution document +- **WHEN** `solution.md` does not exist +- **THEN** the `tasks` artifact is reported as blocked with an unmet dependency, is not offered by the standard workflow, and MUST NOT be created until `solution.md` exists + +### Requirement: Post-implementation reconciliation +The mandatory final task group SHALL include reconciling `solution.md` against the implemented code: updating the as-built section, recording every deviation from the design with its reason, and attaching verification evidence. + +#### Scenario: Implementation deviated from design +- **WHEN** the implementation differs from a decision recorded in `design.md` or `solution.md` +- **THEN** the reconciliation task records the deviation, the reason, and the evidence before apply can complete + +### Requirement: Configurable publication destination +The mandatory final task group SHALL publish the reconciled `solution.md` to the destination declared in the project's `rules: tasks:` config — one of `confluence`, `repo`, or `both` — which the tasks generator embeds in the generated publication tasks. When no destination is configured, the agent SHALL ask the developer to choose before publishing. + +#### Scenario: Confluence destination +- **WHEN** the `rules: tasks:` config declares destination `confluence` with a space and parent page +- **THEN** the agent publishes the document as a Confluence page under that parent via the Atlassian MCP and records the page URL in `solution.md` + +#### Scenario: Repo destination +- **WHEN** the `rules: tasks:` config declares destination `repo` +- **THEN** the agent writes the document as markdown under the repository's `docs/` directory + +#### Scenario: Both destinations +- **WHEN** the `rules: tasks:` config declares destination `both` +- **THEN** the agent writes the repo markdown first and publishes the same content to Confluence + +#### Scenario: No destination configured +- **WHEN** the project's `rules: tasks:` config declares no documentation destination +- **THEN** the agent asks the developer to choose confluence, repo, or both before publishing + +### Requirement: Idempotent Jira closure comment +The mandatory final task group SHALL add a Jira comment summarizing what shipped with links to the published documentation, written so that re-running the closure task updates the existing closure comment instead of posting duplicates. + +#### Scenario: Documentation published +- **WHEN** documentation has been published to the configured destination +- **THEN** the agent adds a Jira closure comment containing the change summary and documentation links + +#### Scenario: Closure re-run +- **WHEN** the closure task runs again for the same change +- **THEN** the existing closure comment is updated rather than a duplicate posted diff --git a/openspec/changes/add-atd-sdlc-schema/specs/standards-integration/spec.md b/openspec/changes/add-atd-sdlc-schema/specs/standards-integration/spec.md new file mode 100644 index 0000000000..369b22a68f --- /dev/null +++ b/openspec/changes/add-atd-sdlc-schema/specs/standards-integration/spec.md @@ -0,0 +1,39 @@ +# standards-integration Specification (delta) + +## ADDED Requirements + +### Requirement: Standards store convention +The system SHALL document the `atd-standards` store convention: a standalone OpenSpec root whose specs are the explicit list {python-service-standards, spring-boot-standards, oracle-ebs-plsql-standards, angular-standards}, mapped from stacks as python → python-service-standards, spring-boot → spring-boot-standards, oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards, referenced by ATD repos via `references: [atd-standards]` in `openspec/config.yaml`. + +#### Scenario: Repo referencing standards +- **WHEN** a repo's config declares `references: [atd-standards]` and the store is registered on the machine +- **THEN** generated instructions carry an index of the standards specs with one-line summaries and fetch recipes + +#### Scenario: Store not registered +- **WHEN** the `atd-standards` store is not registered locally +- **THEN** instruction generation degrades to a warning diagnostic and does not fail + +### Requirement: Standards store readiness before pilot +The ATD rollout documentation SHALL declare `establish-atd-standards-store` as a separately owned prerequisite for pilot wave 1. Readiness SHALL require: a standalone `atd-standards` repository; all four mapped standards specs passing strict validation; named stack-lead owners and CODEOWNERS; working registration/bootstrap instructions; and a pilot machine that passes `openspec store doctor atd-standards` and successfully fetches every mapped spec. Pilot wave 1 SHALL NOT begin while any readiness check is incomplete. + +#### Scenario: Standards prerequisite ready +- **WHEN** the repository and four mapped specs exist, strict validation passes, ownership and bootstrap are documented, store doctor is healthy, and every mapped spec can be fetched on the pilot machine +- **THEN** the standards prerequisite is marked ready and pilot wave 1 may begin + +#### Scenario: Standards prerequisite incomplete +- **WHEN** any standards repository, content, ownership, registration, health, or mapped-fetch check is incomplete +- **THEN** pilot wave 1 remains blocked and the missing readiness check is reported + +### Requirement: Standards consultation at apply time +The `atd-sdlc` schema's apply instructions SHALL direct the agent, before implementing any task, to fetch the standards spec mapped to each stack listed in `analysis.md` — using the explicit mapping python → python-service-standards, spring-boot → spring-boot-standards, oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards — and conform to it. + +#### Scenario: Apply on an Angular change +- **WHEN** `analysis.md` lists `angular` as an affected stack and the agent starts apply +- **THEN** the agent fetches `angular-standards` from the store before writing code + +### Requirement: Standards conformance verify task +The `tasks` artifact instructions SHALL require the final task group to contain one conformance task per affected stack, naming the mapped standards spec from the explicit mapping (e.g. "Verify conformance to `oracle-ebs-plsql-standards` scenarios; note deviations"). + +#### Scenario: Generated task list +- **WHEN** the agent creates `tasks.md` for a change affecting spring-boot and angular +- **THEN** the final task group contains a checkbox conformance task for `spring-boot-standards` and one for `angular-standards` diff --git a/openspec/changes/add-atd-sdlc-schema/tasks.md b/openspec/changes/add-atd-sdlc-schema/tasks.md new file mode 100644 index 0000000000..e75588e030 --- /dev/null +++ b/openspec/changes/add-atd-sdlc-schema/tasks.md @@ -0,0 +1,34 @@ +# Tasks: Add ATD SDLC Schema + +## 1. Schema definition + +- [x] 1.1 Create `schemas/atd-sdlc/schema.yaml` with artifacts ticket → analysis → (specs, design) → solution-doc → tasks (apply tracks tasks.md, tasks requires solution-doc); verify with `openspec status --change ` listing all six artifacts in dependency order +- [x] 1.2 Write `ticket` artifact instruction: Atlassian MCP pull, AC-id assignment, completeness checklist, embedded grilling protocol, confirmed write-back into idempotent managed section (`rules: ticket:` opt-out), MCP-unavailable fallback (developer pastes content), branch-alignment suggestion (compare current branch to ticket key; advisory only, confirm before creating/switching, record branch and any declined suggestion in ticket.md) +- [x] 1.3 Write `analysis` instruction: code as source of truth (doc/code conflicts resolve to code, discrepancy noted), commit SHA recorded per document, file:line citation rule, affected-stacks list from explicit set {python, spring-boot, oracle-ebs, angular}, token-efficient reading strategy (AC-scoped entry-point + call-path tracing, no whole-file sweeps, prefer `rules: analysis:`-declared code-index tools) +- [x] 1.4 Write `specs` instruction: keep upstream delta-spec format, add AC traceability rule ("Covers: AC-n" mandatory, no AC → drop or return to ticket) +- [x] 1.5 Write `design` instruction: mermaid Solution Flow when cross-component or non-trivial (omit for trivial changes), omit-empty-sections rule, length cap of approximately 1,000 words +- [x] 1.6 Write `solution-doc` instruction: full section set with scale-to-change-size and omit-if-not-applicable rules, as-built section initialized pending, AC traceability table +- [x] 1.7 Write `tasks` instruction: files/modules + AC ids + verification command per task; mandatory final group = standards conformance per affected stack (explicit mapping names), solution.md reconciliation with deviations + evidence, publication per destination read from `rules: tasks:` (confluence/repo/both, ask-fallback), idempotent Jira closure comment +- [x] 1.8 Write apply instruction: before implementing, fetch the mapped standards spec per affected stack from the atd-standards store (python → python-service-standards, spring-boot → spring-boot-standards, oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards) + +## 2. Templates + +- [x] 2.1 Create `schemas/atd-sdlc/templates/` — ticket.md, analysis.md, spec.md, design.md, solution.md, tasks.md; verify each template referenced by schema.yaml exists (instruction-loader resolves without diagnostics) + +## 3. Validation + +- [x] 3.1 Add schema tests mirroring existing spec-driven schema tests (test/ patterns for schema resolution and instruction assembly), including the tasks-requires-solution-doc gate; verify `pnpm test` passes +- [x] 3.2 Dry-run: create a sample change with `--schema atd-sdlc` in a scratch project, walk instruction output for every artifact, confirm anti-slop rules, grilling protocol, and final task group appear verbatim + +## 4. Rollout collateral + +- [x] 4.1 Create per-repo `openspec/config.yaml` template (stack context blocks for python/spring-boot/oracle-ebs/angular, `references: [atd-standards]`, documentation destination examples under `rules: tasks:`) under `docs/atd/` +- [x] 4.2 Document `atd-standards` store conventions (explicit stack→spec mapping, register command, update workflow) in `docs/atd/standards-store.md` +- [x] 4.3 Add the separately owned `establish-atd-standards-store` prerequisite to `docs/atd/adoption-track.md`: name stack-lead owners; require the standalone repository, four strict-valid mapped specs, CODEOWNERS, registration/bootstrap instructions, `openspec store doctor atd-standards`, and successful fetches of all mapped specs; mark pilot wave 1 blocked until its acceptance checks pass +- [x] 4.4 Draft follow-up change proposals in `docs/atd/adoption-track.md`: atlassian-integration-hardening, telemetry-opt-in-default, internal-package-identity, standards-ci-enforcement (promote recurring pilot deviation classes into deterministic CI checks) +- [x] 4.5 Draft ATD bootstrap script (`docs/atd/bootstrap.md` + script skeleton): internal npm configuration, package installation, atd-standards store registration, Atlassian MCP verification, `openspec doctor` health check — finalized once the package-identity change lands + +## 5. Verification + +- [ ] 5.1 After `establish-atd-standards-store` passes every readiness check in task 4.3, run pilot wave 1 on one real Jira ticket in a Python or Angular repo; capture clarification count, artifact rework, documentation completion, external-write failures, cycle time +- [ ] 5.2 Verify conformance to this change's own specs: every scenario in specs/** demonstrably holds in the dry-run or pilot transcript diff --git a/openspec/changes/add-atd-workflow-facades/.openspec.yaml b/openspec/changes/add-atd-workflow-facades/.openspec.yaml new file mode 100644 index 0000000000..7250f8fbf8 --- /dev/null +++ b/openspec/changes/add-atd-workflow-facades/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-07-22 diff --git a/openspec/changes/add-atd-workflow-facades/design.md b/openspec/changes/add-atd-workflow-facades/design.md new file mode 100644 index 0000000000..dc4f8ccd31 --- /dev/null +++ b/openspec/changes/add-atd-workflow-facades/design.md @@ -0,0 +1,76 @@ +# Design: ATD Workflow Façades + +## Context + +`add-atd-sdlc-lite-triage` shipped `atd-change-triage` as the journey entry point, delivered through both generation paths and installed by default via the fork's CORE_WORKFLOWS. Everything downstream still speaks generic OpenSpec: `openspec-continue-change`, `openspec-apply-change`, `openspec-verify-change`, `openspec-archive-change`. Those workflows are schema-aware — they read the change's `.openspec.yaml` and follow whatever schema is selected — so the machinery already does the right thing for ATD changes. Two gaps remain: the names carry no ATD meaning (a developer who just ran `atd-change-triage` has no obvious next step), and the core profile (`propose, explore, apply, update, sync, archive, atd-triage`) omits `continue` and `verify` entirely, so the documented journey is not completable on a default install. + +## Goals / Non-Goals + +**Goals** + +- One consistent, self-describing vocabulary for the ATD journey: triage → continue → apply → verify → close. +- Zero duplicated workflow logic — generic and ATD templates compose shared parameterized instruction-body builders. +- A core profile that installs exactly the workflows an ATD developer needs, by default. +- Generic workflows stay available for maintainers and non-ATD schemas. + +**Non-Goals** + +- Renaming or removing any generic workflow (upstream divergence for no benefit). +- New CLI commands, artifact-graph, or resolver behavior. +- Migrating the existing `atd-triage` id or `atd-change-triage` directory. +- Documenting the journey on the docs site (that is `add-atd-docs-site`'s scope; coordination only). + +## Decisions + +### D1: Single-source façades over existing workflows, not copied prompts + +An agent skill cannot reliably invoke another skill, and the generic skills leave the core profile, so merely telling an ATD façade to "delegate" would not reuse anything. The generic continue/apply/verify/archive template modules therefore expose parameterized instruction-body builders. Their existing getters call those builders with the current generic names and policies, preserving generic generated content byte-for-byte. Each `atd-*` module composes the same builder with ATD journey names, ATD-only schema validation, and the step-specific policy hook (notably close's hard completion gate). Every module embeds `STORE_SELECTION_GUIDANCE` from `src/core/templates/workflows/store-selection.ts`. A parity test locks the generic output while façade contract tests cover the ATD additions. Alternative: rename the generic workflows — rejected; it breaks non-ATD users. Alternative: copy their instruction bodies — rejected; upstream fixes would drift. Alternative: reference an uninstalled generic skill from the façade — rejected; skills are not a dependable runtime call graph. + +Every façade reads `schemaName` from `openspec status --json` before acting. It accepts only `atd-sdlc` or `atd-sdlc-lite`; any other schema stops with the matching generic workflow as the next step. This prevents ATD closure and standards policy from being implied on unrelated schemas. + +### D2: Core profile = five façades + explore + update + +CORE_WORKFLOWS becomes `['atd-triage', 'atd-continue', 'atd-apply', 'atd-verify', 'atd-close', 'explore', 'update']`. The five façades are the journey; `explore` and `update` stay because developers think through problems and revise planning artifacts mid-journey, and both are schema-neutral with no ATD-specific behavior to wrap. Generic `propose`, `sync`, `archive`, `continue`, `apply`, and `verify` leave core: propose authors a proposal directly, which the ATD schemas replace with ticket intake; sync/archive are folded into or gated by close; continue/apply/verify are replaced by their façades. Alternative: keep the generic ids in core alongside the façades — rejected; fourteen installed skills with six near-duplicates is worse UX than the problem being solved. Alternative: also wrap explore/update as `atd-*` façades — rejected; a façade that adds no ATD content is pure indirection (and more registry surface to maintain). + +### D3: Close hard-gates all tracked tasks and preserves archive sync + +Both ATD schemas already make closure mandatory inside apply, but only the full template names an `F. Final group`; lite uses a `Closure` group. `atd-close` therefore does not parse a heading. It obtains apply state from `openspec instructions apply --json` and requires `state: "all_done"`, which proves every tracked checkbox—including closure work—is complete. Any pending task is listed and sends the developer back to `atd-change-apply`; unlike generic archive, ATD close never offers an override for incomplete artifacts or tasks. It never performs publication or Jira closure itself. + +Once complete, close retains the generic archive workflow's delta-spec assessment, optional sync, post-sync verification, and store-aware archive path behavior. Removing that phase would archive full-schema deltas without reconciling main specs. Alternative: put publication/Jira closure in close — rejected because closure would have two homes. Alternative: check only a named final heading — rejected because schema templates use different heading names and all tracked work, not only governance work, must be complete. + +### D4: Generic workflows remain selectable; no id migrations + +Nothing leaves ALL_WORKFLOWS. Maintainers working on this fork's own specs (schema `spec-driven`) and anyone using non-ATD schemas select the generic workflows through the custom profile (`getProfileWorkflows('custom', [...])`). The existing `atd-triage` id, `atd-change-triage` skill dir, and `/opsx:atd-triage` command are kept exactly as shipped — a rename to fit a hypothetical tidier scheme would force a WORKFLOW_TO_SKILL_DIR migration, drift-detection churn, and re-learning for pilot users, for zero functional gain. Only triage's hand-off wording changes (it names `atd-change-continue` as the next step). + +### D5: Registry completeness is a spec requirement, with tool-detection named explicitly + +Shipping `atd-triage` surfaced the full registry checklist the hard way: SKILL_NAMES/COMMAND_IDS in `src/core/shared/tool-detection.ts` were missed and caught in review. This change makes the checklist normative: workflow template module + `skill-templates.ts` export + both generation registries in `skill-generation.ts` + ALL_WORKFLOWS + CORE_WORKFLOWS + WORKFLOW_TO_SKILL_DIR + SKILL_NAMES + COMMAND_IDS + regenerated committed artifacts + tests. A registry-parity test asserts the four surfaces that enumerate workflows by id (generation registries, WORKFLOW_TO_SKILL_DIR, SKILL_NAMES/COMMAND_IDS) stay consistent with ALL_WORKFLOWS, so the next workflow cannot repeat the omission. + +## Solution Flow + +```mermaid +flowchart LR + T[atd-change-triage\nclassify + create change] --> C[atd-change-continue\nnext artifact per schema] + C --> C + C --> A[atd-change-apply\nload standards · execute all tracked tasks] + A --> V[atd-change-verify\ntests · AC · standards · docs · closure readiness] + V -->|gaps found| A + V --> X[atd-change-close\ngate: apply state all_done?] + X -->|unchecked items| A + X -->|all checked| ARC[archive] + E[explore / update\navailable at any point] -.-> C + E -.-> A +``` + +## Risks / Trade-offs + +- [Façade instructions drift from the generic workflows they wrap] → generic and ATD getters compose shared parameterized instruction-body builders; a byte-for-byte generic-output parity test prevents accidental changes while façade tests cover ATD policy and hand-offs. +- [A registry surface is missed again (the tool-detection lesson)] → registry-parity test ties every enumerating surface to ALL_WORKFLOWS; spec requirement makes the checklist reviewable, not tribal knowledge. +- [Closure logic creeps into close over time] → the single-home rule is a SHALL requirement; tests assert pending apply tasks hard-block close and close never performs publication/Jira writes. +- [Close drops generic archive's spec synchronization] → close composes the shared archive body and tests a full-schema change with unsynced deltas before archive. +- [Existing installs have the old core set (generic apply/archive/propose/sync)] → `openspec update` synchronizes installed skills against the active profile using WORKFLOW_TO_SKILL_DIR drift detection; stale generic skills are reported/replaced by the standard update path, no bespoke migration. +- [Docs-site journey pages (in-flight `add-atd-docs-site`) ship with the old vocabulary] → coordination note in the proposal; the docs change is not yet implemented, so aligning its flow pages is a wording-level update before its apply, owned by that change. + +## Rollout + +Ships after `add-atd-sdlc-lite-triage` (façades wrap the journey it created). Regenerated `skills/` artifacts land in the same PR; init/update tests prove ignored project-local delivery flips vocabulary atomically. Coordinate `add-atd-docs-site` flow-page vocabulary before that change's apply. Pilot messaging: "start every ticket with `atd-change-triage`; each skill names the next one." diff --git a/openspec/changes/add-atd-workflow-facades/proposal.md b/openspec/changes/add-atd-workflow-facades/proposal.md new file mode 100644 index 0000000000..760047fc0f --- /dev/null +++ b/openspec/changes/add-atd-workflow-facades/proposal.md @@ -0,0 +1,40 @@ +# Add ATD Workflow Façades + +## Why + +`atd-change-triage` gives ATD developers a named entry point, but everything after it speaks a different vocabulary: the journey continues through generic `openspec-*` skills (`continue`, `apply`, `verify`, `archive`) whose names say nothing about the ATD journey — and two of them (`continue`, `verify`) are not even in the core profile, so a default install cannot complete the documented journey at all. The generic skills are schema-aware and work correctly; the problem is UX and profile composition, not machinery. The fix is a set of thin ATD-named façades over the existing schema-aware workflows, completing the vocabulary triage started: triage → continue → apply → verify → close. + +Depends on `add-atd-sdlc-schema` and `add-atd-sdlc-lite-triage` (the schemas and triage entry point the façades navigate). + +## What Changes + +- Add four workflow façades alongside the existing `atd-triage`, forming the five-step ATD journey. Each names its position in the journey and composes the corresponding generic workflow from a shared instruction-body builder, adding only ATD schema validation, policy, and hand-off wording. Copied generic workflow bodies are prohibited: + - `atd-continue` (skill `atd-change-continue`, command `/opsx:atd-continue`): create the next artifact according to the change's selected ATD schema, via the same `openspec status`/`openspec instructions` machinery the generic continue workflow uses. + - `atd-apply` (skill `atd-change-apply`, command `/opsx:atd-apply`): load the applicable ATD standards and execute the tracked tasks, façade over the generic apply workflow. + - `atd-verify` (skill `atd-change-verify`, command `/opsx:atd-verify`): verify tests, acceptance criteria, standards conformance, documentation, and closure readiness, façade over the generic verify workflow. + - `atd-close` (skill `atd-change-close`, command `/opsx:atd-close`): require every tracked task to be complete, including the ATD closure tasks, then run the archive workflow with its delta-spec sync assessment intact. Close is a hard gate, never a second home for closure logic: it surfaces incomplete work and returns to `atd-change-apply`; it never performs publication or Jira closure itself and never offers the generic archive workflow's incomplete-task override. +- Reject non-ATD changes at every façade: only `atd-sdlc` and `atd-sdlc-lite` are accepted; other schemas are directed to the corresponding generic workflow. +- Recompose the fork's CORE_WORKFLOWS as the five `atd-*` workflows plus `explore` and `update` (developers need exploration and artifact revision mid-journey). Generic `propose`, `sync`, `archive`, `continue`, `apply`, and `verify` ids leave core — their ATD façades replace them as the default user-facing vocabulary. +- Generic `openspec-*` workflows remain fully available through the custom profile for maintainers and non-ATD schemas; nothing is removed from ALL_WORKFLOWS. +- Keep the existing `atd-triage` id and `atd-change-triage` skill directory as-is (no rename, no migration); update only its hand-off wording to name `atd-change-continue` as the next step. +- Register every new workflow across the complete registry surface: workflow template module, skill-templates façade export, both generation registries (skills and commands), ALL_WORKFLOWS, CORE_WORKFLOWS, WORKFLOW_TO_SKILL_DIR, and — explicitly, because it was missed once and caught in review — SKILL_NAMES and COMMAND_IDS in tool-detection. Regenerate the committed `skills/` distribution; verify project-local skill and command generation through init/update tests rather than committing ignored `.claude/` output. + +## Capabilities + +### New Capabilities + +- `atd-workflow-facades`: the five-façade ATD journey vocabulary, the thin-façade and close-gate constraints, the core-profile composition, and the registry-completeness rules for shipping a workflow through both delivery paths. + +### Modified Capabilities + +- `atd-change-triage`: hand-off wording only — triage's final step names `atd-change-continue` instead of the generic continue/apply workflows. Expressed as a requirement inside `atd-workflow-facades` because the `atd-change-triage` spec is itself still an in-flight delta in `add-atd-sdlc-lite-triage`, not yet in main specs. + +## Impact + +- New: `src/core/templates/workflows/atd-continue.ts`, `atd-apply.ts`, `atd-verify.ts`, `atd-close.ts` (skill + command template per module, following `atd-triage.ts`), each embedding the shared `STORE_SELECTION_GUIDANCE` block and rejecting non-ATD schemas. +- Modified: the generic continue/apply/verify/archive template modules expose shared, parameterized instruction-body builders. Existing generic generated content remains byte-for-byte stable under parity tests; ATD façades compose those builders instead of copying their workflow logic. +- Modified: `src/core/templates/skill-templates.ts` (exports), `src/core/shared/skill-generation.ts` (both registries: 13 → 17 entries each), `src/core/profiles.ts` (ALL_WORKFLOWS 13 → 17; CORE_WORKFLOWS recomposed), `src/core/profile-sync-drift.ts` (WORKFLOW_TO_SKILL_DIR), `src/core/shared/tool-detection.ts` (SKILL_NAMES and COMMAND_IDS 13 → 17), `src/core/templates/workflows/atd-triage.ts` (hand-off wording). +- Regenerated committed artifacts: `skills/` via `scripts/generate-skillssh.mjs`. `.claude/` remains ignored and uncommitted; init/update tests verify its generated core-profile shape (generic `apply`/`archive`/`propose`/`sync` out, `atd-*` in). +- Tests: count assertions bump in `test/core/profiles.test.ts`, `test/core/shared/tool-detection.test.ts`, `test/core/shared/skill-generation.test.ts`; template parity and skills.sh parity tests pick up the new modules; new façade tests follow `test/core/atd-triage-workflow.test.ts`. +- Coordination note (no files modified here): `add-atd-docs-site` (in flight, not yet implemented) documents the developer journey — its flow pages must use the `atd-change-*` vocabulary and five-step journey introduced here. Flagged to that change's owner; this change does not edit it. +- No artifact-graph, resolver, or CLI behavior changes; façades ride the existing instruction/template generation pipeline. diff --git a/openspec/changes/add-atd-workflow-facades/specs/atd-workflow-facades/spec.md b/openspec/changes/add-atd-workflow-facades/specs/atd-workflow-facades/spec.md new file mode 100644 index 0000000000..ccc3c0d4e3 --- /dev/null +++ b/openspec/changes/add-atd-workflow-facades/specs/atd-workflow-facades/spec.md @@ -0,0 +1,98 @@ +# atd-workflow-facades Specification (delta) + +## ADDED Requirements + +### Requirement: Five-façade ATD journey vocabulary +The system SHALL provide five ATD-facing workflows forming the journey triage → continue → apply → verify → close, with workflow ids `atd-triage`, `atd-continue`, `atd-apply`, `atd-verify`, `atd-close`, skill directory names `atd-change-triage`, `atd-change-continue`, `atd-change-apply`, `atd-change-verify`, `atd-change-close`, and command ids `/opsx:atd-triage`, `/opsx:atd-continue`, `/opsx:atd-apply`, `/opsx:atd-verify`, `/opsx:atd-close`. Each workflow's instructions SHALL name its position in the journey and the next step. The existing `atd-triage` id and `atd-change-triage` directory SHALL be kept as-is (no rename or migration); its hand-off wording SHALL name `atd-change-continue` as the next step. + +#### Scenario: Journey positions named +- **WHEN** any of the five ATD workflow templates is generated +- **THEN** its instructions state where the workflow sits in the triage → continue → apply → verify → close journey and name the next workflow in the sequence + +#### Scenario: Triage hands off to continue +- **WHEN** the `atd-change-triage` skill completes change creation +- **THEN** its hand-off step names `atd-change-continue` as the next step, and the `atd-triage` id and `atd-change-triage` directory are unchanged + +### Requirement: Façades compose existing machinery from one source +Each new ATD workflow SHALL compose the corresponding generic workflow from a shared parameterized instruction-body builder rather than copy its prompt or depend on invoking another installed skill. `atd-continue` SHALL create the next artifact through the shared continue status/instructions flow; `atd-apply` SHALL load the schema-provided ATD standards instructions and execute tracked tasks through the shared apply flow; `atd-verify` SHALL verify tests, acceptance criteria, standards conformance, documentation, and closure readiness through the shared verify flow; `atd-close` SHALL retain the shared archive flow subject to the stricter ATD completion gate below. Existing generic generated instructions SHALL remain byte-for-byte unchanged. Each deployed template SHALL include the shared store-selection guidance block (`STORE_SELECTION_GUIDANCE`). + +#### Scenario: Continue façade delegates schema resolution +- **WHEN** `atd-change-continue` runs against a change created with `--schema atd-sdlc-lite` +- **THEN** the next artifact is determined by the lite schema's graph through the same `openspec` status/instructions commands the generic continue workflow uses, with no schema logic embedded in the façade + +#### Scenario: Generic output remains stable +- **WHEN** the generic workflow getters are migrated to shared instruction-body builders +- **THEN** their generated skill and command content is byte-for-byte identical to the pre-change output + +#### Scenario: Store-selection guidance present +- **WHEN** any of the four new workflow templates is deployed +- **THEN** its content includes the shared store-selection guidance block and the template parity test passes + +### Requirement: Façades accept only ATD schemas +Every ATD façade SHALL read `schemaName` from `openspec status --json` before performing its workflow action and SHALL continue only for `atd-sdlc` or `atd-sdlc-lite`. For any other schema it SHALL stop without modifying artifacts, code, specs, tasks, or archive state and SHALL direct the developer to the corresponding generic workflow. + +#### Scenario: Non-ATD change rejected +- **WHEN** `atd-change-apply` is invoked for a `spec-driven` change +- **THEN** it makes no change and directs the developer to `openspec-apply-change` + +### Requirement: Close hard-gates tracked work and holds no closure logic +`atd-close` SHALL obtain the apply state from `openspec instructions apply --json` and require every tracked task to be complete, including standards conformance, documentation, and Jira closure tasks. It SHALL NOT rely on a particular task-group heading. When any artifact or task is incomplete, close SHALL surface the incomplete items, direct the developer to `atd-change-apply`, and stop without offering an override. Close SHALL NOT perform publication, Jira closure, or any other closure work itself. + +#### Scenario: Any unchecked task blocks archive +- **WHEN** `atd-change-close` runs against a change with any unchecked tracked task (including a Jira closure task) +- **THEN** close lists the unchecked items, directs the developer to `atd-change-apply`, and does not archive or perform the closure work itself + +#### Scenario: Fully checked task list continues to archive +- **WHEN** `atd-change-close` runs and apply reports `state: "all_done"` +- **THEN** close continues into the shared archive flow + +### Requirement: Close preserves delta-spec synchronization +For an ATD change with delta specs, `atd-close` SHALL retain the generic archive workflow's store-aware delta-spec comparison, sync choice, synchronous sync execution, and post-sync verification before moving the change to the archive. A failed or unverifiable sync SHALL stop archive. + +#### Scenario: Unsynced full-schema deltas +- **WHEN** a completed `atd-sdlc` change has delta specs not reflected in main specs +- **THEN** close presents the sync assessment and does not archive until the selected sync completes and every delta is verified against the main specs + +### Requirement: Core profile composition +CORE_WORKFLOWS SHALL be the five ATD workflows plus `explore` and `update`: `['atd-triage', 'atd-continue', 'atd-apply', 'atd-verify', 'atd-close', 'explore', 'update']`. The generic `propose`, `sync`, `archive`, `continue`, `apply`, and `verify` ids SHALL NOT be in the core profile. + +#### Scenario: Default init installs the ATD journey +- **WHEN** `openspec init` runs with the core profile +- **THEN** the five `atd-change-*` skills plus explore and update are installed, and no generic propose/sync/archive/continue/apply/verify skill is installed + +#### Scenario: Mid-journey revision available by default +- **WHEN** a developer on a default install needs to revise a planning artifact between apply and verify +- **THEN** the `update` workflow is already installed without profile selection + +### Requirement: Generic workflows remain selectable +All generic workflow ids SHALL remain in ALL_WORKFLOWS and SHALL be installable through the custom profile for maintainers and non-ATD schemas. No generic workflow SHALL be renamed or removed by this change. + +#### Scenario: Maintainer selects generic workflows +- **WHEN** a user configures the custom profile with `['propose', 'continue', 'apply', 'verify', 'archive']` +- **THEN** the generic `openspec-*` skills and `/opsx:*` commands for those ids are installed and functional + +### Requirement: Registry completeness for every new workflow +Each new workflow SHALL be registered across every enumerating surface: a workflow template module in `src/core/templates/workflows/`, the `skill-templates.ts` façade export, both generation registries (`getSkillTemplates` and `getCommandTemplates`), ALL_WORKFLOWS, CORE_WORKFLOWS (where applicable), WORKFLOW_TO_SKILL_DIR, and SKILL_NAMES and COMMAND_IDS in `src/core/shared/tool-detection.ts`. A registry-parity test SHALL fail when any surface that enumerates workflows by id is inconsistent with ALL_WORKFLOWS. + +#### Scenario: Registered in both generation registries +- **WHEN** the skill and command template registries are queried for each of the four new workflow ids +- **THEN** exactly one skill entry (with the `atd-change-` directory name) and exactly one command entry exist per id + +#### Scenario: Tool-detection surfaces extended +- **WHEN** SKILL_NAMES and COMMAND_IDS are inspected after this change +- **THEN** both contain the four new entries and their lengths match the generation registries (17) + +#### Scenario: Registry omission fails CI +- **WHEN** a future workflow id is added to ALL_WORKFLOWS but omitted from WORKFLOW_TO_SKILL_DIR, SKILL_NAMES, or COMMAND_IDS +- **THEN** the registry-parity test fails + +### Requirement: Distribution artifacts regenerated +The committed `skills/` distribution (via `scripts/generate-skillssh.mjs`) SHALL gain the four new `atd-change-*` skill directories and SHALL pass template parity tests. Project-local `.claude/` output SHALL remain ignored and uncommitted; init and update tests SHALL verify that skills-only, commands-only, and combined delivery generate the new core profile correctly. + +#### Scenario: skills.sh distribution regenerated +- **WHEN** the skills.sh parity test runs after this change +- **THEN** `skills/atd-change-continue/`, `skills/atd-change-apply/`, `skills/atd-change-verify/`, and `skills/atd-change-close/` exist and match the generated templates + +#### Scenario: Generated project command set reflects new core profile +- **WHEN** init or update generates commands for a temporary project using the core profile +- **THEN** it creates the five `atd-*` commands plus explore and update, and removes or omits generic propose/sync/archive/continue/apply/verify command files diff --git a/openspec/changes/add-atd-workflow-facades/tasks.md b/openspec/changes/add-atd-workflow-facades/tasks.md new file mode 100644 index 0000000000..dc6f36bc77 --- /dev/null +++ b/openspec/changes/add-atd-workflow-facades/tasks.md @@ -0,0 +1,34 @@ +# Tasks: Add ATD Workflow Façades + +## 1. Shared workflow composition + +- [ ] 1.1 Extract parameterized instruction-body builders from `continue-change.ts`, `apply-change.ts`, `verify-change.ts`, and `archive-change.ts`; preserve existing generic skill and command output byte-for-byte; verify with focused template snapshot/parity tests +- [ ] 1.2 Add the shared ATD schema guard (`schemaName` must be `atd-sdlc` or `atd-sdlc-lite`) and tests proving a `spec-driven` change stops without mutation and names the corresponding generic workflow + +## 2. ATD workflow template modules + +- [ ] 2.1 Create `src/core/templates/workflows/atd-continue.ts` (skill `atd-change-continue`, command `atd-continue`) by composing the shared continue body; name journey step 2, create one next artifact from status/instructions, and hand off to `atd-change-apply` when apply-ready; verify `pnpm build` and focused tests +- [ ] 2.2 Create `src/core/templates/workflows/atd-apply.ts` (skill `atd-change-apply`, command `atd-apply`) by composing the shared apply body; follow schema-provided standards/apply instructions, complete every tracked task including closure tasks, and hand off to `atd-change-verify`; verify focused tests +- [ ] 2.3 Create `src/core/templates/workflows/atd-verify.ts` (skill `atd-change-verify`, command `atd-verify`) by composing the shared verify body; verify tests, AC traceability, standards, documentation, and closure readiness, then hand off to `atd-change-close`; verify focused tests +- [ ] 2.4 Create `src/core/templates/workflows/atd-close.ts` (skill `atd-change-close`, command `atd-close`) by composing the shared archive body with a hard gate on `openspec instructions apply --json` reporting `state: "all_done"`; retain delta-spec assessment/sync/post-sync verification, never override incomplete work, and never perform publication or Jira closure; verify focused tests +- [ ] 2.5 Update `src/core/templates/workflows/atd-triage.ts` so its hand-off names `atd-change-continue`; verify `test/core/atd-triage-workflow.test.ts` + +## 3. Registry and profile surfaces + +- [ ] 3.1 Export the four template pairs from `src/core/templates/skill-templates.ts` and register them in both registries in `src/core/shared/skill-generation.ts`; verify exactly one skill and command entry per workflow id +- [ ] 3.2 Add the four ids to `ALL_WORKFLOWS`, recompose `CORE_WORKFLOWS` as `atd-triage`, `atd-continue`, `atd-apply`, `atd-verify`, `atd-close`, `explore`, `update`, and update profile/config expectations; verify profile tests +- [ ] 3.3 Extend `WORKFLOW_TO_SKILL_DIR`, `SKILL_NAMES`, and `COMMAND_IDS` with all four façades; add behavior tests proving façade-only skill and command installations are detected +- [ ] 3.4 Add registry-parity coverage tying both generation registries, `WORKFLOW_TO_SKILL_DIR`, `SKILL_NAMES`, and `COMMAND_IDS` to `ALL_WORKFLOWS`; verify an intentional omission fails the test + +## 4. Journey and delivery tests + +- [ ] 4.1 Add `test/core/atd-facades-workflow.test.ts` covering both skill and command surfaces: journey positions/handoffs, ATD-only schema guard, shared store guidance, continue/apply/verify composition, close hard gate, and absence of closure writes in close +- [ ] 4.2 Add an integration test for `atd-close`: incomplete tasks block without override; completed full-schema tasks with unsynced deltas enter the archive sync assessment and cannot archive on failed verification +- [ ] 4.3 Test core-profile init and update for skills-only, commands-only, and combined delivery: install the five ATD façades plus explore/update and remove or omit generic propose/sync/archive/continue/apply/verify surfaces +- [ ] 4.4 Bump count/order expectations from 13 to 17 and run the full test suite + +## 5. Distribution and coordination + +- [ ] 5.1 Run `pnpm build && pnpm generate:skills`; commit the four new `skills/atd-change-*/SKILL.md` files and verify skills.sh parity. Keep ignored `.claude/` output uncommitted +- [ ] 5.2 Align `add-atd-docs-site` journey requirements with the five-step `atd-change-*` vocabulary before either change ships; verify both changes validate strictly +- [ ] 5.3 Add the appropriate changeset for the user-visible workflow/profile change; verify package contents and release notes describe the new default ATD journey diff --git a/schemas/atd-sdlc-lite/schema.yaml b/schemas/atd-sdlc-lite/schema.yaml new file mode 100644 index 0000000000..d29f666f9c --- /dev/null +++ b/schemas/atd-sdlc-lite/schema.yaml @@ -0,0 +1,217 @@ +name: atd-sdlc-lite +version: 1 +description: ATD lightweight workflow for low-risk corrections - ticket → analysis → tasks +artifacts: + - id: ticket + generates: ticket.md + description: Compact ticket intake for a low-risk correction + template: ticket.md + instruction: | + Create the compact ticket document for a low-risk correction. This is the + lite schema: the change was routed here by triage (see `triage.md`) because + it restores existing intended behavior with localized impact. Keep the + document short — same required data as the full schema, less prose. + + Change names use the Jira ticket key (e.g. `abc-1234-add-export`). Derive the + ticket key from the change name. + + **Intake:** + 1. Pull the Jira issue and ALL linked Confluence pages via the Atlassian MCP. + 2. If the Atlassian MCP is unavailable, ask the developer to paste the ticket + content and continue with the same checklist below. + 3. Record in ticket.md: the normalized problem statement, acceptance criteria + with stable IDs (AC-1, AC-2, …), affected systems, and links to the Jira + issue and every Confluence source. + + **Triage record (mandatory gate):** + A sidecar is STRUCTURALLY complete when `triage.md` contains a + recommendation, the developer's confirmed choice, and an evaluation for + every eligibility condition listed below. Structural completeness is not + enough — lite processing may continue ONLY when all three hold: + - every condition evaluation is a pass (no FAIL, no UNCERTAIN), and + - the recommendation is `atd-sdlc-lite`, and + - the confirmed choice is `atd-sdlc-lite`. + When all three hold, fold the routing record (recommendation, condition + evaluations, confirmed choice) into ticket.md and continue. If any + evaluation is FAIL or UNCERTAIN, or the recommendation or confirmed + choice is not `atd-sdlc-lite`, inform the developer, append the + escalation to `triage.md`, and switch the change's `.openspec.yaml` to + `schema: atd-sdlc` before proceeding. + + If the sidecar is missing, empty, or structurally incomplete, treat it + exactly like a missing record — the change bypassed triage — and run the + eligibility evaluation now, before intake continues: perform a bounded + codebase preflight (owning component, entry points and call path, + covering tests/specs, impact check), evaluate every condition below, + write `triage.md` with the evaluations marked "self-triage at ticket + intake", and apply the same gate to the result. Lite processing without + a valid, all-pass triage record is never allowed. + + Eligibility conditions — ALL must pass; classification is risk-based, + never line count (a one-line change to an authorization condition, SQL + WHERE clause, or financial calculation is full regardless of size): + 1. Single repository and single component + 2. Small, localized file impact + 3. Restores existing intended behavior (no new behavior) + 4. Existing acceptance criteria, specification, or test already defines the behavior + 5. No API contract change + 6. No database/schema/data migration + 7. No authentication, authorization, security, privacy, or compliance impact + 8. No cross-service integration behavior change + 9. No new dependency + 10. No deployment or infrastructure change + 11. Straightforward automated regression test exists or is easy to add + 12. Trivial rollback + 13. No new functional or technical documentation needed (localized + corrections to existing docs stay lite-eligible) + + **Branch alignment (advisory):** + Compare the current git branch name with the ticket key. If the branch does not + reference the key, suggest creating or switching to a branch named after the + ticket (e.g. `abc-1234-add-export`). This is a suggestion only — never block, + and never create or switch branches without explicit developer confirmation. + Record the branch used (and any declined suggestion) in ticket.md. + + **Restored behavior (lite-specific, mandatory):** + Record an explicit confirmation of WHICH existing intended behavior this + change restores. A lite change never introduces new behavior — if it does, + it does not belong in this schema; escalate via the analysis artifact. + + **Completeness checklist (gate):** + - Problem statement + - Acceptance criteria + - Affected systems + - Edge cases + - Constraints + - Out-of-scope + + **Grilling protocol (when any checklist item is missing):** + - First explore the codebase for answers. A question the code can answer + (e.g. which module owns the behavior) is answered by reading the code, + never asked. + - Otherwise ask the developer EXACTLY ONE question at a time, and attach a + recommended answer to every question. + - Loop until the checklist passes. + - Record the question/answer trace in ticket.md under "Clarified Requirements". + - If the ticket is already adequate, the checklist passes trivially — do not + interrogate for its own sake. + + **Jira write-back (confirmed, idempotent):** + After grilling produced clarified requirements, OFFER to update the Jira issue. + Proceed only after the developer confirms. Write into a clearly delimited + managed section of the issue description: + + ---- OPENSPEC MANAGED SECTION (auto-generated, do not edit) ---- + ...clarified requirements... + ---- END OPENSPEC MANAGED SECTION ---- + + Re-runs replace ONLY the managed section and never touch human-authored + content. Note the update in ticket.md. If the developer declines, or the + project's `rules: ticket:` config disables write-back, record clarified + requirements only in ticket.md. + requires: [] + + - id: analysis + generates: analysis.md + description: Short impact assessment with lite-eligibility justification + template: analysis.md + instruction: | + Create the short impact assessment. Same evidence standards as the full + schema, scoped to a correction — this document must satisfy the full + schema's content contract so escalation retains it without regeneration. + + **Code is the source of truth.** Derive current behavior from the code itself. + Documentation (Confluence, comments, wikis) is a hint to verify against code. + When documentation and code disagree, record the code's behavior as current + truth and list the discrepancy for the developer. Business rules found in code + that no documentation mentions are captured with their citation. + + **Evidence:** + - Record the repository commit SHA once at the top of the document. + - Every claim about existing behavior carries a `file:line` citation + (e.g. `src/orders/service.py:120-141`). + - Name the affected stacks from the explicit set: + {python, spring-boot, oracle-ebs, angular}. The apply phase maps these to + standards specs, so this list is mandatory. + + **Required content:** + - Root cause of the defect, with citation. + - Target files for the correction. + - The existing acceptance criteria, specification, or test that covers the + intended behavior. + - Risk assessment. + - Why this change qualifies for lite processing — re-confirm the condition + evaluations recorded in `triage.md` against what the analysis found. + + **Escalation check (mandatory, before tasks are created):** + If the assessment uncovers ANY full-workflow trigger — API contract change, + database/schema/data migration, authentication/authorization/security/ + privacy/compliance impact, cross-service integration behavior, new + dependency, deployment or infrastructure change, new behavior rather than + restoration, or a needed new solution document — STOP: + 1. Inform the developer of the trigger. + 2. Append an escalation entry to `triage.md`: the trigger discovered, + previous schema (atd-sdlc-lite), new schema (atd-sdlc), and reason. + 3. Edit the change's `.openspec.yaml` metadata to `schema: atd-sdlc`. + 4. The completed ticket.md and analysis.md are retained — they satisfy the + full schema's contract. Subsequent commands reread the schema metadata: + specs and design become ready; solution-doc and tasks stay blocked. + Downgrading a full change to lite is not supported. + requires: + - ticket + + - id: tasks + generates: tasks.md + description: Standard lite task checklist + template: tasks.md + instruction: | + Create the lite task list. Standard shape, in this order: + + 1. Implement the correction (name target files from analysis.md; reference + the AC IDs served). + 2. Add or update a regression test covering the restored behavior. + 3. Run the relevant verification command and record the result. + 4. One standards check per affected stack in analysis.md, naming the mapped + spec: python → python-service-standards, + spring-boot → spring-boot-standards, + oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards. + 5. Documentation impact: record "no new solution document or durable + documentation set is needed" — applying localized corrections to + existing documentation is allowed and noted here. If a NEW document + turns out to be needed, that is a full-workflow trigger: escalate + (see apply instruction) instead of writing it under lite. + 6. Add an idempotent Jira closure comment: summary of the correction and + verification evidence; re-runs update the existing closure comment + instead of posting a duplicate. + + Every task states its verification (test command, CLI invocation, or + observable output). + requires: + - analysis + +apply: + requires: [tasks] + tracks: tasks.md + instruction: | + Before implementing ANY task: fetch the standards spec mapped to each stack + listed in analysis.md from the atd-standards store — + python → python-service-standards, spring-boot → spring-boot-standards, + oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards — + and conform to it while writing code. + + Work through the checklist in order, mark each checkbox complete as you go. + + **Late escalation (full-workflow trigger found after tasks.md exists or + during apply):** continuing under lite is unsafe. STOP: + 1. Stop implementation; leave further lite checkboxes unchecked. + 2. Move `tasks.md` to `tasks.lite.md` as audit history — the tracked + tasks.md path must be absent so the full schema's tasks artifact is not + falsely complete. + 3. Append an escalation entry to `triage.md`: trigger, previous schema + (atd-sdlc-lite), new schema (atd-sdlc), reason. + 4. Update ticket.md and analysis.md for the wider scope. + 5. Edit the change's `.openspec.yaml` metadata to `schema: atd-sdlc`. + 6. Continue under the full schema: specs and design become ready; + solution-doc and tasks are blocked; apply is blocked until a new full + tasks.md exists. The regenerated full task list MUST account for any + partial implementation — verify, reconcile, or revert it. diff --git a/schemas/atd-sdlc-lite/templates/analysis.md b/schemas/atd-sdlc-lite/templates/analysis.md new file mode 100644 index 0000000000..4b6bf7f47d --- /dev/null +++ b/schemas/atd-sdlc-lite/templates/analysis.md @@ -0,0 +1,20 @@ +# Impact Assessment + +**Commit SHA:** +**Affected stacks:** + +## Root Cause + + + +## Target Files + +## Covering Specification / Test + + + +## Risk Assessment + +## Lite Eligibility + + diff --git a/schemas/atd-sdlc-lite/templates/tasks.md b/schemas/atd-sdlc-lite/templates/tasks.md new file mode 100644 index 0000000000..f01ee7a927 --- /dev/null +++ b/schemas/atd-sdlc-lite/templates/tasks.md @@ -0,0 +1,11 @@ +## 1. Correction + +- [ ] 1.1 Implement the correction — files: ; covers: ; verify: +- [ ] 1.2 Add/update regression test for the restored behavior; verify: +- [ ] 1.3 Run verification and record the result: + +## 2. Closure + +- [ ] 2.1 Verify conformance to scenarios; note deviations +- [ ] 2.2 Documentation impact: record "no new solution document or durable documentation set needed"; apply localized corrections to existing docs if any; verify: statement recorded here, doc diffs listed if any +- [ ] 2.3 Add idempotent Jira closure comment (summary + verification evidence; re-run updates, never duplicates); verify: comment URL noted here diff --git a/schemas/atd-sdlc-lite/templates/ticket.md b/schemas/atd-sdlc-lite/templates/ticket.md new file mode 100644 index 0000000000..8cd9ae7e3d --- /dev/null +++ b/schemas/atd-sdlc-lite/templates/ticket.md @@ -0,0 +1,33 @@ +# Ticket: + +## Sources + +- Jira: +- Confluence: +- Branch: + +## Problem Statement + +## Acceptance Criteria + +- **AC-1**: + +## Affected Systems + +## Restored Behavior + + + +## Edge Cases + +## Constraints + +## Out of Scope + +## Clarified Requirements + + + +## Triage Record + + diff --git a/schemas/atd-sdlc/schema.yaml b/schemas/atd-sdlc/schema.yaml new file mode 100644 index 0000000000..b1d4074366 --- /dev/null +++ b/schemas/atd-sdlc/schema.yaml @@ -0,0 +1,259 @@ +name: atd-sdlc +version: 1 +description: ATD workflow - Jira ticket → analysis → (specs, design) → solution-doc → tasks +artifacts: + - id: ticket + generates: ticket.md + description: Normalized ticket intake from Jira and Confluence with completeness gate + template: ticket.md + instruction: | + Create the ticket document that establishes WHAT was asked and makes it complete. + + Change names use the Jira ticket key (e.g. `abc-1234-add-export`). Derive the + ticket key from the change name. + + **Intake:** + 1. Pull the Jira issue and ALL linked Confluence pages via the Atlassian MCP. + 2. If the Atlassian MCP is unavailable, ask the developer to paste the ticket + content and continue with the same checklist below. + 3. Record in ticket.md: the normalized problem statement, acceptance criteria + with stable IDs (AC-1, AC-2, …), affected systems, and links to the Jira + issue and every Confluence source. + + **Triage record:** + If a `triage.md` sidecar exists in the change directory, fold its routing + record (recommendation, condition evaluations, confirmed choice) into + ticket.md. When no sidecar exists, proceed normally — direct full-schema + creation needs no triage. + + **Branch alignment (advisory):** + Compare the current git branch name with the ticket key. If the branch does not + reference the key, suggest creating or switching to a branch named after the + ticket (e.g. `abc-1234-add-export`). This is a suggestion only — never block, + and never create or switch branches without explicit developer confirmation. + Record the branch used (and any declined suggestion) in ticket.md. + + **Completeness checklist (gate):** + - Problem statement + - Acceptance criteria + - Affected systems + - Edge cases + - Constraints + - Out-of-scope + + **Grilling protocol (when any checklist item is missing):** + - First explore the codebase for answers. A question the code can answer + (e.g. which module owns the behavior) is answered by reading the code, + never asked. + - Otherwise ask the developer EXACTLY ONE question at a time, and attach a + recommended answer to every question. + - Loop until the checklist passes. + - Record the question/answer trace in ticket.md under "Clarified Requirements". + - If the ticket is already adequate, the checklist passes trivially — do not + interrogate for its own sake. + + **Jira write-back (confirmed, idempotent):** + After grilling produced clarified requirements, OFFER to update the Jira issue. + Proceed only after the developer confirms. Write into a clearly delimited + managed section of the issue description: + + ---- OPENSPEC MANAGED SECTION (auto-generated, do not edit) ---- + ...clarified requirements... + ---- END OPENSPEC MANAGED SECTION ---- + + Re-runs replace ONLY the managed section and never touch human-authored + content. Note the update in ticket.md. If the developer declines, or the + project's `rules: ticket:` config disables write-back, record clarified + requirements only in ticket.md. + requires: [] + + - id: analysis + generates: analysis.md + description: Evidence-cited analysis of current behavior with affected stacks + template: analysis.md + instruction: | + Create the analysis document that establishes how the system behaves TODAY. + + **Code is the source of truth.** Derive current behavior from the code itself. + Documentation (Confluence, comments, wikis) is a hint to verify against code. + When documentation and code disagree, record the code's behavior as current + truth and list the discrepancy for the developer. Business rules found in code + that no documentation mentions are captured with their citation. + + **Evidence:** + - Record the repository commit SHA once at the top of the document. + - Every claim about existing behavior carries a `file:line` citation + (e.g. `src/orders/service.py:120-141`). + - Name the affected stacks from the explicit set: + {python, spring-boot, oracle-ebs, angular}. The apply phase maps these to + standards specs, so this list is mandatory. + + **Token-efficient reading — scope everything to the acceptance criteria:** + - For each AC, locate the entry points (endpoint, job, UI action) it concerns. + - Trace the call path from the entry point and read only the sections that + path touches. + - Never sweep whole directories or whole files when a targeted read answers + the question. + - When the project's `rules: analysis:` config names code-index or code-graph + tooling, prefer it over raw file reads for symbol lookup and call-path + tracing. + + If analysis reveals the ticket's acceptance criteria are wrong or incomplete, + return to the ticket artifact and update it with the developer. + requires: + - ticket + + - id: specs + generates: "specs/**/*.md" + description: Delta specifications traceable to acceptance criteria + template: spec.md + instruction: | + Create specification files that define WHAT the system should do. + + A spec is a behavior contract, not an implementation plan. + + **AC traceability (mandatory):** every requirement MUST reference at least one + acceptance-criterion ID from ticket.md — write "Covers: AC-n" in the + requirement description. A candidate requirement with no matching acceptance + criterion is scope invention: either drop it or return to the ticket artifact + and add the criterion with the developer. Never keep an untraceable + requirement. + + Create one spec file per capability: specs//spec.md, kebab-case + names. + + Delta operations (use ## headers): + - **ADDED Requirements**: new capabilities + - **MODIFIED Requirements**: changed behavior — MUST include full updated content + - **REMOVED Requirements**: deprecated — MUST include **Reason** and **Migration** + - **RENAMED Requirements**: name changes only — FROM:/TO: format + + Format requirements: + - Each requirement: `### Requirement: ` followed by description with + SHALL/MUST language and its "Covers: AC-n" line. + - Each scenario: `#### Scenario: ` with WHEN/THEN format. + - **CRITICAL**: scenarios use exactly 4 hashtags (`####`). + - Every requirement MUST have at least one scenario. + + Specs should be testable — each scenario is a potential test case. + requires: + - analysis + + - id: design + generates: design.md + description: Technical decisions, alternatives, risks, and solution flow + template: design.md + instruction: | + Create the design document that explains HOW to implement the change. + + Sections: + - **Context**: current state from analysis.md, constraints + - **Decisions**: key technical choices with rationale and alternatives + considered (why X over Y?) + - **Solution Flow**: a mermaid diagram — REQUIRED when the change spans + multiple components or the flow is non-trivial; OMIT it for + single-component changes with a straightforward flow. Never draw a diagram + merely to satisfy the template. + - **Risks / Trade-offs**: [Risk] → Mitigation format + + Omit any section that has no content. Never fill a section with boilerplate. + Keep the document under roughly 1,000 words — design records decisions, not + an essay. + + Reference the ticket for motivation, analysis for current behavior, specs for + requirements. + requires: + - analysis + + - id: solution-doc + generates: solution.md + description: Enterprise-facing functional and technical solution document + template: solution.md + instruction: | + Create solution.md — the enterprise-facing functional and technical document. + It exists BEFORE implementation and is reconciled against the code after. + + **Full section set** (scale depth to the change size; OMIT any section that + does not apply — a section is never filled with boilerplate to satisfy the + template): + - Executive summary + - Functional problem and proposed behavior + - Scope and business rules + - Acceptance-criteria traceability (table mapping AC IDs → spec requirements) + - Current and proposed technical architecture + - APIs, data, security, observability + - Migration and rollback + - Testing strategy + - Standards applied (the mapped standards spec per affected stack) + - As-built implementation and deviations — initialize as + "Pending implementation"; the final task group updates it + - Publication and release metadata + + For a small fix with no API, data, migration, or security surface, the + document is short: summary, behavior, traceability, testing, standards — + nothing else. + + Content comes from ticket.md (what and why), specs (contract), and design.md + (how). Do not invent content that is not in those artifacts. + requires: + - specs + - design + + - id: tasks + generates: tasks.md + description: Verifiable implementation checklist with mandatory final group + template: tasks.md + instruction: | + Create the task list that breaks down the implementation work. + + **IMPORTANT: follow the checkbox format exactly.** The apply phase parses + `- [ ] X.Y` checkboxes to track progress. + + **Every task MUST state:** + - the target files or modules it touches + - the acceptance-criterion IDs it serves (e.g. "AC-2, AC-3") + - a verification command or check (test command, CLI invocation, or + observable output) + + Exception: governance tasks in the mandatory final group (standards + conformance, reconciliation, publication, Jira closure) need no code + files or AC IDs, but MUST still state their verification evidence. + + Group related tasks under ## numbered headings, ordered by dependency. + + **Mandatory final task group — apply is complete only when these are checked:** + 1. One standards-conformance task per affected stack in analysis.md, naming + the mapped spec: python → python-service-standards, + spring-boot → spring-boot-standards, + oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards. + (e.g. "Verify conformance to `angular-standards` scenarios; note deviations") + 2. Reconcile solution.md against the implemented code: update the as-built + section, record every deviation from design with its reason and + verification evidence. + 3. Publish the reconciled solution.md to the destination declared in the + project's `rules: tasks:` config — `confluence` (page under the configured + space/parent via the Atlassian MCP, record the page URL in solution.md), + `repo` (markdown under docs/), or `both` (repo first, then Confluence). + When no destination is configured, ask the developer to choose before + publishing. + 4. Add an idempotent Jira closure comment: change summary plus links to the + published documentation; re-runs update the existing closure comment + instead of posting a duplicate. + requires: + - solution-doc + +apply: + requires: [tasks] + tracks: tasks.md + instruction: | + Before implementing ANY task: fetch the standards spec mapped to each stack + listed in analysis.md from the atd-standards store — + python → python-service-standards, spring-boot → spring-boot-standards, + oracle-ebs → oracle-ebs-plsql-standards, angular → angular-standards — + and conform to it while writing code. + + Read context files, work through pending tasks in order, mark each checkbox + complete as you go. The mandatory final task group (standards conformance, + solution.md reconciliation, publication, Jira closure) is part of apply — + apply is complete only when it is checked. Pause on blockers or unclear + requirements. diff --git a/schemas/atd-sdlc/templates/analysis.md b/schemas/atd-sdlc/templates/analysis.md new file mode 100644 index 0000000000..e97ac39d1f --- /dev/null +++ b/schemas/atd-sdlc/templates/analysis.md @@ -0,0 +1,20 @@ +# Analysis + +**Commit SHA:** +**Affected stacks:** + +## Current Behavior + + + +## Documentation Discrepancies + + + +## Entry Points and Call Paths + + + +## Observations + + diff --git a/schemas/atd-sdlc/templates/design.md b/schemas/atd-sdlc/templates/design.md new file mode 100644 index 0000000000..e92e4b3a61 --- /dev/null +++ b/schemas/atd-sdlc/templates/design.md @@ -0,0 +1,17 @@ +# Design + +## Context + + + +## Decisions + + + +## Solution Flow + + + +## Risks / Trade-offs + + diff --git a/schemas/atd-sdlc/templates/solution.md b/schemas/atd-sdlc/templates/solution.md new file mode 100644 index 0000000000..1fd22a4a14 --- /dev/null +++ b/schemas/atd-sdlc/templates/solution.md @@ -0,0 +1,35 @@ +# Solution: + + + +## Executive Summary + +## Functional Problem and Proposed Behavior + +## Scope and Business Rules + +## Acceptance-Criteria Traceability + +| AC | Requirement | Spec | +|----|-------------|------| +| AC-1 | | | + +## Technical Architecture (Current and Proposed) + +## APIs, Data, Security, Observability + +## Migration and Rollback + +## Testing Strategy + +## Standards Applied + + + +## As-Built Implementation and Deviations + +Pending implementation. + +## Publication and Release Metadata + + diff --git a/schemas/atd-sdlc/templates/spec.md b/schemas/atd-sdlc/templates/spec.md new file mode 100644 index 0000000000..76a2a578a8 --- /dev/null +++ b/schemas/atd-sdlc/templates/spec.md @@ -0,0 +1,11 @@ +## ADDED Requirements + +### Requirement: + + +Covers: + +#### Scenario: + +- **WHEN** +- **THEN** diff --git a/schemas/atd-sdlc/templates/tasks.md b/schemas/atd-sdlc/templates/tasks.md new file mode 100644 index 0000000000..a4a3c12889 --- /dev/null +++ b/schemas/atd-sdlc/templates/tasks.md @@ -0,0 +1,13 @@ +## 1. + + +- [ ] 1.1 +- [ ] 1.2 + +## F. Final group (mandatory — apply completes only when checked) + + +- [ ] F.1 Verify conformance to scenarios; note deviations +- [ ] F.2 Reconcile solution.md against implemented code: update as-built section, record deviations with reasons and evidence; verify: as-built section no longer says "Pending implementation" +- [ ] F.3 Publish reconciled solution.md to ; verify: +- [ ] F.4 Add idempotent Jira closure comment (summary + documentation links; re-run updates, never duplicates); verify: comment URL noted in solution.md Publication metadata diff --git a/schemas/atd-sdlc/templates/ticket.md b/schemas/atd-sdlc/templates/ticket.md new file mode 100644 index 0000000000..31c88a9f1c --- /dev/null +++ b/schemas/atd-sdlc/templates/ticket.md @@ -0,0 +1,35 @@ +# Ticket: + +## Sources + +- Jira: +- Confluence: +- Branch: + +## Problem Statement + + + +## Acceptance Criteria + + +- **AC-1**: +- **AC-2**: + +## Affected Systems + + + +## Edge Cases + +## Constraints + +## Out of Scope + +## Clarified Requirements + + + +## Triage Record + + diff --git a/skills/atd-change-triage/SKILL.md b/skills/atd-change-triage/SKILL.md new file mode 100644 index 0000000000..71afccc417 --- /dev/null +++ b/skills/atd-change-triage/SKILL.md @@ -0,0 +1,127 @@ +--- +name: atd-change-triage +description: Classify a Jira ticket against the ATD lite-eligibility table and create the change with the confirmed schema (atd-sdlc or atd-sdlc-lite). Use when starting work on a Jira ticket. +allowed-tools: Bash(openspec:*) +license: MIT +compatibility: Requires openspec CLI. +metadata: + author: openspec + version: "1.0" +--- + +Classify a Jira ticket as lite or full and create the change with the confirmed schema. + +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. + +**Input**: A Jira ticket key or URL (e.g. `ABC-1234`). If none was provided, ask for it. + +**Steps** + +1. **Read the ticket** + + Pull the Jira issue (and linked Confluence pages) via the Atlassian MCP. + If the MCP is unavailable, ask the developer to paste the ticket content. + Do NOT run the full intake/grilling here — that is the ticket artifact's job + after the change exists. + +2. **Bounded codebase preflight (mandatory before recommending lite)** + + Scoped to the ticket, lighter than an analysis document — only enough to + classify safely: + - Locate the owning component. + - Inspect the relevant entry points and call path. + - Identify existing tests or specifications covering the behavior. + - Check for API contract, data, security, dependency, integration, and + deployment impact. + +3. **Evaluate the eligibility decision table** (canonical list below; the fork + also maintains it in `docs/atd/lite-eligibility.md`) + + Eligibility conditions — ALL must pass for lite: + 1. Single repository and single component + 2. Small, localized file impact + 3. Restores existing intended behavior (no new behavior) + 4. Existing acceptance criteria, specification, or test already defines the behavior + 5. No API contract change + 6. No database/schema/data migration + 7. No authentication, authorization, security, privacy, or compliance impact + 8. No cross-service integration behavior change + 9. No new dependency + 10. No deployment or infrastructure change + 11. Straightforward automated regression test exists or is easy to add + 12. Trivial rollback + 13. No new functional or technical documentation needed (localized corrections to existing docs stay lite-eligible) + + Rules: + - Any condition that fails OR cannot be confidently evaluated from the + ticket or the inspected code → **full**. Uncertainty is never lite. + - Risk, never line count: a one-line change to an authorization condition, + SQL WHERE clause, or financial calculation routes **full** regardless of + size. + +4. **Present the recommendation and confirm (monotonic)** + + Show the recommendation WITH the specific condition evaluations that drove + it (quote failed/uncertain conditions verbatim). + - Recommendation is **lite**: the developer may confirm lite or strengthen + to full. + - Recommendation is **full**: full is mandatory. If the developer asks for + lite, decline and quote the failed or uncertain conditions. + +5. **Create the change and write the triage record** + + ```bash + openspec new change - --schema --json + ``` + + Change names are kebab-case: LOWERCASE the Jira key in the change name + (`ABC-1234` → `abc-1234-fix-export`). Keep the uppercase form only for + Jira display and lookups. + + Parse the JSON output and take `change.path` from it — NEVER assume the + change lives under the current repository's `openspec/changes/` (the CLI + can resolve another planning root or store). + + Write `triage.md` under that returned path containing: the recommendation, + each condition's evaluation, and the developer's confirmed choice. + + **NEVER create or modify `ticket.md`** — artifact completion is determined + by output-file existence; a partial ticket.md would mark the ticket artifact + complete and silently skip intake, completeness checking, grilling, and + write-back. The ticket artifact reads triage.md and folds the routing record + in when it runs. + +6. **Hand off** + + Tell the developer the change was created with schema `` and that + the next step is the `ticket` artifact (e.g. via the continue/apply + workflow). + +**triage.md format** + +```markdown +# Triage: + +**Recommendation:** atd-sdlc-lite | atd-sdlc +**Confirmed choice:** atd-sdlc-lite | atd-sdlc (developer: ) + +## Condition evaluations + +| Condition | Result | Evidence | +|-----------|--------|----------| +| Single repo/component | pass | | +| ... | pass / FAIL / UNCERTAIN | ... | + +## Escalations + + +``` + +**Guardrails** + +- Uncertainty always routes full. Never guess a condition to pass. +- Never weaken full → lite through confirmation; strengthening lite → full is allowed. +- Never write ticket.md or any artifact output file. +- Always write triage.md under the `--json`-returned change path. +- Quote condition evaluations — the record must let a reviewer audit the routing. diff --git a/src/core/profile-sync-drift.ts b/src/core/profile-sync-drift.ts index a876d6ce72..5727b86772 100644 --- a/src/core/profile-sync-drift.ts +++ b/src/core/profile-sync-drift.ts @@ -30,6 +30,7 @@ export const WORKFLOW_TO_SKILL_DIR: Record = { 'verify': 'openspec-verify-change', 'onboard': 'openspec-onboard', 'propose': 'openspec-propose', + 'atd-triage': 'atd-change-triage', }; function toKnownWorkflows(workflows: readonly string[]): WorkflowId[] { diff --git a/src/core/profiles.ts b/src/core/profiles.ts index acdc3ec953..798bd23652 100644 --- a/src/core/profiles.ts +++ b/src/core/profiles.ts @@ -11,7 +11,7 @@ import type { Profile } from './global-config.js'; * Core workflows included in the 'core' profile. * These provide the streamlined experience for new users. */ -export const CORE_WORKFLOWS = ['propose', 'explore', 'apply', 'update', 'sync', 'archive'] as const; +export const CORE_WORKFLOWS = ['propose', 'explore', 'apply', 'update', 'sync', 'archive', 'atd-triage'] as const; /** * All available workflows in the system. @@ -29,6 +29,7 @@ export const ALL_WORKFLOWS = [ 'bulk-archive', 'verify', 'onboard', + 'atd-triage', ] as const; export type WorkflowId = (typeof ALL_WORKFLOWS)[number]; diff --git a/src/core/shared/skill-generation.ts b/src/core/shared/skill-generation.ts index f671b4de73..71e773bfb2 100644 --- a/src/core/shared/skill-generation.ts +++ b/src/core/shared/skill-generation.ts @@ -17,6 +17,8 @@ import { getVerifyChangeSkillTemplate, getOnboardSkillTemplate, getOpsxProposeSkillTemplate, + getAtdTriageSkillTemplate, + getOpsxAtdTriageCommandTemplate, getOpsxExploreCommandTemplate, getOpsxNewCommandTemplate, getOpsxContinueCommandTemplate, @@ -70,6 +72,7 @@ export function getSkillTemplates(workflowFilter?: readonly string[]): SkillTemp { template: getVerifyChangeSkillTemplate(), dirName: 'openspec-verify-change', workflowId: 'verify' }, { template: getOnboardSkillTemplate(), dirName: 'openspec-onboard', workflowId: 'onboard' }, { template: getOpsxProposeSkillTemplate(), dirName: 'openspec-propose', workflowId: 'propose' }, + { template: getAtdTriageSkillTemplate(), dirName: 'atd-change-triage', workflowId: 'atd-triage' }, ]; if (!workflowFilter) return all; @@ -97,6 +100,7 @@ export function getCommandTemplates(workflowFilter?: readonly string[]): Command { template: getOpsxVerifyCommandTemplate(), id: 'verify' }, { template: getOpsxOnboardCommandTemplate(), id: 'onboard' }, { template: getOpsxProposeCommandTemplate(), id: 'propose' }, + { template: getOpsxAtdTriageCommandTemplate(), id: 'atd-triage' }, ]; if (!workflowFilter) return all; diff --git a/src/core/shared/tool-detection.ts b/src/core/shared/tool-detection.ts index 30622209dc..5066324d19 100644 --- a/src/core/shared/tool-detection.ts +++ b/src/core/shared/tool-detection.ts @@ -24,6 +24,7 @@ export const SKILL_NAMES = [ 'openspec-verify-change', 'openspec-onboard', 'openspec-propose', + 'atd-change-triage', ] as const; export type SkillName = (typeof SKILL_NAMES)[number]; @@ -44,6 +45,7 @@ export const COMMAND_IDS = [ 'verify', 'onboard', 'propose', + 'atd-triage', ] as const; export type CommandId = (typeof COMMAND_IDS)[number]; diff --git a/src/core/templates/skill-templates.ts b/src/core/templates/skill-templates.ts index 598fcc4465..5558e098ce 100644 --- a/src/core/templates/skill-templates.ts +++ b/src/core/templates/skill-templates.ts @@ -19,3 +19,4 @@ export { getVerifyChangeSkillTemplate, getOpsxVerifyCommandTemplate } from './wo export { getOnboardSkillTemplate, getOpsxOnboardCommandTemplate } from './workflows/onboard.js'; export { getOpsxProposeSkillTemplate, getOpsxProposeCommandTemplate } from './workflows/propose.js'; export { getFeedbackSkillTemplate } from './workflows/feedback.js'; +export { getAtdTriageSkillTemplate, getOpsxAtdTriageCommandTemplate } from './workflows/atd-triage.js'; diff --git a/src/core/templates/workflows/atd-triage.ts b/src/core/templates/workflows/atd-triage.ts new file mode 100644 index 0000000000..96c9fe851e --- /dev/null +++ b/src/core/templates/workflows/atd-triage.ts @@ -0,0 +1,148 @@ +/** + * ATD change-triage workflow templates (skill + slash command). + * + * Entry point for the ATD two-schema model: classifies a Jira ticket against + * the lite-eligibility decision table and creates the change with the + * confirmed schema (atd-sdlc or atd-sdlc-lite). + */ +import type { SkillTemplate, CommandTemplate } from '../types.js'; +import { STORE_SELECTION_GUIDANCE } from './store-selection.js'; + +const TRIAGE_INSTRUCTIONS = `Classify a Jira ticket as lite or full and create the change with the confirmed schema. + +${STORE_SELECTION_GUIDANCE} + +**Input**: A Jira ticket key or URL (e.g. \`ABC-1234\`). If none was provided, ask for it. + +**Steps** + +1. **Read the ticket** + + Pull the Jira issue (and linked Confluence pages) via the Atlassian MCP. + If the MCP is unavailable, ask the developer to paste the ticket content. + Do NOT run the full intake/grilling here — that is the ticket artifact's job + after the change exists. + +2. **Bounded codebase preflight (mandatory before recommending lite)** + + Scoped to the ticket, lighter than an analysis document — only enough to + classify safely: + - Locate the owning component. + - Inspect the relevant entry points and call path. + - Identify existing tests or specifications covering the behavior. + - Check for API contract, data, security, dependency, integration, and + deployment impact. + +3. **Evaluate the eligibility decision table** (canonical list below; the fork + also maintains it in \`docs/atd/lite-eligibility.md\`) + + Eligibility conditions — ALL must pass for lite: + 1. Single repository and single component + 2. Small, localized file impact + 3. Restores existing intended behavior (no new behavior) + 4. Existing acceptance criteria, specification, or test already defines the behavior + 5. No API contract change + 6. No database/schema/data migration + 7. No authentication, authorization, security, privacy, or compliance impact + 8. No cross-service integration behavior change + 9. No new dependency + 10. No deployment or infrastructure change + 11. Straightforward automated regression test exists or is easy to add + 12. Trivial rollback + 13. No new functional or technical documentation needed (localized corrections to existing docs stay lite-eligible) + + Rules: + - Any condition that fails OR cannot be confidently evaluated from the + ticket or the inspected code → **full**. Uncertainty is never lite. + - Risk, never line count: a one-line change to an authorization condition, + SQL WHERE clause, or financial calculation routes **full** regardless of + size. + +4. **Present the recommendation and confirm (monotonic)** + + Show the recommendation WITH the specific condition evaluations that drove + it (quote failed/uncertain conditions verbatim). + - Recommendation is **lite**: the developer may confirm lite or strengthen + to full. + - Recommendation is **full**: full is mandatory. If the developer asks for + lite, decline and quote the failed or uncertain conditions. + +5. **Create the change and write the triage record** + + \`\`\`bash + openspec new change - --schema --json + \`\`\` + + Change names are kebab-case: LOWERCASE the Jira key in the change name + (\`ABC-1234\` → \`abc-1234-fix-export\`). Keep the uppercase form only for + Jira display and lookups. + + Parse the JSON output and take \`change.path\` from it — NEVER assume the + change lives under the current repository's \`openspec/changes/\` (the CLI + can resolve another planning root or store). + + Write \`triage.md\` under that returned path containing: the recommendation, + each condition's evaluation, and the developer's confirmed choice. + + **NEVER create or modify \`ticket.md\`** — artifact completion is determined + by output-file existence; a partial ticket.md would mark the ticket artifact + complete and silently skip intake, completeness checking, grilling, and + write-back. The ticket artifact reads triage.md and folds the routing record + in when it runs. + +6. **Hand off** + + Tell the developer the change was created with schema \`\` and that + the next step is the \`ticket\` artifact (e.g. via the continue/apply + workflow). + +**triage.md format** + +\`\`\`markdown +# Triage: + +**Recommendation:** atd-sdlc-lite | atd-sdlc +**Confirmed choice:** atd-sdlc-lite | atd-sdlc (developer: ) + +## Condition evaluations + +| Condition | Result | Evidence | +|-----------|--------|----------| +| Single repo/component | pass | | +| ... | pass / FAIL / UNCERTAIN | ... | + +## Escalations + + +\`\`\` + +**Guardrails** + +- Uncertainty always routes full. Never guess a condition to pass. +- Never weaken full → lite through confirmation; strengthening lite → full is allowed. +- Never write ticket.md or any artifact output file. +- Always write triage.md under the \`--json\`-returned change path. +- Quote condition evaluations — the record must let a reviewer audit the routing.`; + +export function getAtdTriageSkillTemplate(): SkillTemplate { + return { + name: 'atd-change-triage', + description: + 'Classify a Jira ticket against the ATD lite-eligibility table and create the change with the confirmed schema (atd-sdlc or atd-sdlc-lite). Use when starting work on a Jira ticket.', + instructions: TRIAGE_INSTRUCTIONS, + license: 'MIT', + compatibility: 'Requires openspec CLI.', + metadata: { author: 'openspec', version: '1.0' }, + }; +} + +export function getOpsxAtdTriageCommandTemplate(): CommandTemplate { + return { + name: 'atd-triage', + description: 'Triage a Jira ticket to the lite or full ATD schema and create the change', + category: 'Workflow', + tags: ['workflow', 'atd', 'triage'], + content: TRIAGE_INSTRUCTIONS, + }; +} diff --git a/test/commands/config-profile.test.ts b/test/commands/config-profile.test.ts index ab18e4e6b7..31e7033f17 100644 --- a/test/commands/config-profile.test.ts +++ b/test/commands/config-profile.test.ts @@ -69,7 +69,7 @@ describe('deriveProfileFromWorkflowSelection', () => { it('returns core when selection has exactly core workflows in different order', async () => { const { deriveProfileFromWorkflowSelection } = await import('../../src/commands/config.js'); - expect(deriveProfileFromWorkflowSelection(['archive', 'sync', 'update', 'apply', 'explore', 'propose'])).toBe('core'); + expect(deriveProfileFromWorkflowSelection(['archive', 'sync', 'update', 'apply', 'explore', 'propose', 'atd-triage'])).toBe('core'); }); }); @@ -98,6 +98,7 @@ describe('config profile interactive flow', () => { 'openspec-update-change', 'openspec-sync-specs', 'openspec-archive-change', + 'atd-change-triage', ]; for (const dirName of coreSkillDirs) { const skillPath = path.join(projectDir, '.claude', 'skills', dirName, 'SKILL.md'); @@ -105,7 +106,7 @@ describe('config profile interactive flow', () => { fs.writeFileSync(skillPath, `name: ${dirName}\n`, 'utf-8'); } - const coreCommands = ['propose', 'explore', 'apply', 'update', 'sync', 'archive']; + const coreCommands = ['propose', 'explore', 'apply', 'update', 'sync', 'archive', 'atd-triage']; for (const commandId of coreCommands) { const commandPath = path.join(projectDir, '.claude', 'commands', 'opsx', `${commandId}.md`); fs.mkdirSync(path.dirname(commandPath), { recursive: true }); @@ -427,7 +428,7 @@ describe('config profile interactive flow', () => { const config = getGlobalConfig(); expect(config.profile).toBe('core'); expect(config.delivery).toBe('skills'); - expect(config.workflows).toEqual(['propose', 'explore', 'apply', 'update', 'sync', 'archive']); + expect(config.workflows).toEqual(['propose', 'explore', 'apply', 'update', 'sync', 'archive', 'atd-triage']); expect(select).not.toHaveBeenCalled(); expect(checkbox).not.toHaveBeenCalled(); expect(confirm).not.toHaveBeenCalled(); diff --git a/test/commands/config.test.ts b/test/commands/config.test.ts index 1e4f7e73d0..6ad85b2af2 100644 --- a/test/commands/config.test.ts +++ b/test/commands/config.test.ts @@ -274,7 +274,7 @@ describe('config profile command', () => { const result = getGlobalConfig(); expect(result.profile).toBe('core'); expect(result.delivery).toBe('skills'); // preserved - expect(result.workflows).toEqual(['propose', 'explore', 'apply', 'update', 'sync', 'archive']); + expect(result.workflows).toEqual(['propose', 'explore', 'apply', 'update', 'sync', 'archive', 'atd-triage']); }); it('custom workflow selection should set profile to custom', async () => { diff --git a/test/core/artifact-graph/atd-sdlc-lite-schema.test.ts b/test/core/artifact-graph/atd-sdlc-lite-schema.test.ts new file mode 100644 index 0000000000..402d977ac2 --- /dev/null +++ b/test/core/artifact-graph/atd-sdlc-lite-schema.test.ts @@ -0,0 +1,252 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import * as os from 'node:os'; +import { resolveSchema } from '../../../src/core/artifact-graph/resolver.js'; +import { ArtifactGraph } from '../../../src/core/artifact-graph/graph.js'; +import { detectCompleted } from '../../../src/core/artifact-graph/state.js'; +import { loadTemplate, loadChangeContext } from '../../../src/core/artifact-graph/instruction-loader.js'; + +const full = resolveSchema('atd-sdlc'); +const lite = resolveSchema('atd-sdlc-lite'); + +const instructionOf = (schema: typeof full, id: string) => + schema.artifacts.find(a => a.id === id)?.instruction ?? ''; + +/** + * Extracts a shared rule block from an instruction: from the start marker + * up to (excluding) the next bold `**Header**` line, or to the end. + */ +function extractBlock(instruction: string, startMarker: string): string { + const start = instruction.indexOf(startMarker); + expect(start, `marker not found: ${startMarker}`).toBeGreaterThanOrEqual(0); + const rest = instruction.slice(start + startMarker.length); + const next = rest.search(/\n\s*\*\*/); + const block = startMarker + (next === -1 ? rest : rest.slice(0, next)); + return block.trim(); +} + +describe('atd-sdlc-lite built-in schema', () => { + it('resolves with the three-artifact pipeline ticket → analysis → tasks', () => { + expect(lite.name).toBe('atd-sdlc-lite'); + expect(lite.artifacts.map(a => a.id)).toEqual(['ticket', 'analysis', 'tasks']); + + const requires = Object.fromEntries(lite.artifacts.map(a => [a.id, a.requires])); + expect(requires['ticket']).toEqual([]); + expect(requires['analysis']).toEqual(['ticket']); + expect(requires['tasks']).toEqual(['analysis']); + + expect(lite.apply?.requires).toEqual(['tasks']); + expect(lite.apply?.tracks).toBe('tasks.md'); + }); + + it('resolves every template referenced by the schema', () => { + for (const artifact of lite.artifacts) { + expect(loadTemplate('atd-sdlc-lite', artifact.template).length).toBeGreaterThan(0); + } + }); + + describe('instruction parity with atd-sdlc (shared rule blocks verbatim)', () => { + const sharedTicketBlocks = [ + '**Intake:**', + '**Branch alignment (advisory):**', + '**Completeness checklist (gate):**', + '**Grilling protocol (when any checklist item is missing):**', + '**Jira write-back (confirmed, idempotent):**', + ]; + + it.each(sharedTicketBlocks)('ticket block %s matches', marker => { + const fullBlock = extractBlock(instructionOf(full, 'ticket'), marker); + expect(instructionOf(lite, 'ticket')).toContain(fullBlock); + }); + + it.each(['**Code is the source of truth.**', '**Evidence:**'])( + 'analysis block %s matches', + marker => { + const fullBlock = extractBlock(instructionOf(full, 'analysis'), marker); + expect(instructionOf(lite, 'analysis')).toContain(fullBlock); + } + ); + + it('both schemas carry the identical explicit stack mapping in tasks and apply', () => { + for (const text of [ + instructionOf(full, 'tasks'), + instructionOf(lite, 'tasks'), + full.apply?.instruction ?? '', + lite.apply?.instruction ?? '', + ]) { + expect(text).toContain('python → python-service-standards'); + expect(text).toContain('spring-boot → spring-boot-standards'); + expect(text).toContain('oracle-ebs → oracle-ebs-plsql-standards'); + expect(text).toContain('angular → angular-standards'); + } + }); + }); + + describe('template compatibility with the full schema contract', () => { + it('lite ticket template carries every mandatory full-contract field', () => { + const t = loadTemplate('atd-sdlc-lite', 'ticket.md'); + for (const heading of [ + '## Sources', + '## Problem Statement', + '## Acceptance Criteria', + '## Affected Systems', + '## Edge Cases', + '## Constraints', + '## Out of Scope', + '## Clarified Requirements', + '## Triage Record', + ]) { + expect(t).toContain(heading); + } + // lite-specific addition on top of the full contract + expect(t).toContain('## Restored Behavior'); + }); + + it('lite analysis template carries SHA and affected-stacks fields', () => { + const t = loadTemplate('atd-sdlc-lite', 'analysis.md'); + expect(t).toContain('**Commit SHA:**'); + expect(t).toContain('**Affected stacks:**'); + }); + }); + + describe('escalation via .openspec.yaml schema switch', () => { + let changeDir: string; + + beforeEach(() => { + changeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'atd-lite-escalation-')); + }); + + afterEach(() => { + fs.rmSync(changeDir, { recursive: true, force: true }); + }); + + function seedLiteChange(): void { + fs.writeFileSync(path.join(changeDir, '.openspec.yaml'), 'schema: atd-sdlc-lite\n'); + fs.writeFileSync(path.join(changeDir, 'ticket.md'), '# Ticket'); + fs.writeFileSync(path.join(changeDir, 'analysis.md'), '# Impact Assessment'); + } + + function escalate(): void { + fs.writeFileSync(path.join(changeDir, '.openspec.yaml'), 'schema: atd-sdlc\n'); + } + + it('pre-tasks escalation: ticket/analysis done, specs/design ready, solution-doc/tasks blocked, apply blocked', () => { + seedLiteChange(); + escalate(); + + const ctx = loadChangeContext(os.tmpdir(), path.basename(changeDir), undefined, { changeDir }); + expect(ctx.schemaName).toBe('atd-sdlc'); + expect(ctx.completed.has('ticket')).toBe(true); + expect(ctx.completed.has('analysis')).toBe(true); + expect(ctx.graph.getNextArtifacts(ctx.completed).sort()).toEqual(['design', 'specs']); + + const blocked = ctx.graph.getBlocked(ctx.completed); + expect(blocked['solution-doc']).toEqual(['design', 'specs']); + expect(blocked['tasks']).toEqual(['solution-doc']); + // apply requires the tasks artifact, which is not complete + expect(ctx.completed.has('tasks')).toBe(false); + }); + + it('late escalation: tasks.lite.md preserved, tracked tasks.md absent, apply blocked until a full task list exists', () => { + seedLiteChange(); + fs.writeFileSync(path.join(changeDir, 'tasks.md'), '## 1. Work\n\n- [x] 1.1 partial\n- [ ] 1.2 pending\n'); + + // late-escalation procedure from the lite apply instruction + fs.renameSync(path.join(changeDir, 'tasks.md'), path.join(changeDir, 'tasks.lite.md')); + escalate(); + + expect(fs.existsSync(path.join(changeDir, 'tasks.lite.md'))).toBe(true); + expect(fs.existsSync(path.join(changeDir, 'tasks.md'))).toBe(false); + + const ctx = loadChangeContext(os.tmpdir(), path.basename(changeDir), undefined, { changeDir }); + expect(ctx.schemaName).toBe('atd-sdlc'); + // the preserved lite checklist must NOT satisfy the full tasks artifact + expect(ctx.completed.has('tasks')).toBe(false); + expect(ctx.graph.getNextArtifacts(ctx.completed).sort()).toEqual(['design', 'specs']); + expect(ctx.graph.getBlocked(ctx.completed)['tasks']).toEqual(['solution-doc']); + }); + + it('lite ticket gate enforces semantic validity, not just structural completeness', () => { + const ticket = instructionOf(lite, 'ticket'); + expect(ticket).toContain('Structural completeness is not'); + expect(ticket).toContain('no FAIL, no UNCERTAIN'); + expect(ticket).toContain('recommendation is `atd-sdlc-lite`'); + expect(ticket).toContain('confirmed choice is `atd-sdlc-lite`'); + expect(ticket).toContain('missing, empty, or structurally incomplete'); + expect(ticket).toContain('all-pass triage record is never allowed'); + // the packaged schema never points at unpackaged repository docs + expect(ticket).not.toContain('docs/atd/'); + }); + + it('the 13-condition list is identical (normalized, ordered) across schema, triage workflow, and docs', async () => { + const CANONICAL = [ + 'Single repository and single component', + 'Small, localized file impact', + 'Restores existing intended behavior (no new behavior)', + 'Existing acceptance criteria, specification, or test already defines the behavior', + 'No API contract change', + 'No database/schema/data migration', + 'No authentication, authorization, security, privacy, or compliance impact', + 'No cross-service integration behavior change', + 'No new dependency', + 'No deployment or infrastructure change', + 'Straightforward automated regression test exists or is easy to add', + 'Trivial rollback', + 'No new functional or technical documentation needed (localized corrections to existing docs stay lite-eligible)', + ].map(normalize); + + function normalize(s: string): string { + return s.toLowerCase().replace(/[`*|]/g, '').replace(/\s+/g, ' ').trim(); + } + + function extractNumberedList(text: string, startMarker: string, endMarker: string): string[] { + const start = text.indexOf(startMarker); + expect(start, `marker not found: ${startMarker}`).toBeGreaterThanOrEqual(0); + const endIdx = text.indexOf(endMarker, start); + const section = text.slice(start, endIdx === -1 ? undefined : endIdx); + const items: string[] = []; + const re = /(?:^|\n)\s*\d{1,2}\.\s+([\s\S]*?)(?=\n\s*\d{1,2}\.\s|$)/g; + for (const m of section.matchAll(re)) items.push(normalize(m[1])); + return items; + } + + // Surface 1: packaged lite schema (ticket gate) + const schemaList = extractNumberedList( + instructionOf(lite, 'ticket'), + 'Eligibility conditions', + '**Branch alignment' + ); + expect(schemaList).toEqual(CANONICAL); + + // Surface 2: triage workflow instructions (both delivery paths share the constant) + const { getAtdTriageSkillTemplate } = await import('../../../src/core/templates/workflows/atd-triage.js'); + const triageInstructions = getAtdTriageSkillTemplate().instructions; + const triageList = extractNumberedList(triageInstructions, 'Eligibility conditions', 'Rules:'); + expect(triageList).toEqual(CANONICAL); + + // Surface 3: docs/atd/lite-eligibility.md table + const docText = fs.readFileSync( + path.join(__dirname, '../../../docs/atd/lite-eligibility.md'), + 'utf-8' + ); + const docList = [...docText.matchAll(/^\|\s*\d+\s*\|\s*(.+?)\s*\|\s*$/gm)].map(m => normalize(m[1])); + expect(docList).toEqual(CANONICAL); + + // Risk examples: same three classes on every surface (normalized) + for (const surface of [instructionOf(lite, 'ticket'), triageInstructions, docText]) { + const n = normalize(surface); + for (const example of ['authorization condition', 'where clause', 'financial calculation']) { + expect(n, example).toContain(example); + } + } + }); + + it('lite instructions document both escalation procedures', () => { + expect(instructionOf(lite, 'analysis')).toContain('`.openspec.yaml` metadata to `schema: atd-sdlc`'); + expect(lite.apply?.instruction).toContain('tasks.lite.md'); + expect(lite.apply?.instruction).toContain('Late escalation'); + expect(instructionOf(lite, 'analysis')).toContain('Downgrading a full change to lite is not supported'); + }); + }); +}); diff --git a/test/core/artifact-graph/atd-sdlc-schema.test.ts b/test/core/artifact-graph/atd-sdlc-schema.test.ts new file mode 100644 index 0000000000..fd59ca2b9f --- /dev/null +++ b/test/core/artifact-graph/atd-sdlc-schema.test.ts @@ -0,0 +1,194 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import * as os from 'node:os'; +import { resolveSchema } from '../../../src/core/artifact-graph/resolver.js'; +import { ArtifactGraph } from '../../../src/core/artifact-graph/graph.js'; +import { detectCompleted } from '../../../src/core/artifact-graph/state.js'; +import { loadTemplate, loadChangeContext, generateInstructions } from '../../../src/core/artifact-graph/instruction-loader.js'; + +describe('atd-sdlc built-in schema', () => { + it('resolves through the built-in tier with the six-artifact pipeline', () => { + const schema = resolveSchema('atd-sdlc'); + + expect(schema.name).toBe('atd-sdlc'); + expect(schema.version).toBe(1); + expect(schema.artifacts.map(a => a.id)).toEqual([ + 'ticket', + 'analysis', + 'specs', + 'design', + 'solution-doc', + 'tasks', + ]); + }); + + it('encodes the dependency chain ticket → analysis → (specs, design) → solution-doc → tasks', () => { + const schema = resolveSchema('atd-sdlc'); + const requires = Object.fromEntries(schema.artifacts.map(a => [a.id, a.requires])); + + expect(requires['ticket']).toEqual([]); + expect(requires['analysis']).toEqual(['ticket']); + expect(requires['specs']).toEqual(['analysis']); + expect(requires['design']).toEqual(['analysis']); + expect(requires['solution-doc']).toEqual(['specs', 'design']); + expect(requires['tasks']).toEqual(['solution-doc']); + }); + + it('tracks apply via tasks.md gated on the tasks artifact', () => { + const schema = resolveSchema('atd-sdlc'); + + expect(schema.apply?.requires).toEqual(['tasks']); + expect(schema.apply?.tracks).toBe('tasks.md'); + expect(schema.apply?.instruction).toContain('atd-standards'); + }); + + it('resolves every template referenced by the schema', () => { + const schema = resolveSchema('atd-sdlc'); + + for (const artifact of schema.artifacts) { + const template = loadTemplate('atd-sdlc', artifact.template); + expect(template.length).toBeGreaterThan(0); + } + }); + + describe('tasks-requires-solution-doc gate', () => { + let changeDir: string; + + beforeEach(() => { + changeDir = fs.mkdtempSync(path.join(os.tmpdir(), 'atd-sdlc-gate-')); + }); + + afterEach(() => { + fs.rmSync(changeDir, { recursive: true, force: true }); + }); + + it('blocks tasks until solution.md exists', () => { + const graph = ArtifactGraph.fromSchema(resolveSchema('atd-sdlc')); + + fs.writeFileSync(path.join(changeDir, 'ticket.md'), '# Ticket'); + fs.writeFileSync(path.join(changeDir, 'analysis.md'), '# Analysis'); + fs.mkdirSync(path.join(changeDir, 'specs', 'cap'), { recursive: true }); + fs.writeFileSync(path.join(changeDir, 'specs', 'cap', 'spec.md'), '## ADDED Requirements'); + fs.writeFileSync(path.join(changeDir, 'design.md'), '# Design'); + + let completed = detectCompleted(graph, changeDir); + expect(completed.has('solution-doc')).toBe(false); + expect(graph.getBlocked(completed)['tasks']).toEqual(['solution-doc']); + expect(graph.getNextArtifacts(completed)).toEqual(['solution-doc']); + + fs.writeFileSync(path.join(changeDir, 'solution.md'), '# Solution'); + completed = detectCompleted(graph, changeDir); + expect(completed.has('solution-doc')).toBe(true); + expect(graph.getNextArtifacts(completed)).toEqual(['tasks']); + }); + }); + + describe('instruction content contracts', () => { + const schema = resolveSchema('atd-sdlc'); + const instruction = (id: string) => + schema.artifacts.find(a => a.id === id)?.instruction ?? ''; + + it('ticket carries intake, grilling, write-back, and branch-alignment rules', () => { + const ticket = instruction('ticket'); + expect(ticket).toContain('Atlassian MCP'); + expect(ticket).toContain('paste the ticket'); + expect(ticket).toContain('AC-1'); + expect(ticket).toContain('EXACTLY ONE question at a time'); + expect(ticket).toContain('recommended answer'); + expect(ticket).toContain('managed section'); + expect(ticket).toContain('rules: ticket:'); + expect(ticket).toContain('triage.md'); + // branch alignment is a suggestion, never an enforcement + expect(ticket).toContain('suggestion only'); + expect(ticket).toContain('never create or switch branches without explicit developer confirmation'); + }); + + it('analysis carries code-as-truth, citation, stack, and token-efficiency rules', () => { + const analysis = instruction('analysis'); + expect(analysis).toContain('Code is the source of truth'); + expect(analysis).toContain('commit SHA'); + expect(analysis).toContain('file:line'); + expect(analysis).toContain('{python, spring-boot, oracle-ebs, angular}'); + expect(analysis).toContain('rules: analysis:'); + expect(analysis).toContain('Never sweep whole directories'); + }); + + it('specs mandate AC traceability', () => { + const specs = instruction('specs'); + expect(specs).toContain('Covers: AC-n'); + expect(specs).toContain('scope invention'); + }); + + it('design and solution-doc carry anti-slop rules', () => { + expect(instruction('design')).toContain('Never draw a diagram'); + expect(instruction('solution-doc')).toContain('never filled with boilerplate'); + expect(instruction('solution-doc')).toContain('Pending implementation'); + }); + + it('tasks carry the mandatory final group with the explicit standards mapping', () => { + const tasks = instruction('tasks'); + expect(tasks).toContain('Mandatory final task group'); + expect(tasks).toContain('python → python-service-standards'); + expect(tasks).toContain('spring-boot → spring-boot-standards'); + expect(tasks).toContain('oracle-ebs → oracle-ebs-plsql-standards'); + expect(tasks).toContain('angular → angular-standards'); + expect(tasks).toContain('rules: tasks:'); + expect(tasks).toContain('idempotent Jira closure comment'); + }); + + it('apply instruction mandates the standards fetch before implementing', () => { + const apply = schema.apply?.instruction ?? ''; + expect(apply).toContain('Before implementing ANY task'); + expect(apply).toContain('python → python-service-standards'); + expect(apply).toContain('angular → angular-standards'); + }); + }); + + describe('instruction assembly with project config and references', () => { + let projectRoot: string; + + beforeEach(() => { + projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'atd-sdlc-assembly-')); + const changeDir = path.join(projectRoot, 'openspec', 'changes', 'abc-1-test'); + fs.mkdirSync(changeDir, { recursive: true }); + fs.writeFileSync(path.join(changeDir, '.openspec.yaml'), 'schema: atd-sdlc\n'); + }); + + afterEach(() => { + fs.rmSync(projectRoot, { recursive: true, force: true }); + }); + + it('rules: tasks: from openspec/config.yaml reaches the generated tasks instructions', () => { + fs.writeFileSync( + path.join(projectRoot, 'openspec', 'config.yaml'), + 'schema: atd-sdlc\nrules:\n tasks:\n - "Documentation destination: repo"\n' + ); + + const ctx = loadChangeContext(projectRoot, 'abc-1-test'); + const instructions = generateInstructions(ctx, 'tasks', projectRoot); + + expect(instructions.rules).toEqual(['Documentation destination: repo']); + expect(instructions.instruction).toContain('rules: tasks:'); + }); + + it('a references index entry for atd-standards is carried into the generated instructions', () => { + const ctx = loadChangeContext(projectRoot, 'abc-1-test', 'atd-sdlc'); + const instructions = generateInstructions(ctx, 'ticket', projectRoot, { + references: [ + { + store_id: 'atd-standards', + root: '/tmp/atd-standards', + specs: [{ id: 'angular-standards', summary: 'ATD Angular coding standards' }], + fetch: 'openspec show --type spec --store atd-standards', + status: [], + }, + ], + }); + + expect(instructions.references).toHaveLength(1); + expect(instructions.references?.[0].store_id).toBe('atd-standards'); + expect(instructions.references?.[0].specs?.[0].id).toBe('angular-standards'); + }); + }); +}); diff --git a/test/core/atd-triage-workflow.test.ts b/test/core/atd-triage-workflow.test.ts new file mode 100644 index 0000000000..bae3b47210 --- /dev/null +++ b/test/core/atd-triage-workflow.test.ts @@ -0,0 +1,200 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { InitCommand } from '../../src/core/init.js'; +import { FileSystemUtils } from '../../src/utils/file-system.js'; +import type { GlobalConfig } from '../../src/core/global-config.js'; +import path from 'path'; +import fs from 'fs/promises'; +import os from 'os'; +import { randomUUID } from 'crypto'; +import { CORE_WORKFLOWS, ALL_WORKFLOWS } from '../../src/core/profiles.js'; +import { WORKFLOW_TO_SKILL_DIR } from '../../src/core/profile-sync-drift.js'; +import { getSkillTemplates, getCommandTemplates } from '../../src/core/shared/skill-generation.js'; +import { getAtdTriageSkillTemplate, getOpsxAtdTriageCommandTemplate } from '../../src/core/templates/workflows/atd-triage.js'; + +const mockState = { + config: { featureFlags: {}, profile: 'core', delivery: 'both' } as GlobalConfig, +}; + +vi.mock('../../src/core/global-config.js', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + getGlobalConfig: () => ({ ...mockState.config }), + }; +}); + +describe('atd-triage workflow delivery', () => { + it('is a core workflow with a skill-dir mapping', () => { + expect(CORE_WORKFLOWS).toContain('atd-triage'); + expect(ALL_WORKFLOWS).toContain('atd-triage'); + expect(WORKFLOW_TO_SKILL_DIR['atd-triage']).toBe('atd-change-triage'); + }); + + it('is registered in both generation registries', () => { + const skillEntry = getSkillTemplates(['atd-triage']); + expect(skillEntry).toHaveLength(1); + expect(skillEntry[0].dirName).toBe('atd-change-triage'); + expect(skillEntry[0].template.name).toBe('atd-change-triage'); + + const commandEntry = getCommandTemplates(['atd-triage']); + expect(commandEntry).toHaveLength(1); + expect(commandEntry[0].template.name).toBe('atd-triage'); + }); + + describe('instruction content contracts (both delivery paths)', () => { + const surfaces = [ + ['skill', getAtdTriageSkillTemplate().instructions], + ['command', getOpsxAtdTriageCommandTemplate().content], + ] as const; + + it.each(surfaces)('%s carries the sidecar rules', (_name, text) => { + expect(text).toContain('--schema --json'); + expect(text).toContain('`change.path`'); + expect(text).toContain('NEVER assume the'); + expect(text).toContain('NEVER create or modify `ticket.md`'); + expect(text).toContain('triage.md'); + }); + + it.each(surfaces)('%s enforces monotonic confirmation and uncertainty→full', (_name, text) => { + expect(text).toContain('full is mandatory'); + expect(text).toContain('decline and quote the failed or uncertain conditions'); + expect(text).toContain('Uncertainty is never lite'); + expect(text).toContain('strengthen'); + }); + + it.each(surfaces)('%s carries risk-not-linecount and the documentation rule', (_name, text) => { + expect(text).toContain('Risk, never line count'); + expect(text).toContain('authorization condition'); + expect(text).toContain('SQL WHERE clause'); + expect(text).toContain('financial calculation'); + expect(text).toContain('localized corrections'); + expect(text).toContain('stay lite-eligible'); + expect(text).toContain('No new functional or technical documentation'); + }); + + it.each(surfaces)('%s requires the bounded preflight', (_name, text) => { + expect(text).toContain('Bounded codebase preflight'); + expect(text).toContain('owning component'); + expect(text).toContain('entry points and call path'); + expect(text).toContain('lighter than an analysis document'); + }); + + it.each(surfaces)('%s documents the escalation append format', (_name, text) => { + expect(text).toContain('## Escalations'); + expect(text).toContain('trigger, previous schema, new schema, reason'); + }); + }); + + describe('init installs triage by default (core profile, no selection)', () => { + let testDir: string; + + beforeEach(async () => { + mockState.config = { featureFlags: {}, profile: 'core', delivery: 'both' }; + testDir = path.join(os.tmpdir(), `openspec-atd-triage-init-${randomUUID()}`); + await fs.mkdir(testDir, { recursive: true }); + }); + + afterEach(async () => { + await fs.rm(testDir, { recursive: true, force: true }); + }); + + it('creates skill and command artifacts for the claude tool', async () => { + const initCommand = new InitCommand({ tools: 'claude', force: true }); + await initCommand.execute(testDir); + + expect(await FileSystemUtils.fileExists( + path.join(testDir, '.claude', 'skills', 'atd-change-triage', 'SKILL.md') + )).toBe(true); + expect(await FileSystemUtils.fileExists( + path.join(testDir, '.claude', 'commands', 'opsx', 'atd-triage.md') + )).toBe(true); + }); + + it('respects skills-only delivery (skill yes, command no)', async () => { + mockState.config = { featureFlags: {}, profile: 'core', delivery: 'skills' }; + const initCommand = new InitCommand({ tools: 'claude', force: true }); + await initCommand.execute(testDir); + + expect(await FileSystemUtils.fileExists( + path.join(testDir, '.claude', 'skills', 'atd-change-triage', 'SKILL.md') + )).toBe(true); + expect(await FileSystemUtils.fileExists( + path.join(testDir, '.claude', 'commands', 'opsx', 'atd-triage.md') + )).toBe(false); + }); + + it('respects commands-only delivery (command yes, skill no)', async () => { + mockState.config = { featureFlags: {}, profile: 'core', delivery: 'commands' }; + const initCommand = new InitCommand({ tools: 'claude', force: true }); + await initCommand.execute(testDir); + + expect(await FileSystemUtils.fileExists( + path.join(testDir, '.claude', 'commands', 'opsx', 'atd-triage.md') + )).toBe(true); + expect(await FileSystemUtils.fileExists( + path.join(testDir, '.claude', 'skills', 'atd-change-triage', 'SKILL.md') + )).toBe(false); + }); + }); + + describe('routing record handling in both schemas', () => { + const flat = (s: string) => s.replace(/\s+/g, ' '); + + it('both ticket instructions fold the triage routing record when present', async () => { + const { resolveSchema } = await import('../../src/core/artifact-graph/resolver.js'); + for (const schemaName of ['atd-sdlc', 'atd-sdlc-lite']) { + const schema = resolveSchema(schemaName); + const ticket = flat(schema.artifacts.find(a => a.id === 'ticket')?.instruction ?? ''); + expect(ticket, schemaName).toContain('routing record (recommendation, condition evaluations, confirmed choice)'); + } + }); + + it('full schema proceeds normally without a sidecar; lite treats it as a mandatory gate', async () => { + const { resolveSchema } = await import('../../src/core/artifact-graph/resolver.js'); + const fullTicket = flat(resolveSchema('atd-sdlc').artifacts.find(a => a.id === 'ticket')?.instruction ?? ''); + const liteTicket = flat(resolveSchema('atd-sdlc-lite').artifacts.find(a => a.id === 'ticket')?.instruction ?? ''); + + expect(fullTicket).toContain('proceed normally'); + expect(liteTicket).toContain('self-triage at ticket intake'); + expect(liteTicket).toContain('never allowed'); + // semantic gate: structurally complete but failing sidecars escalate + expect(liteTicket).toContain('no FAIL, no UNCERTAIN'); + expect(liteTicket).toContain('recommendation is `atd-sdlc-lite`'); + expect(liteTicket).toContain('confirmed choice is `atd-sdlc-lite`'); + }); + }); + + describe('sidecar is not an artifact output (graph-level)', () => { + it('no artifact in either schema generates triage.md', async () => { + const { resolveSchema } = await import('../../src/core/artifact-graph/resolver.js'); + for (const schemaName of ['atd-sdlc', 'atd-sdlc-lite']) { + const schema = resolveSchema(schemaName); + for (const artifact of schema.artifacts) { + expect(artifact.generates, `${schemaName}/${artifact.id}`).not.toContain('triage'); + } + } + }); + + it('writing triage.md leaves the ticket artifact pending in both schemas', async () => { + const { resolveSchema } = await import('../../src/core/artifact-graph/resolver.js'); + const { ArtifactGraph } = await import('../../src/core/artifact-graph/graph.js'); + const { detectCompleted } = await import('../../src/core/artifact-graph/state.js'); + + for (const schemaName of ['atd-sdlc', 'atd-sdlc-lite']) { + const changeDir = path.join(os.tmpdir(), `atd-triage-sidecar-${randomUUID()}`); + await fs.mkdir(changeDir, { recursive: true }); + try { + await fs.writeFile(path.join(changeDir, '.openspec.yaml'), `schema: ${schemaName}\n`); + await fs.writeFile(path.join(changeDir, 'triage.md'), '# Triage: abc-1'); + + const graph = ArtifactGraph.fromSchema(resolveSchema(schemaName)); + const completed = detectCompleted(graph, changeDir); + expect(completed.has('ticket'), schemaName).toBe(false); + expect(graph.getNextArtifacts(completed), schemaName).toEqual(['ticket']); + } finally { + await fs.rm(changeDir, { recursive: true, force: true }); + } + } + }); + }); +}); diff --git a/test/core/profiles.test.ts b/test/core/profiles.test.ts index b06456e016..e1cd55a914 100644 --- a/test/core/profiles.test.ts +++ b/test/core/profiles.test.ts @@ -9,7 +9,7 @@ import { describe('profiles', () => { describe('CORE_WORKFLOWS', () => { it('should contain the default core workflows', () => { - expect(CORE_WORKFLOWS).toEqual(['propose', 'explore', 'apply', 'update', 'sync', 'archive']); + expect(CORE_WORKFLOWS).toEqual(['propose', 'explore', 'apply', 'update', 'sync', 'archive', 'atd-triage']); }); it('should include update in the core profile (default install, not expanded-only)', () => { @@ -24,14 +24,15 @@ describe('profiles', () => { }); describe('ALL_WORKFLOWS', () => { - it('should contain all 12 workflows', () => { - expect(ALL_WORKFLOWS).toHaveLength(12); + it('should contain all 13 workflows', () => { + expect(ALL_WORKFLOWS).toHaveLength(13); }); it('should contain expected workflow IDs', () => { const expected = [ 'propose', 'explore', 'new', 'continue', 'apply', 'update', 'ff', 'sync', 'archive', 'bulk-archive', 'verify', 'onboard', + 'atd-triage', ]; expect([...ALL_WORKFLOWS]).toEqual(expected); }); diff --git a/test/core/shared/skill-generation.test.ts b/test/core/shared/skill-generation.test.ts index 5f4bba9d55..c806c906b3 100644 --- a/test/core/shared/skill-generation.test.ts +++ b/test/core/shared/skill-generation.test.ts @@ -8,9 +8,9 @@ import { describe('skill-generation', () => { describe('getSkillTemplates', () => { - it('should return all 12 skill templates', () => { + it('should return all 13 skill templates', () => { const templates = getSkillTemplates(); - expect(templates).toHaveLength(12); + expect(templates).toHaveLength(13); }); it('should have unique directory names', () => { @@ -89,9 +89,9 @@ describe('skill-generation', () => { }); describe('getCommandTemplates', () => { - it('should return all 12 command templates', () => { + it('should return all 13 command templates', () => { const templates = getCommandTemplates(); - expect(templates).toHaveLength(12); + expect(templates).toHaveLength(13); }); it('should have unique IDs', () => { @@ -144,9 +144,9 @@ describe('skill-generation', () => { }); describe('getCommandContents', () => { - it('should return all 12 command contents', () => { + it('should return all 13 command contents', () => { const contents = getCommandContents(); - expect(contents).toHaveLength(12); + expect(contents).toHaveLength(13); }); it('should have valid content structure', () => { diff --git a/test/core/shared/tool-detection.test.ts b/test/core/shared/tool-detection.test.ts index c4ef3bbb6c..85f9bd35d5 100644 --- a/test/core/shared/tool-detection.test.ts +++ b/test/core/shared/tool-detection.test.ts @@ -28,7 +28,7 @@ describe('tool-detection', () => { describe('SKILL_NAMES', () => { it('should contain all skill names matching COMMAND_IDS', () => { - expect(SKILL_NAMES).toHaveLength(12); + expect(SKILL_NAMES).toHaveLength(13); expect(SKILL_NAMES).toContain('openspec-explore'); expect(SKILL_NAMES).toContain('openspec-new-change'); expect(SKILL_NAMES).toContain('openspec-continue-change'); @@ -332,4 +332,26 @@ metadata: expect(cursorStatus?.needsUpdate).toBe(false); }); }); + + describe('atd-triage-only installations', () => { + it('detects a project configured with only the atd-change-triage skill', async () => { + const skillFile = path.join(testDir, '.claude', 'skills', 'atd-change-triage', 'SKILL.md'); + await fs.mkdir(path.dirname(skillFile), { recursive: true }); + await fs.writeFile(skillFile, 'name: atd-change-triage\n'); + + const status = getToolSkillStatus(testDir, 'claude'); + expect(status.configured).toBe(true); + expect(status.skillCount).toBe(1); + expect(getConfiguredTools(testDir)).toContain('claude'); + }); + + it('detects a project configured with only the atd-triage command', async () => { + const { getConfiguredToolsForProfileSync } = await import('../../../src/core/profile-sync-drift.js'); + const commandFile = path.join(testDir, '.claude', 'commands', 'opsx', 'atd-triage.md'); + await fs.mkdir(path.dirname(commandFile), { recursive: true }); + await fs.writeFile(commandFile, '# atd-triage\n'); + + expect(getConfiguredToolsForProfileSync(testDir)).toContain('claude'); + }); + }); }); diff --git a/test/core/update.test.ts b/test/core/update.test.ts index 43f662baf7..00f739826a 100644 --- a/test/core/update.test.ts +++ b/test/core/update.test.ts @@ -1706,7 +1706,7 @@ More user content after markers. call.map(arg => String(arg)).join(' ') ); expect(calls.some(call => - call.includes('Your custom profile is missing 2 core workflows: update, sync') + call.includes('Your custom profile is missing 3 core workflows: update, sync, atd-triage') )).toBe(true); expect(calls.some(call => call.includes('openspec config profile core') @@ -1727,7 +1727,7 @@ More user content after markers. featureFlags: {}, profile: 'custom', delivery: 'both', - workflows: ['propose', 'explore', 'apply', 'sync', 'archive'], + workflows: ['propose', 'explore', 'apply', 'sync', 'archive', 'atd-triage'], }); const initCommand = new InitCommand({ tools: 'claude', force: true }); @@ -1755,7 +1755,7 @@ More user content after markers. featureFlags: {}, profile: 'custom', delivery: 'both', - workflows: ['propose', 'explore', 'apply', 'update', 'sync', 'archive', 'verify'], + workflows: ['propose', 'explore', 'apply', 'update', 'sync', 'archive', 'atd-triage', 'verify'], }); const initCommand = new InitCommand({ tools: 'claude', force: true }); From 85f42ea39378fd775809119821fba37e702c21ab Mon Sep 17 00:00:00 2001 From: rpogula Date: Wed, 22 Jul 2026 14:26:31 -0400 Subject: [PATCH 2/2] =?UTF-8?q?feat(atd):=20add=20workflow=20fa=C3=A7ades?= =?UTF-8?q?=20completing=20the=20five-step=20ATD=20journey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add atd-continue, atd-apply, atd-verify, and atd-close as thin façades over the generic continue/apply/verify/archive workflows, composed from new shared parameterized instruction-body builders (generic output stays byte-for-byte identical, locked by snapshots). Each façade names its journey position, embeds the shared ATD schema guard (atd-sdlc / atd-sdlc-lite only), and hands off to the next step; close hard-gates on apply state "all_done" with no override, states the delta-spec merge procedure inline, and never performs closure work itself. Recompose CORE_WORKFLOWS as the five ATD workflows plus explore and update; generic ids stay available via the custom profile. Register the façades across every enumerating surface, add a registry-parity test so an omission fails CI, map atd command→skill references for skills-only delivery, reuse the exported WORKFLOW_TO_SKILL_DIR in init (fixes stale local copy leaving façade skills behind on delivery switch), and point init/update onboarding at /opsx:atd-triage. Regenerate the committed skills/ distribution (17 skills). Implements openspec/changes/add-atd-workflow-facades (18/18 tasks). --- .changeset/add-atd-workflow-facades.md | 8 + .../specs/atd-developer-docs/spec.md | 2 +- .../add-atd-workflow-facades/design.md | 1 + .../specs/atd-workflow-facades/spec.md | 4 +- .../changes/add-atd-workflow-facades/tasks.md | 36 +- skills/atd-change-apply/SKILL.md | 167 +++ skills/atd-change-close/SKILL.md | 143 ++ skills/atd-change-continue/SKILL.md | 129 ++ skills/atd-change-triage/SKILL.md | 4 +- skills/atd-change-verify/SKILL.md | 185 +++ src/core/init.ts | 24 +- src/core/profile-sync-drift.ts | 4 + src/core/profiles.ts | 6 +- src/core/shared/skill-generation.ts | 16 + src/core/shared/tool-detection.ts | 8 + src/core/templates/skill-templates.ts | 4 + src/core/templates/workflows/apply-change.ts | 218 +--- .../templates/workflows/archive-change.ts | 244 ++-- src/core/templates/workflows/atd-apply.ts | 46 + src/core/templates/workflows/atd-close.ts | 96 ++ src/core/templates/workflows/atd-continue.ts | 43 + src/core/templates/workflows/atd-triage.ts | 4 +- src/core/templates/workflows/atd-verify.ts | 48 + .../workflows/atd-workflow-shared.ts | 36 + .../templates/workflows/continue-change.ts | 168 +-- src/core/templates/workflows/verify-change.ts | 206 +-- src/core/update.ts | 12 +- src/utils/command-references.ts | 8 +- test/commands/config-profile.test.ts | 20 +- test/commands/config.test.ts | 2 +- test/core/atd-close-gate.test.ts | 104 ++ test/core/atd-facades-workflow.test.ts | 292 +++++ test/core/init.test.ts | 64 +- test/core/profiles.test.ts | 16 +- test/core/shared/skill-generation.test.ts | 12 +- test/core/shared/tool-detection.test.ts | 7 +- .../generic-workflow-parity.test.ts.snap | 1150 +++++++++++++++++ .../templates/generic-workflow-parity.test.ts | 33 + test/core/update.test.ts | 49 +- 39 files changed, 2905 insertions(+), 714 deletions(-) create mode 100644 .changeset/add-atd-workflow-facades.md create mode 100644 skills/atd-change-apply/SKILL.md create mode 100644 skills/atd-change-close/SKILL.md create mode 100644 skills/atd-change-continue/SKILL.md create mode 100644 skills/atd-change-verify/SKILL.md create mode 100644 src/core/templates/workflows/atd-apply.ts create mode 100644 src/core/templates/workflows/atd-close.ts create mode 100644 src/core/templates/workflows/atd-continue.ts create mode 100644 src/core/templates/workflows/atd-verify.ts create mode 100644 src/core/templates/workflows/atd-workflow-shared.ts create mode 100644 test/core/atd-close-gate.test.ts create mode 100644 test/core/atd-facades-workflow.test.ts create mode 100644 test/core/templates/__snapshots__/generic-workflow-parity.test.ts.snap create mode 100644 test/core/templates/generic-workflow-parity.test.ts diff --git a/.changeset/add-atd-workflow-facades.md b/.changeset/add-atd-workflow-facades.md new file mode 100644 index 0000000000..7eb35e051d --- /dev/null +++ b/.changeset/add-atd-workflow-facades.md @@ -0,0 +1,8 @@ +--- +"@fission-ai/openspec": minor +--- + +### Features + +- **ATD workflow façades** — four new workflows complete the five-step ATD journey started by `atd-triage`: `atd-continue` (skill `atd-change-continue`, `/opsx:atd-continue`), `atd-apply` (`atd-change-apply`, `/opsx:atd-apply`), `atd-verify` (`atd-change-verify`, `/opsx:atd-verify`), and `atd-close` (`atd-change-close`, `/opsx:atd-close`). Each is a thin façade composed from the corresponding generic workflow's shared instruction-body builder, adding ATD-only schema validation (`atd-sdlc` / `atd-sdlc-lite`; other schemas are directed to the generic workflow), journey naming, and step policy. `atd-close` hard-gates on `openspec instructions apply --json` reporting `state: "all_done"` — no incomplete-work override — and retains the archive workflow's delta-spec sync assessment; it never performs publication or Jira closure itself. +- **Core profile recomposed** — the default install is now the ATD journey: `atd-triage`, `atd-continue`, `atd-apply`, `atd-verify`, `atd-close`, plus `explore` and `update`. Generic `propose`, `continue`, `apply`, `verify`, `sync`, and `archive` leave the core profile but remain fully available through the custom profile (`openspec config profile`). Existing installs converge via `openspec update`'s standard profile-drift sync. diff --git a/openspec/changes/add-atd-docs-site/specs/atd-developer-docs/spec.md b/openspec/changes/add-atd-docs-site/specs/atd-developer-docs/spec.md index 41f46e79e6..9d8d6a790b 100644 --- a/openspec/changes/add-atd-docs-site/specs/atd-developer-docs/spec.md +++ b/openspec/changes/add-atd-docs-site/specs/atd-developer-docs/spec.md @@ -21,7 +21,7 @@ The site navigation SHALL contain: an index page stating the workflow purpose (o - **THEN** the navigation resolves index, architecture, getting-started, flows/{triage, full-sdlc, lite, escalation}, standards, examples/{example-full, example-lite}, and reference/{config-keys, faq} ### Requirement: Flow pages carry diagrams matching the shipped schemas -Each flow page SHALL carry a mermaid diagram consistent with the corresponding shipped schema or skill behavior, sourced from the approved change design documents (`add-atd-sdlc-schema`, `add-atd-sdlc-lite-triage`). +Each flow page SHALL carry a mermaid diagram consistent with the corresponding shipped schema or skill behavior, sourced from the approved change design documents (`add-atd-sdlc-schema`, `add-atd-sdlc-lite-triage`, `add-atd-workflow-facades`). Flow pages SHALL present the developer journey in the five-step façade vocabulary (`atd-change-triage` → `atd-change-continue` → `atd-change-apply` → `atd-change-verify` → `atd-change-close`); generic `openspec-*`/`/opsx:*` workflow names appear only when documenting maintainer or non-ATD flows. #### Scenario: Full SDLC flow page - **WHEN** a developer opens the full-sdlc flow page diff --git a/openspec/changes/add-atd-workflow-facades/design.md b/openspec/changes/add-atd-workflow-facades/design.md index dc4f8ccd31..5e185864ef 100644 --- a/openspec/changes/add-atd-workflow-facades/design.md +++ b/openspec/changes/add-atd-workflow-facades/design.md @@ -19,6 +19,7 @@ - New CLI commands, artifact-graph, or resolver behavior. - Migrating the existing `atd-triage` id or `atd-change-triage` directory. - Documenting the journey on the docs site (that is `add-atd-docs-site`'s scope; coordination only). +- Lite→full escalation: it remains schema-driven (the `atd-sdlc-lite` schema owns the one-way escalation instructions); façades do not reimplement or gate it. ## Decisions diff --git a/openspec/changes/add-atd-workflow-facades/specs/atd-workflow-facades/spec.md b/openspec/changes/add-atd-workflow-facades/specs/atd-workflow-facades/spec.md index ccc3c0d4e3..0b2c0a781e 100644 --- a/openspec/changes/add-atd-workflow-facades/specs/atd-workflow-facades/spec.md +++ b/openspec/changes/add-atd-workflow-facades/specs/atd-workflow-facades/spec.md @@ -29,11 +29,11 @@ Each new ATD workflow SHALL compose the corresponding generic workflow from a sh - **THEN** its content includes the shared store-selection guidance block and the template parity test passes ### Requirement: Façades accept only ATD schemas -Every ATD façade SHALL read `schemaName` from `openspec status --json` before performing its workflow action and SHALL continue only for `atd-sdlc` or `atd-sdlc-lite`. For any other schema it SHALL stop without modifying artifacts, code, specs, tasks, or archive state and SHALL direct the developer to the corresponding generic workflow. +Every ATD façade's instructions SHALL direct the agent to read `schemaName` from `openspec status --json` before performing its workflow action and to continue only for `atd-sdlc` or `atd-sdlc-lite`. For any other schema the instructions SHALL direct the agent to stop without modifying artifacts, code, specs, tasks, or archive state and to point the developer to the corresponding generic workflow. Automated tests verify the instruction contract; actual agent compliance is validated during pilot. #### Scenario: Non-ATD change rejected - **WHEN** `atd-change-apply` is invoked for a `spec-driven` change -- **THEN** it makes no change and directs the developer to `openspec-apply-change` +- **THEN** its instructions direct the agent to stop without modifying anything and to point the developer to `openspec-apply-change` ### Requirement: Close hard-gates tracked work and holds no closure logic `atd-close` SHALL obtain the apply state from `openspec instructions apply --json` and require every tracked task to be complete, including standards conformance, documentation, and Jira closure tasks. It SHALL NOT rely on a particular task-group heading. When any artifact or task is incomplete, close SHALL surface the incomplete items, direct the developer to `atd-change-apply`, and stop without offering an override. Close SHALL NOT perform publication, Jira closure, or any other closure work itself. diff --git a/openspec/changes/add-atd-workflow-facades/tasks.md b/openspec/changes/add-atd-workflow-facades/tasks.md index dc6f36bc77..ebf150678b 100644 --- a/openspec/changes/add-atd-workflow-facades/tasks.md +++ b/openspec/changes/add-atd-workflow-facades/tasks.md @@ -2,33 +2,33 @@ ## 1. Shared workflow composition -- [ ] 1.1 Extract parameterized instruction-body builders from `continue-change.ts`, `apply-change.ts`, `verify-change.ts`, and `archive-change.ts`; preserve existing generic skill and command output byte-for-byte; verify with focused template snapshot/parity tests -- [ ] 1.2 Add the shared ATD schema guard (`schemaName` must be `atd-sdlc` or `atd-sdlc-lite`) and tests proving a `spec-driven` change stops without mutation and names the corresponding generic workflow +- [x] 1.1 Extract parameterized instruction-body builders from `continue-change.ts`, `apply-change.ts`, `verify-change.ts`, and `archive-change.ts`; preserve existing generic skill and command output byte-for-byte; verify with focused template snapshot/parity tests +- [x] 1.2 Add the shared ATD schema guard (`schemaName` must be `atd-sdlc` or `atd-sdlc-lite`) and instruction-contract tests asserting the generated templates direct the agent to stop on a `spec-driven` change without mutation and to name the corresponding generic workflow ## 2. ATD workflow template modules -- [ ] 2.1 Create `src/core/templates/workflows/atd-continue.ts` (skill `atd-change-continue`, command `atd-continue`) by composing the shared continue body; name journey step 2, create one next artifact from status/instructions, and hand off to `atd-change-apply` when apply-ready; verify `pnpm build` and focused tests -- [ ] 2.2 Create `src/core/templates/workflows/atd-apply.ts` (skill `atd-change-apply`, command `atd-apply`) by composing the shared apply body; follow schema-provided standards/apply instructions, complete every tracked task including closure tasks, and hand off to `atd-change-verify`; verify focused tests -- [ ] 2.3 Create `src/core/templates/workflows/atd-verify.ts` (skill `atd-change-verify`, command `atd-verify`) by composing the shared verify body; verify tests, AC traceability, standards, documentation, and closure readiness, then hand off to `atd-change-close`; verify focused tests -- [ ] 2.4 Create `src/core/templates/workflows/atd-close.ts` (skill `atd-change-close`, command `atd-close`) by composing the shared archive body with a hard gate on `openspec instructions apply --json` reporting `state: "all_done"`; retain delta-spec assessment/sync/post-sync verification, never override incomplete work, and never perform publication or Jira closure; verify focused tests -- [ ] 2.5 Update `src/core/templates/workflows/atd-triage.ts` so its hand-off names `atd-change-continue`; verify `test/core/atd-triage-workflow.test.ts` +- [x] 2.1 Create `src/core/templates/workflows/atd-continue.ts` (skill `atd-change-continue`, command `atd-continue`) by composing the shared continue body; name journey step 2, create one next artifact from status/instructions, and hand off to `atd-change-apply` when apply-ready; verify `pnpm build` and focused tests +- [x] 2.2 Create `src/core/templates/workflows/atd-apply.ts` (skill `atd-change-apply`, command `atd-apply`) by composing the shared apply body; follow schema-provided standards/apply instructions, complete every tracked task including closure tasks, and hand off to `atd-change-verify`; verify focused tests +- [x] 2.3 Create `src/core/templates/workflows/atd-verify.ts` (skill `atd-change-verify`, command `atd-verify`) by composing the shared verify body; verify tests, AC traceability, standards, documentation, and closure readiness, then hand off to `atd-change-close`; verify focused tests +- [x] 2.4 Create `src/core/templates/workflows/atd-close.ts` (skill `atd-change-close`, command `atd-close`) by composing the shared archive body with a hard gate on `openspec instructions apply --json` reporting `state: "all_done"`; retain delta-spec assessment/sync/post-sync verification, never override incomplete work, and never perform publication or Jira closure; verify focused tests +- [x] 2.5 Update `src/core/templates/workflows/atd-triage.ts` so its hand-off names `atd-change-continue`; verify `test/core/atd-triage-workflow.test.ts` ## 3. Registry and profile surfaces -- [ ] 3.1 Export the four template pairs from `src/core/templates/skill-templates.ts` and register them in both registries in `src/core/shared/skill-generation.ts`; verify exactly one skill and command entry per workflow id -- [ ] 3.2 Add the four ids to `ALL_WORKFLOWS`, recompose `CORE_WORKFLOWS` as `atd-triage`, `atd-continue`, `atd-apply`, `atd-verify`, `atd-close`, `explore`, `update`, and update profile/config expectations; verify profile tests -- [ ] 3.3 Extend `WORKFLOW_TO_SKILL_DIR`, `SKILL_NAMES`, and `COMMAND_IDS` with all four façades; add behavior tests proving façade-only skill and command installations are detected -- [ ] 3.4 Add registry-parity coverage tying both generation registries, `WORKFLOW_TO_SKILL_DIR`, `SKILL_NAMES`, and `COMMAND_IDS` to `ALL_WORKFLOWS`; verify an intentional omission fails the test +- [x] 3.1 Export the four template pairs from `src/core/templates/skill-templates.ts` and register them in both registries in `src/core/shared/skill-generation.ts`; verify exactly one skill and command entry per workflow id +- [x] 3.2 Add the four ids to `ALL_WORKFLOWS`, recompose `CORE_WORKFLOWS` as `atd-triage`, `atd-continue`, `atd-apply`, `atd-verify`, `atd-close`, `explore`, `update`, and update profile/config expectations and any `CoreWorkflowId` usages affected by removed generic core ids; verify profile tests and `tsc --noEmit` +- [x] 3.3 Extend `WORKFLOW_TO_SKILL_DIR`, `SKILL_NAMES`, and `COMMAND_IDS` with all four façades; add behavior tests proving façade-only skill and command installations are detected +- [x] 3.4 Add registry-parity coverage tying both generation registries, `WORKFLOW_TO_SKILL_DIR`, `SKILL_NAMES`, and `COMMAND_IDS` to `ALL_WORKFLOWS`; verify an intentional omission fails the test ## 4. Journey and delivery tests -- [ ] 4.1 Add `test/core/atd-facades-workflow.test.ts` covering both skill and command surfaces: journey positions/handoffs, ATD-only schema guard, shared store guidance, continue/apply/verify composition, close hard gate, and absence of closure writes in close -- [ ] 4.2 Add an integration test for `atd-close`: incomplete tasks block without override; completed full-schema tasks with unsynced deltas enter the archive sync assessment and cannot archive on failed verification -- [ ] 4.3 Test core-profile init and update for skills-only, commands-only, and combined delivery: install the five ATD façades plus explore/update and remove or omit generic propose/sync/archive/continue/apply/verify surfaces -- [ ] 4.4 Bump count/order expectations from 13 to 17 and run the full test suite +- [x] 4.1 Add `test/core/atd-facades-workflow.test.ts` covering both skill and command surfaces: journey positions/handoffs, ATD-only schema guard, shared store guidance, continue/apply/verify composition, close hard gate, and absence of closure writes in close +- [x] 4.2 Add an integration test for `atd-close`: incomplete tasks block without override; completed full-schema tasks with unsynced deltas enter the archive sync assessment and cannot archive on failed verification +- [x] 4.3 Test core-profile init and update for skills-only, commands-only, and combined delivery: install the five ATD façades plus explore/update and remove or omit generic propose/sync/archive/continue/apply/verify surfaces +- [x] 4.4 Bump count/order expectations from 13 to 17 and run the full test suite ## 5. Distribution and coordination -- [ ] 5.1 Run `pnpm build && pnpm generate:skills`; commit the four new `skills/atd-change-*/SKILL.md` files and verify skills.sh parity. Keep ignored `.claude/` output uncommitted -- [ ] 5.2 Align `add-atd-docs-site` journey requirements with the five-step `atd-change-*` vocabulary before either change ships; verify both changes validate strictly -- [ ] 5.3 Add the appropriate changeset for the user-visible workflow/profile change; verify package contents and release notes describe the new default ATD journey +- [x] 5.1 Run `pnpm build && pnpm generate:skills`; commit the four new `skills/atd-change-*/SKILL.md` files and verify skills.sh parity. Keep ignored `.claude/` output uncommitted +- [x] 5.2 Align `add-atd-docs-site` journey requirements with the five-step `atd-change-*` vocabulary before either change ships; verify both changes validate strictly +- [x] 5.3 Add the appropriate changeset for the user-visible workflow/profile change; verify package contents and release notes describe the new default ATD journey diff --git a/skills/atd-change-apply/SKILL.md b/skills/atd-change-apply/SKILL.md new file mode 100644 index 0000000000..4a3c58d890 --- /dev/null +++ b/skills/atd-change-apply/SKILL.md @@ -0,0 +1,167 @@ +--- +name: atd-change-apply +description: Implement an ATD change: load the applicable ATD standards and execute every tracked task, including closure tasks. Step 3 of the ATD journey; use after atd-change-continue. +allowed-tools: Bash(openspec:*) +license: MIT +compatibility: Requires openspec CLI. +metadata: + author: openspec + version: "1.0" +--- + +Implement the tracked tasks of an ATD change under the applicable ATD standards (step 3 of the ATD journey). + +**Store selection:** If the user names a store (a store is a standalone OpenSpec repo registered on this machine) or the work lives in one, run `openspec store list --json` to discover registered store ids, then pass `--store ` on the commands that read or write specs and changes (`new change`, `status`, `instructions`, `list`, `show`, `validate`, `archive`, `doctor`, `context`). Other commands do not take the flag. Hints printed by commands already carry the flag; keep it on follow-ups. Without a store, commands act on the nearest local `openspec/` root. + +**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes. + +**Steps** + +1. **Select the change** + + If a name is provided, use it. Otherwise: + - Infer from conversation context if the user mentioned a change + - Auto-select if only one active change exists + - If ambiguous, run `openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select + + Always announce: "Using change: " and how to override (e.g., `/opsx:atd-apply `). + +2. **Check status to understand the schema** + ```bash + openspec status --change "" --json + ``` + Parse the JSON to understand: + - `schemaName`: The workflow being used (e.g., "spec-driven") + - `planningHome`, `changeRoot`, and `actionContext`: planning scope and edit constraints + - Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others) + + **ATD schema guard**: This workflow only acts on ATD changes. If `schemaName` is not `atd-sdlc` or `atd-sdlc-lite`, STOP — do not modify artifacts, code, specs, tasks, or archive state — and direct the developer to the generic `openspec-apply-change` workflow instead. + +3. **Get apply instructions** + + ```bash + openspec instructions apply --change "" --json + ``` + + This returns: + - `contextFiles`: artifact ID -> array of concrete file paths (varies by schema) + - Progress (total, complete, remaining) + - Task list with status + - Dynamic instruction based on current state + + **Handle states:** + - If `state: "blocked"` (missing artifacts): show message, suggest using `atd-change-continue` + - If `state: "all_done"`: congratulate, suggest archive + - Otherwise: proceed to implementation + +4. **Read context files** + + Read every file path listed under `contextFiles` from the apply instructions output. + The files depend on the schema being used: + - **spec-driven**: proposal, specs, design, tasks + - Other schemas: follow the contextFiles from CLI output + +5. **Show current progress** + + Display: + - Schema being used + - Progress: "N/M tasks complete" + - Remaining tasks overview + - Dynamic instruction from CLI + +6. **Implement tasks (loop until done or blocked)** + + For each pending task: + - Show which task is being worked on + - Make the code changes required + - Keep changes minimal and focused + - Mark task complete in the tasks file: `- [ ]` → `- [x]` + - Continue to next task + + **Pause if:** + - Task is unclear → ask for clarification + - Implementation reveals a design issue → suggest updating artifacts + - Error or blocker encountered → report and wait for guidance + - User interrupts + +7. **On completion or pause, show status** + + Display: + - Tasks completed this session + - Overall progress: "N/M tasks complete" + - If all done: suggest archive + - If paused: explain why and wait for guidance + +**Output During Implementation** + +``` +## Implementing: (schema: ) + +Working on task 3/7: +[...implementation happening...] +✓ Task complete + +Working on task 4/7: +[...implementation happening...] +✓ Task complete +``` + +**Output On Completion** + +``` +## Implementation Complete + +**Change:** +**Schema:** +**Progress:** 7/7 tasks complete ✓ + +### Completed This Session +- [x] Task 1 +- [x] Task 2 +... + +All tasks complete! Continue with `atd-change-verify` before closing. +``` + +**Output On Pause (Issue Encountered)** + +``` +## Implementation Paused + +**Change:** +**Schema:** +**Progress:** 4/7 tasks complete + +### Issue Encountered + + +**Options:** +1.