From e3fc1625c8ea070e63bc0d255e018dcd788bd940 Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Thu, 30 Jul 2026 13:59:42 +0100 Subject: [PATCH 1/7] fix(meta,work-package): the artifacts checkout is the git target for planning artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The engineering planning folder is a checkout of its own in this repo, so a commit aimed at the host repo puts the artifacts nowhere a published link resolves. Five surfaces stated the single-layout model; each now states the layout it resolves, or cites the one op that owns the choice. commit-and-persist picks the primitive from the layout — commit-submodule when .engineering is its own checkout, commit-regular-files when the artifacts are ordinary files of the host checkout — and states that the parent's pointer bump lands in a PR where that branch takes changes only through one. agent-conduct and manage-artifacts cite the resolving op instead of restating a location; committed-to-parent and push-before-linking were one rule written twice, so the surviving rule is push-before-linking. The Engineering link row and the review-mode Reports base URL carry the planning root as a slot, so a renderer cannot copy either as if one layout were the only one. Publishing is two steps, not a technique that calls another: the technique resolves the ref and the file set, the activity binds manage-git::artifact-commits to put them on the branch. Activity 13 and 14 both bind the pair, and the activity-13 diagram draws the review arm the definition actually walks. verify-outcomes and generate-summary read the session themselves, so the state and trace they read are protocol locals rather than inputs a caller supplies, and meta drops the two variables nothing produced. gitnexus-operations states what the graph answers: code symbols and file paths, not which prose states a claim; keyword-shaped queries; and a freshness check before any operation whose answer turns on the tree. Refs #319, #338, #320, #310 --- meta/activities/04-end-workflow.yaml | 4 +- meta/techniques/agent-conduct.md | 4 +- .../gitnexus-operations/TECHNIQUE.md | 12 ++++- .../workflow-engine/commit-and-persist.md | 9 ++-- .../workflow-engine/generate-summary.md | 10 ++--- .../workflow-engine/verify-outcomes.md | 10 ++--- meta/workflow.yaml | 10 +---- .../activities/13-submit-for-review.yaml | 20 +++++++-- work-package/activities/14-complete.yaml | 17 +++++-- work-package/activities/README.md | 11 +++-- work-package/resources/pr-description.md | 6 ++- work-package/resources/review-mode.md | 6 +-- .../techniques/manage-artifacts/TECHNIQUE.md | 8 +--- .../techniques/publish-review-artifacts.md | 45 ------------------- .../techniques/resolve-artifact-publish.md | 43 ++++++++++++++++++ .../techniques/update-pr/TECHNIQUE.md | 4 +- .../techniques/update-pr/create-pr.md | 2 +- work-package/workflow.yaml | 2 +- 18 files changed, 119 insertions(+), 104 deletions(-) delete mode 100644 work-package/techniques/publish-review-artifacts.md create mode 100644 work-package/techniques/resolve-artifact-publish.md diff --git a/meta/activities/04-end-workflow.yaml b/meta/activities/04-end-workflow.yaml index 5c3423b4d..6b7d5f0ad 100644 --- a/meta/activities/04-end-workflow.yaml +++ b/meta/activities/04-end-workflow.yaml @@ -1,5 +1,5 @@ id: end-workflow -version: 4.2.0 +version: 4.3.0 name: End Workflow description: Close out the client workflow. required: true @@ -10,14 +10,12 @@ steps: name: workflow-engine::verify-outcomes inputs: outcomes: target_workflow_outcomes - state: client_state - kind: technique id: generate-summary technique: name: workflow-engine::generate-summary inputs: workflow_definition: target_workflow_id - execution_trace: client_trace - kind: checkpoint id: completion-confirmed message: Session summary presented above. Confirm closure or return to the workflow to address remaining items. diff --git a/meta/techniques/agent-conduct.md b/meta/techniques/agent-conduct.md index da63f0034..b2ace20b7 100644 --- a/meta/techniques/agent-conduct.md +++ b/meta/techniques/agent-conduct.md @@ -1,6 +1,6 @@ --- metadata: - version: 4.5.0 + version: 4.6.0 --- ## Capability @@ -95,7 +95,7 @@ On resume, still dispatch a worker via [dispatch-activity](./workflow-engine/dis ### orchestrator-component-path-scope -Branch creation, PR creation, and code commits MUST be performed inside the component directory (the submodule), NEVER in the host monorepo root. Planning artifact commits (`.engineering/artifacts/`) MUST be performed in the host repo where that directory lives, on the current branch — do NOT create a new branch in the host repo. +Branch creation, PR creation, and code commits MUST be performed inside the component directory (the submodule), NEVER in the host monorepo root. Planning artifact commits (`.engineering/artifacts/`) land on the current branch of the checkout that holds that directory — which checkout that is, and the primitive it takes, are resolved by [commit-and-persist](./workflow-engine/commit-and-persist.md) step 5. Do NOT create a new branch for them. ### orchestrator-automatic-transitions diff --git a/meta/techniques/gitnexus-operations/TECHNIQUE.md b/meta/techniques/gitnexus-operations/TECHNIQUE.md index 1aaf85c8f..c5bb63ea2 100644 --- a/meta/techniques/gitnexus-operations/TECHNIQUE.md +++ b/meta/techniques/gitnexus-operations/TECHNIQUE.md @@ -1,6 +1,6 @@ --- metadata: - version: 3.2.0 + version: 3.3.0 --- ## Capability @@ -19,7 +19,15 @@ Always apply [detect-changes](./detect-changes.md) after applying a rename or ba ### index-freshness-first -Apply [verify-index](./verify-index.md) at the start of any GitNexus session. Stale indexes return misleading results. +Apply [verify-index](./verify-index.md) at the start of any GitNexus session, and again before any operation whose answer turns on the current tree — [impact](./impact.md), [detect-changes](./detect-changes.md), [orphan-scan](./orphan-scan.md), [diff-coverage-map](./diff-coverage-map.md). A stale index answers in the same shape as a fresh one and says nothing about its own age, so an unverified answer is indistinguishable from a correct one. + +### graph-answers-code-not-prose + +The graph holds code symbols and file paths. For a markdown tree — `workflows/`, `docs/`, `.engineering/` — it locates a file by path but cannot answer which text states a claim, and [query](./query.md) returns unrelated matches rather than an empty result, so a miss does not read as a miss. Reach for the graph by path (a [cypher](./cypher.md) `f.filePath` match) or for code structure; read the prose with grep and Read. + +### keyword-shaped-queries + +Phrase [query](./query.md) as keywords, not as a natural-language question. Its ranking fuses keyword and semantic scoring, and the semantic half contributes only where the index carries embeddings — which is a property of how the repo was indexed, not something the query can assert. Keyword-shaped input is the phrasing that works either way. ### must-use-operations diff --git a/meta/techniques/workflow-engine/commit-and-persist.md b/meta/techniques/workflow-engine/commit-and-persist.md index 6eb928e3f..68b18c357 100644 --- a/meta/techniques/workflow-engine/commit-and-persist.md +++ b/meta/techniques/workflow-engine/commit-and-persist.md @@ -1,6 +1,6 @@ --- metadata: - version: 1.7.0 + version: 1.8.0 --- ## Capability @@ -28,14 +28,17 @@ Path to the planning folder. 2. Set the header-line `**Status:**` to the current lifecycle milestone for that workflow (text — distinct from Progress Status; see [Progress table](../../resources/planning-readme.md#progress-table)). 3. If the README already matches after steps 1–2, leave content equivalent — still include the file in the engineering commit below so a prior local-only edit is pushed. 4. If `{host_repo_path}/{component_path}` has uncommitted changes (`git status --porcelain` non-empty), apply [version-control](../version-control/TECHNIQUE.md)::[commit-submodule](../version-control/commit-submodule.md)(*paths*=changed files, *submodule_message*=`'(): source changes'` with the Conventional Commits type that fits the activity — feat for implement, fix for post-impl-review fixes, refactor for cleanup, *parent_branch*=current parent branch). Skip when the working tree is clean. -5. **Engineering commit + push:** Apply [version-control](../version-control/TECHNIQUE.md)::[commit-regular-files](../version-control/commit-regular-files.md)(*paths*=ALL changes under `.engineering/artifacts/` within `{planning_folder_path}`, including `README.md`, `session.json` and `.session-token`, *message*=`docs(): artifacts`). This post-activity hook **is** the commit request — do not wait for a separate user confirmation. Push must succeed before this operation returns: Engineering links and resume assume the remote holds the commit, so a local-only README or artifact update does not satisfy this step. +5. **Engineering commit + push:** Commit ALL changes under `.engineering/artifacts/` within `{planning_folder_path}`, including `README.md`, `session.json` and `.session-token`, with *message*=`docs(): artifacts`. The primitive follows the layout, resolved per [version-control](../version-control/TECHNIQUE.md)::[infrastructure-submodule-paths](../version-control/TECHNIQUE.md#infrastructure-submodule-paths). This post-activity hook **is** the commit request — do not wait for a separate user confirmation. Push must succeed before this operation returns: Engineering links and resume assume the remote holds the commit, so a local-only README or artifact update does not satisfy this step. + > When `.engineering` is a checkout of its own, apply [commit-submodule](../version-control/commit-submodule.md)(*submodule_path*=`.engineering`) — its own branch and remote carry the artifacts. + > Otherwise apply [commit-regular-files](../version-control/commit-regular-files.md) — the artifacts are ordinary files of the host checkout. + > Where the host branch accepts changes only through pull requests, the parent's submodule-pointer bump lands in a PR; a direct push to that branch is refused, and the engineering push above already satisfies this step without it. 6. Confirm the engineering push landed (remote tracking branch includes the new commit). If push failed, retry once; if still failing, surface the error and do not advance to the next activity. ## Rules ### commit-after-activity -After every completed activity, BOTH source-side changes (under `{host_repo_path}/{component_path}`, via [commit-submodule](../version-control/commit-submodule.md)) AND engineering artifacts (under `.engineering/artifacts/`, via [commit-regular-files](../version-control/commit-regular-files.md)) MUST be committed and **pushed** before evaluating transitions to the next activity. Skipping either scope leaves a dirty or remote-stale tree that breaks resume, Engineering links, and downstream activities. The submodule commit may be skipped only when the working tree at `{host_repo_path}/{component_path}` is clean. The engineering commit may be skipped only when the planning folder has no local changes **and** README Progress Status for `{activity_id}` already shows the intended post-activity status on the remote (complete, or cancelled/N/A when `{mark_progress_na}` applied) per [Status vocabulary](../../resources/planning-readme.md#status-vocabulary) — otherwise Apply sync-progress-status (step 1) then commit and push. Scope: this orchestrator post-activity hook only — distinct from [explicit-commit](../version-control/TECHNIQUE.md#explicit-commit), which governs ad-hoc commits outside this hook. +After every completed activity, BOTH source-side changes (under `{host_repo_path}/{component_path}`, via [commit-submodule](../version-control/commit-submodule.md)) AND engineering artifacts (under `.engineering/artifacts/`, via the primitive step 5 resolves for the layout) MUST be committed and **pushed** before evaluating transitions to the next activity. Skipping either scope leaves a dirty or remote-stale tree that breaks resume, Engineering links, and downstream activities. The submodule commit may be skipped only when the working tree at `{host_repo_path}/{component_path}` is clean. The engineering commit may be skipped only when the planning folder has no local changes **and** README Progress Status for `{activity_id}` already shows the intended post-activity status on the remote (complete, or cancelled/N/A when `{mark_progress_na}` applied) per [Status vocabulary](../../resources/planning-readme.md#status-vocabulary) — otherwise Apply sync-progress-status (step 1) then commit and push. Scope: this orchestrator post-activity hook only — distinct from [explicit-commit](../version-control/TECHNIQUE.md#explicit-commit), which governs ad-hoc commits outside this hook. ### readme-progress-before-persist diff --git a/meta/techniques/workflow-engine/generate-summary.md b/meta/techniques/workflow-engine/generate-summary.md index 45e177173..90ef49ceb 100644 --- a/meta/techniques/workflow-engine/generate-summary.md +++ b/meta/techniques/workflow-engine/generate-summary.md @@ -1,6 +1,6 @@ --- metadata: - version: 1.0.0 + version: 1.1.0 --- ## Capability @@ -13,10 +13,6 @@ Compose the markdown session summary presented at workflow close. Workflow definition (id, title, outcomes) -### execution_trace - -Completed activities, checkpoint decisions, artifacts produced - ## Outputs ### completion_summary @@ -25,8 +21,8 @@ Completed activities, checkpoint decisions, artifacts produced ## Protocol -1. Draw from `{execution_trace}` to compose the summary sections: workflow id and title, start/completion timestamps, activities completed, key checkpoint decisions, artifacts with paths, outcomes satisfied vs. unmet, follow-up items. Return the assembled markdown as `{completion_summary}`. - > Obtain the execution trace through the `inspect_session` tool — `view: activities` for completed activities, `view: checkpoints` for checkpoint decisions, `view: history` for the event trace, or `view: summary` for all of it — rather than reading `session.json` directly. +1. Resolve `{$execution_trace}`: the session's completed activities, checkpoint decisions and artifacts produced. Draw from `{execution_trace}` to compose the summary sections: workflow id and title, start/completion timestamps, activities completed, key checkpoint decisions, artifacts with paths, outcomes satisfied vs. unmet, follow-up items. Return the assembled markdown as `{completion_summary}`. + > Obtain `{execution_trace}` through the `inspect_session` tool — `view: activities` for completed activities, `view: checkpoints` for checkpoint decisions, `view: history` for the event trace, or `view: summary` for all of it — rather than reading `session.json` directly. It is resolved here, never supplied by a caller. ## Rules diff --git a/meta/techniques/workflow-engine/verify-outcomes.md b/meta/techniques/workflow-engine/verify-outcomes.md index 190851b42..62aef0562 100644 --- a/meta/techniques/workflow-engine/verify-outcomes.md +++ b/meta/techniques/workflow-engine/verify-outcomes.md @@ -1,6 +1,6 @@ --- metadata: - version: 1.2.0 + version: 1.3.0 --- ## Capability @@ -13,10 +13,6 @@ Compare a workflow's declared `outcomes` against state and identify gaps. Array of expected outcome strings to evaluate. -### state - -Current variable state and completed-activities trace - ## Outputs ### gaps @@ -26,5 +22,5 @@ Array of unsatisfied outcomes ## Protocol 1. Resolve the outcome list to evaluate: prefer a non-empty `{outcomes}` binding when supplied; otherwise fall back to the calling activity's declared `outcome:` list. Outcome strings are plain declarative prose — never encode or parse conditional predicates inside them. When a producing step was structurally gated out on the path taken, skip the outcomes that step would have satisfied rather than reporting them as unmet gaps. -2. For each entry in that list, evaluate satisfaction against state variables, artifact presence in `planning_folder_path`, and the completed-activities trace; collect every unmet item into `{gaps}`. - > Read the state variables and completed-activities trace through the `inspect_session` tool (`view: variables` and `view: activities`, or `view: summary` for both) rather than reading `session.json` directly. When `inspect_session` disagrees with a just-completed worker envelope for a critical path, prefer the envelope and planning-folder evidence (same reconcile stance as [dispatch-activity](./dispatch-activity.md#distrust-then-reconcile)). +2. Resolve `{$state}`: the session's variables and completed-activities trace. For each entry in that list, evaluate satisfaction against `{state}`'s variables, artifact presence in `planning_folder_path`, and its completed-activities trace; collect every unmet item into `{gaps}`. + > Read `{state}` through the `inspect_session` tool (`view: variables` and `view: activities`, or `view: summary` for both) rather than reading `session.json` directly. It is resolved here, never supplied by a caller — an orchestrator holding a stale copy of the bag is the disagreement the reconcile stance below exists for. When `inspect_session` disagrees with a just-completed worker envelope for a critical path, prefer the envelope and planning-folder evidence (same reconcile stance as [dispatch-activity](./dispatch-activity.md#distrust-then-reconcile)). diff --git a/meta/workflow.yaml b/meta/workflow.yaml index 1ebf255c1..288227445 100644 --- a/meta/workflow.yaml +++ b/meta/workflow.yaml @@ -1,6 +1,6 @@ $schema: ../../schemas/workflow.schema.json id: meta -version: 5.12.0 +version: 5.13.0 title: Meta Workflow description: Top-level lifecycle workflow that orchestrates client workflow sessions. Excluded from list_workflows — bootstrap navigates here directly. author: m2ux @@ -53,13 +53,7 @@ variables: defaultValue: false - name: target_workflow_outcomes type: string - description: The client workflow's declared outcomes, read by verify-outcomes during end-workflow close-out - - name: client_state - type: string - description: The dispatched client workflow's final variable state, read by verify-outcomes during end-workflow - - name: client_trace - type: string - description: The dispatched client workflow's execution trace, read by generate-summary during end-workflow + description: The client workflow's own outcome list, seeded in its bag, read by verify-outcomes during end-workflow close-out - name: workflow_match_ambiguous type: boolean description: Whether the user request matched multiple workflows — gates the workflow-selection checkpoint in discover-session diff --git a/work-package/activities/13-submit-for-review.yaml b/work-package/activities/13-submit-for-review.yaml index f401ff618..5dfdb62d7 100644 --- a/work-package/activities/13-submit-for-review.yaml +++ b/work-package/activities/13-submit-for-review.yaml @@ -1,5 +1,5 @@ id: submit-for-review -version: 1.14.0 +version: 1.15.0 name: Submit for Review description: Submit the work for review — PR review lifecycle normally; a verified private-remote push in stealth mode. required: true @@ -18,8 +18,22 @@ steps: operator: == value: true - kind: technique - id: publish-review-artifacts - technique: publish-review-artifacts + id: resolve-artifact-publish + technique: resolve-artifact-publish + condition: + type: simple + variable: is_review_mode + operator: == + value: true + - kind: technique + id: commit-review-artifacts + technique: + name: manage-git::artifact-commits + inputs: + activity_name: submit-for-review + issue_key: issue_number + files: publishable_files + branch: artifact_publish_ref condition: type: simple variable: is_review_mode diff --git a/work-package/activities/14-complete.yaml b/work-package/activities/14-complete.yaml index dd21d30e2..a8c43b1f7 100644 --- a/work-package/activities/14-complete.yaml +++ b/work-package/activities/14-complete.yaml @@ -1,5 +1,5 @@ id: complete -version: 1.7.0 +version: 1.8.0 name: Complete Work Package description: Wrap up the work package after PR merge (or after review-mode close-out). required: true @@ -81,12 +81,23 @@ steps: - action: validate target: broken_artifact_links == [] message: "Planning artifacts carry links that do not resolve: {broken_artifact_links}. Repoint each to a target that resolves at the publish ref, then re-run." + - kind: technique + id: resolve-close-out-publish + technique: resolve-artifact-publish + condition: + type: simple + variable: is_review_mode + operator: == + value: true - kind: technique id: publish-close-out-artifacts technique: - name: publish-review-artifacts + name: manage-git::artifact-commits inputs: - publishing_activity: complete + activity_name: complete + issue_key: issue_number + files: publishable_files + branch: artifact_publish_ref condition: type: simple variable: is_review_mode diff --git a/work-package/activities/README.md b/work-package/activities/README.md index f0aa522be..4a638b4c3 100644 --- a/work-package/activities/README.md +++ b/work-package/activities/README.md @@ -366,11 +366,10 @@ Definition: [`13-submit-for-review.yaml`](./13-submit-for-review.yaml) ```mermaid graph TD entryNode(["Entry"]) --> reviewMode{"Review mode?"} - reviewMode -->|"yes"| consolidate["Consolidate review findings"] - consolidate --> genSummary["Generate review summary"] - genSummary --> cpSummaryApproval{"review-summary-approval checkpoint"} - cpSummaryApproval --> postReview["Post PR review"] - postReview --> awaitReview + reviewMode -->|"yes"| consolidate["Consolidate review findings → resolve publish ref → commit artifacts → generate review summary"] + consolidate --> cpSummaryApproval{"review-summary-approval checkpoint"} + cpSummaryApproval --> persistSummary["Persist review summary → post PR review"] + persistSummary --> awaitReview reviewMode -->|"no"| cpDco{"dco-sign-off-confirmation checkpoint"} cpDco --> stealthMode{"Stealth mode?"} @@ -431,7 +430,7 @@ graph TD docsGate -->|"yes"| retrospective["Conduct the retrospective into COMPLETE.md, then verify planning-folder links"] retrospective --> publishGate{"Review mode?"} - publishGate -->|"yes"| republish["Publish close-out artifacts on the publish branch"] + publishGate -->|"yes"| republish["Resolve the publish ref, then commit the close-out artifacts onto it"] publishGate -->|"no"| removeWorktree republish --> removeWorktree["Remove component worktree (when this run created one)"] removeWorktree --> selectNext["Select next work package"] diff --git a/work-package/resources/pr-description.md b/work-package/resources/pr-description.md index 71e0a7a6d..7b1e3f9a9 100644 --- a/work-package/resources/pr-description.md +++ b/work-package/resources/pr-description.md @@ -2,7 +2,7 @@ name: pr-description description: PR description templates and link-row rendering forms. metadata: - version: 1.6.0 + version: 1.7.0 order: 12 legacy_id: 12 --- @@ -140,9 +140,11 @@ Optional sections (add when applicable): `## Migration Notes` (required steps fo **Standard link row** (Issue = the GitHub issue in the target repo, never the Jira ticket): ```markdown -🐛 [Issue]({TARGET_REPO_URL}/issues/{GITHUB_ISSUE_NUMBER}) 📐 [Engineering]({ENG_REPO_URL}/blob/{ENG_BRANCH}/.engineering/artifacts/planning/{PLANNING_FOLDER}/README.md) +🐛 [Issue]({TARGET_REPO_URL}/issues/{GITHUB_ISSUE_NUMBER}) 📐 [Engineering]({ENG_REPO_URL}/blob/{ENG_BRANCH}/{ENG_PLANNING_PATH}/{PLANNING_FOLDER}/README.md) ``` +`{ENG_PLANNING_PATH}` is the planning root relative to the root of the checkout `{ENG_BRANCH}` belongs to: `artifacts/planning` when `.engineering/` is a checkout of its own, and `.engineering/artifacts/planning` when the artifacts live directly in the host checkout. The rendering step resolves which, alongside the ref itself. + **Issue-skipped placeholder** (when `issue_skipped == true` — the line is rendered, italicised, no link, so reviewers can tell the omission was intentional): ```markdown diff --git a/work-package/resources/review-mode.md b/work-package/resources/review-mode.md index 2c3abbbb3..89737187e 100644 --- a/work-package/resources/review-mode.md +++ b/work-package/resources/review-mode.md @@ -2,7 +2,7 @@ name: review-mode description: Guidelines for using the work-package workflow in review mode to conduct structured PR reviews. Covers detection, adapted workflow behavior, and output generation. Organized by review category for per-section delivery to the technique that renders that category. metadata: - version: 1.13.0 + version: 1.14.0 order: 24 legacy_id: 24 --- @@ -38,10 +38,10 @@ The summary header carries `PR`, `Plan`, `Reviewers`, `Reports`, and `Date` fiel **Reports list:** The header includes a `Reports` field naming each report the summary links to, as hyperlinks. Each entry links the report by name to its artifact, under the engineering-artifacts base URL: ``` -https://github.com/{ENG_REPO_OWNER}/{ENG_REPO_NAME}/blob/{ARTIFACT_PUBLISH_REF}/artifacts/planning/{PLANNING_FOLDER}/ +https://github.com/{ENG_REPO_OWNER}/{ENG_REPO_NAME}/blob/{ARTIFACT_PUBLISH_REF}/{ENG_PLANNING_PATH}/{PLANNING_FOLDER}/ ``` -`{ARTIFACT_PUBLISH_REF}` is the **branch** the linked artifacts are published on, so the linked tree carries whatever the run adds after the link is written — close-out, retrospective, session trace and follow-ups all land on that branch and resolve from the same URL. Resolve `{ENG_REPO_OWNER}` and `{ENG_REPO_NAME}` from the artifacts checkout's remote; never hardcode `main`. The path after the ref is relative to the root of the checkout that ref belongs to: `artifacts/planning/…` when `.engineering/` is itself a checkout, and `.engineering/artifacts/planning/…` when the artifacts live directly in the product checkout. The set of reports and their artifact filenames are supplied by the rendering step — one entry per review category the run produced — not fixed by this template. +`{ARTIFACT_PUBLISH_REF}` is the **branch** the linked artifacts are published on, so the linked tree carries whatever the run adds after the link is written — close-out, retrospective, session trace and follow-ups all land on that branch and resolve from the same URL. Resolve `{ENG_REPO_OWNER}` and `{ENG_REPO_NAME}` from the engineering checkout's remote; never hardcode `main`. `{ENG_PLANNING_PATH}` is relative to the root of the checkout that ref belongs to: `artifacts/planning` when `.engineering/` is itself a checkout, and `.engineering/artifacts/planning` when the artifacts live directly in the product checkout. The set of reports and their artifact filenames are supplied by the rendering step — one entry per review category the run produced — not fixed by this template. **Ref split — engineering artifacts by branch, reviewed code by sha:** every engineering-artifact link (`Plan`, `Reports`, a designator's report anchor) carries `{ARTIFACT_PUBLISH_REF}`. Every citation of the reviewed code carries the reviewed head sha instead, as a permanent blob URL under the reviewed repository: diff --git a/work-package/techniques/manage-artifacts/TECHNIQUE.md b/work-package/techniques/manage-artifacts/TECHNIQUE.md index 93bb6524e..af8560420 100644 --- a/work-package/techniques/manage-artifacts/TECHNIQUE.md +++ b/work-package/techniques/manage-artifacts/TECHNIQUE.md @@ -1,6 +1,6 @@ --- metadata: - version: 3.4.0 + version: 3.5.0 --- ## Capability @@ -79,10 +79,6 @@ Specific, plain technical language: no vague descriptions ("various improvements Artifact filenames are prefixed with the server-provided `artifactPrefix`. Techniques declare bare names (e.g., `code-review.md`); the prefix is applied at write time (e.g., `09-code-review.md`). This groups related artifacts and sorts them in workflow order. -### committed-to-parent - -Planning artifacts are regular files in the parent repo (`.engineering/artifacts/`). They MUST be committed and pushed to the parent repo before any PR or issue references them via URL, otherwise the link will 404. - ### push-before-linking -Any engineering link included in a PR body (📐 Engineering) MUST resolve to a committed file on the remote. Commit and push the planning folder BEFORE creating or updating the PR. +Any engineering link — in a PR body (📐 Engineering), an issue, or a posted review — MUST resolve to a committed file on the remote, or the reader gets a 404. Commit and push the planning folder BEFORE writing a URL that points into it, via [manage-git](../manage-git/TECHNIQUE.md)::[artifact-commits](../manage-git/artifact-commits.md), which owns the checkout the commit lands in. diff --git a/work-package/techniques/publish-review-artifacts.md b/work-package/techniques/publish-review-artifacts.md deleted file mode 100644 index 14a3257eb..000000000 --- a/work-package/techniques/publish-review-artifacts.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -metadata: - version: 1.3.0 ---- - -## Capability - -Commit and push review-linked planning artifacts to the engineering-checkout ref the consolidated review links, emitting the publish ref for hyperlink construction. - -## Inputs - -### planning_folder_path - -Path to the planning folder whose artifacts the consolidated review links (`README.md`, report artifacts, `review-summary.md`). - -### host_repo_path - -Path to the product repo root (monorepo or standalone); the `.engineering/` artifacts directory sits under it. - -### publishing_activity - -Name recorded on the publish commit, identifying which activity's artifacts it carries. - -#### default - -`submit-for-review` - -## Outputs - -### artifact_publish_ref - -The engineering checkout's branch name — the ref engineering-artifact hyperlinks resolve against. - - -## Protocol - -1. Resolve `{$eng_git_dir}`: `{host_repo_path}/.engineering` when that path is a git checkout (submodule or nested clone); otherwise `{host_repo_path}`. Resolve `{$eng_branch}`: `git -C {eng_git_dir} branch --show-current` — never hardcode `main`. -2. Apply [manage-git::artifact-commits](./manage-git/artifact-commits.md) for ALL changed files under `{planning_folder_path}` (including `README.md`, linked report artifacts, `review-summary.md`, `session.json`, and `.session-token`) with `branch` = `{eng_branch}`, `activity_name` = `{publishing_activity}`, and `issue_key` = `{issue_number}`. That op stages, commits and pushes inside the engineering checkout, so the branch tip carries these artifacts. -3. Emit `{eng_branch}` as `{artifact_publish_ref}`. - -## Rules - -### publish-ref-is-a-branch - -The emitted ref is the branch, never a commit SHA. The planning folder keeps growing after a review is posted — close-out, retrospective, session trace and follow-ups all arrive later — so a reader following a branch link sees the current tree while a reader following a sha link sees the tree as it stood before those files existed. Re-running this op on a later activity refreshes the branch tip without changing any link already posted. diff --git a/work-package/techniques/resolve-artifact-publish.md b/work-package/techniques/resolve-artifact-publish.md new file mode 100644 index 000000000..9032f33f8 --- /dev/null +++ b/work-package/techniques/resolve-artifact-publish.md @@ -0,0 +1,43 @@ +--- +metadata: + version: 1.0.0 +--- + +## Capability + +Resolve the engineering checkout's publish branch and the planning-folder files that ride on it, for artifact hyperlink construction. + +## Inputs + +### planning_folder_path + +Path to the planning folder whose artifacts the consolidated review links (`README.md`, report artifacts, `review-summary.md`). + +### host_repo_path + +Path to the product repo root (monorepo or standalone); the `.engineering/` artifacts directory sits under it. + +## Outputs + +### artifact_publish_ref + +The engineering checkout's branch name — the ref engineering-artifact hyperlinks resolve against. + +### publishable_files + +Every changed file under `{planning_folder_path}`, including `README.md`, the linked report artifacts, `review-summary.md`, `session.json` and `.session-token`. + +## Protocol + +1. Resolve `{$eng_git_dir}`: `{host_repo_path}/.engineering` when that path is a git checkout (submodule or nested clone); otherwise `{host_repo_path}`. Resolve `{$eng_branch}`: `git -C {eng_git_dir} branch --show-current` — never hardcode `main`. +2. Collect every changed path under `{planning_folder_path}` as `{publishable_files}` (`git -C {eng_git_dir} status --porcelain` restricted to that folder), and emit `{eng_branch}` as `{artifact_publish_ref}`. + +## Rules + +### publish-ref-is-a-branch + +The emitted ref is the branch, never a commit SHA. The planning folder keeps growing after a review is posted — close-out, retrospective, session trace and follow-ups all arrive later — so a reader following a branch link sees the current tree while a reader following a sha link sees the tree as it stood before those files existed. Re-resolving on a later activity refreshes the branch tip without changing any link already posted. + +### resolve-before-linking + +The file set and the ref are resolved together, in that order, before any hyperlink carrying the ref is rendered. The commit that puts those files on that branch is a separate activity step — [manage-git](./manage-git/TECHNIQUE.md)::[artifact-commits](./manage-git/artifact-commits.md) — so a link is written only after the step that pushed its target has run ([push-before-linking](./manage-artifacts/TECHNIQUE.md#push-before-linking)). diff --git a/work-package/techniques/update-pr/TECHNIQUE.md b/work-package/techniques/update-pr/TECHNIQUE.md index 124e430e5..6fd70c27a 100644 --- a/work-package/techniques/update-pr/TECHNIQUE.md +++ b/work-package/techniques/update-pr/TECHNIQUE.md @@ -1,6 +1,6 @@ --- metadata: - version: 2.5.1 + version: 2.6.0 --- ## Capability @@ -73,7 +73,7 @@ Typical binds: `plan-prepare` → `initial`; `strategic-review` and `submit-for- - all-mandated-sections-present: Every section the selected pr-description template variant mandates is present in the rendered body as a literal heading. The mandated sections are defined in the resource — [Template (Initial)](../../resources/pr-description.md#template-initial) or [Template (Final)](../../resources/pr-description.md#template-final) — and are checked by name (e.g. `grep -F` each `## ` the template requires, plus the Issue/Engineering link row). Optional sections (`Migration Notes`, `Screenshots`) are never required. A missing mandated section is a finding naming that section — the intra-section rules below do not substitute for this check, since a body that omits a section passes them vacuously. - summary-max-two-sentences: Summary section is 1-2 sentences, leads with the outcome, and includes measurable impact when available. -- engineering-link-mandatory: Engineering link is present, resolved from the parent repo's `git remote get-url origin` and current `git branch --show-current`, and resolves to a committed file on the remote. +- engineering-link-mandatory: Engineering link is present, resolved from the remote and current branch of the checkout that holds the planning folder — never from the host repo's when that folder is a checkout of its own — and resolves to a committed file on the remote. [render](./render.md) step 3 owns that resolution. - issue-link-or-explicit-placeholder: Issue line is present. When `issue-skipped == true`, render `🐛 _Issue: skipped_` as an explicit placeholder rather than dropping the line or fabricating a number. - no-commit-headings-in-changes: Changes section groups bullets by component (bold component name), not by Conventional Commits header or commit message. - no-files-changed-list: Changes section does not enumerate file paths. File-level detail belongs in the PR's Files-changed tab. diff --git a/work-package/techniques/update-pr/create-pr.md b/work-package/techniques/update-pr/create-pr.md index 379bf10c1..e6a300ef6 100644 --- a/work-package/techniques/update-pr/create-pr.md +++ b/work-package/techniques/update-pr/create-pr.md @@ -32,7 +32,7 @@ URL to the PR ### 1. Prepare PR Inputs -- BEFORE creating the PR: honor [push-before-linking](../manage-artifacts/TECHNIQUE.md#push-before-linking) / [committed-to-parent](../manage-artifacts/TECHNIQUE.md#committed-to-parent) for `{planning_folder_path}`. +- BEFORE creating the PR: honor [push-before-linking](../manage-artifacts/TECHNIQUE.md#push-before-linking) for `{planning_folder_path}`. - Compose the PR title and body using the [Template (Initial)](../../resources/pr-description.md#template-initial). Reference `{issue_number}` per `{issue_platform}` (GitHub `#N` vs Jira `KEY-N`). ### 2. Create Draft PR diff --git a/work-package/workflow.yaml b/work-package/workflow.yaml index 819d29ce1..509a9325f 100644 --- a/work-package/workflow.yaml +++ b/work-package/workflow.yaml @@ -1,6 +1,6 @@ $schema: ../../schemas/workflow.schema.json id: work-package -version: 3.37.0 +version: 3.38.0 title: Work Package Implementation Workflow description: Defines how to plan and implement ONE work package from inception to merged PR. A work package is a discrete unit of work such as a feature, bug-fix, enhancement, refactoring, or any other deliverable change. For multiple related work packages, use the work-packages workflow to create a roadmap first. Also supports review mode for auditing an existing PR or implementation end-to-end. author: m2ux From e451dc06252f2924285105a651f3e3c48ec07027 Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Thu, 30 Jul 2026 14:15:53 +0100 Subject: [PATCH 2/7] fix(meta,work-package): close the audit findings on this change's own text The canon audit over the change surface found eight defects in prose this branch authored. Each is fixed here. resolve-before-linking named an activity step from inside a technique rule, scoped to one protocol phase, and restated push-before-linking's invariant; the step order and that rule already carry it, so it goes. The graph's markdown limit folds into query-not-grep rather than sitting beside it: a second rule about when to reach for the graph left the pair intersecting on markdown with opposite consequences and no ordering. The Cypher fragment goes with it, since raw queries live in the operations. infrastructure-submodule-paths is a rule, so it is cited by dotted address rather than the :: form that invokes a technique. The blockquote notes under step 5 gain the trailing spaces that fold them into their parent bullet. target_workflow_outcomes states what the value is, without the reader tail. The engineering planning root is enumerated once, in review-mode; pr-description glosses the slot without restating the arms or naming the step that resolves it. --- meta/techniques/gitnexus-operations/TECHNIQUE.md | 6 +----- meta/techniques/workflow-engine/commit-and-persist.md | 6 +++--- meta/workflow.yaml | 2 +- work-package/resources/pr-description.md | 2 +- work-package/techniques/resolve-artifact-publish.md | 4 ---- 5 files changed, 6 insertions(+), 14 deletions(-) diff --git a/meta/techniques/gitnexus-operations/TECHNIQUE.md b/meta/techniques/gitnexus-operations/TECHNIQUE.md index c5bb63ea2..8f070cb05 100644 --- a/meta/techniques/gitnexus-operations/TECHNIQUE.md +++ b/meta/techniques/gitnexus-operations/TECHNIQUE.md @@ -11,7 +11,7 @@ Codebase intelligence via the GitNexus knowledge graph — indexing, structural ### query-not-grep -Apply [query](./query.md) / [context](./context.md) for execution flows and relationships. Grep is for text patterns and string literals only — when structure matters, use GitNexus. +Apply [query](./query.md) / [context](./context.md) for execution flows and relationships among code symbols — that is what the graph holds. For a markdown tree it holds paths and no prose, so a question about which text states a claim is a grep question, and [query](./query.md) answers it with unrelated matches rather than nothing, which means a miss there does not read as a miss. Grep is also for text patterns and string literals in code. ### detect-changes-after-edit @@ -21,10 +21,6 @@ Always apply [detect-changes](./detect-changes.md) after applying a rename or ba Apply [verify-index](./verify-index.md) at the start of any GitNexus session, and again before any operation whose answer turns on the current tree — [impact](./impact.md), [detect-changes](./detect-changes.md), [orphan-scan](./orphan-scan.md), [diff-coverage-map](./diff-coverage-map.md). A stale index answers in the same shape as a fresh one and says nothing about its own age, so an unverified answer is indistinguishable from a correct one. -### graph-answers-code-not-prose - -The graph holds code symbols and file paths. For a markdown tree — `workflows/`, `docs/`, `.engineering/` — it locates a file by path but cannot answer which text states a claim, and [query](./query.md) returns unrelated matches rather than an empty result, so a miss does not read as a miss. Reach for the graph by path (a [cypher](./cypher.md) `f.filePath` match) or for code structure; read the prose with grep and Read. - ### keyword-shaped-queries Phrase [query](./query.md) as keywords, not as a natural-language question. Its ranking fuses keyword and semantic scoring, and the semantic half contributes only where the index carries embeddings — which is a property of how the repo was indexed, not something the query can assert. Keyword-shaped input is the phrasing that works either way. diff --git a/meta/techniques/workflow-engine/commit-and-persist.md b/meta/techniques/workflow-engine/commit-and-persist.md index 68b18c357..f1c6fcddb 100644 --- a/meta/techniques/workflow-engine/commit-and-persist.md +++ b/meta/techniques/workflow-engine/commit-and-persist.md @@ -28,9 +28,9 @@ Path to the planning folder. 2. Set the header-line `**Status:**` to the current lifecycle milestone for that workflow (text — distinct from Progress Status; see [Progress table](../../resources/planning-readme.md#progress-table)). 3. If the README already matches after steps 1–2, leave content equivalent — still include the file in the engineering commit below so a prior local-only edit is pushed. 4. If `{host_repo_path}/{component_path}` has uncommitted changes (`git status --porcelain` non-empty), apply [version-control](../version-control/TECHNIQUE.md)::[commit-submodule](../version-control/commit-submodule.md)(*paths*=changed files, *submodule_message*=`'(): source changes'` with the Conventional Commits type that fits the activity — feat for implement, fix for post-impl-review fixes, refactor for cleanup, *parent_branch*=current parent branch). Skip when the working tree is clean. -5. **Engineering commit + push:** Commit ALL changes under `.engineering/artifacts/` within `{planning_folder_path}`, including `README.md`, `session.json` and `.session-token`, with *message*=`docs(): artifacts`. The primitive follows the layout, resolved per [version-control](../version-control/TECHNIQUE.md)::[infrastructure-submodule-paths](../version-control/TECHNIQUE.md#infrastructure-submodule-paths). This post-activity hook **is** the commit request — do not wait for a separate user confirmation. Push must succeed before this operation returns: Engineering links and resume assume the remote holds the commit, so a local-only README or artifact update does not satisfy this step. - > When `.engineering` is a checkout of its own, apply [commit-submodule](../version-control/commit-submodule.md)(*submodule_path*=`.engineering`) — its own branch and remote carry the artifacts. - > Otherwise apply [commit-regular-files](../version-control/commit-regular-files.md) — the artifacts are ordinary files of the host checkout. +5. **Engineering commit + push:** Commit ALL changes under `.engineering/artifacts/` within `{planning_folder_path}`, including `README.md`, `session.json` and `.session-token`, with *message*=`docs(): artifacts`. The primitive follows the layout, classified by `version-control.infrastructure-submodule-paths`. This post-activity hook **is** the commit request — do not wait for a separate user confirmation. Push must succeed before this operation returns: Engineering links and resume assume the remote holds the commit, so a local-only README or artifact update does not satisfy this step. + > When `.engineering` is a checkout of its own, apply [commit-submodule](../version-control/commit-submodule.md)(*submodule_path*=`.engineering`) — its own branch and remote carry the artifacts. + > Otherwise apply [commit-regular-files](../version-control/commit-regular-files.md) — the artifacts are ordinary files of the host checkout. > Where the host branch accepts changes only through pull requests, the parent's submodule-pointer bump lands in a PR; a direct push to that branch is refused, and the engineering push above already satisfies this step without it. 6. Confirm the engineering push landed (remote tracking branch includes the new commit). If push failed, retry once; if still failing, surface the error and do not advance to the next activity. diff --git a/meta/workflow.yaml b/meta/workflow.yaml index 288227445..05a17b1a9 100644 --- a/meta/workflow.yaml +++ b/meta/workflow.yaml @@ -53,7 +53,7 @@ variables: defaultValue: false - name: target_workflow_outcomes type: string - description: The client workflow's own outcome list, seeded in its bag, read by verify-outcomes during end-workflow close-out + description: The client workflow's own outcome list, seeded in its bag - name: workflow_match_ambiguous type: boolean description: Whether the user request matched multiple workflows — gates the workflow-selection checkpoint in discover-session diff --git a/work-package/resources/pr-description.md b/work-package/resources/pr-description.md index 7b1e3f9a9..2d7160f8e 100644 --- a/work-package/resources/pr-description.md +++ b/work-package/resources/pr-description.md @@ -143,7 +143,7 @@ Optional sections (add when applicable): `## Migration Notes` (required steps fo 🐛 [Issue]({TARGET_REPO_URL}/issues/{GITHUB_ISSUE_NUMBER}) 📐 [Engineering]({ENG_REPO_URL}/blob/{ENG_BRANCH}/{ENG_PLANNING_PATH}/{PLANNING_FOLDER}/README.md) ``` -`{ENG_PLANNING_PATH}` is the planning root relative to the root of the checkout `{ENG_BRANCH}` belongs to: `artifacts/planning` when `.engineering/` is a checkout of its own, and `.engineering/artifacts/planning` when the artifacts live directly in the host checkout. The rendering step resolves which, alongside the ref itself. +`{ENG_PLANNING_PATH}` is the planning root relative to the root of the checkout `{ENG_BRANCH}` belongs to, so it carries the `.engineering/` segment only when the artifacts live directly in that checkout. **Issue-skipped placeholder** (when `issue_skipped == true` — the line is rendered, italicised, no link, so reviewers can tell the omission was intentional): diff --git a/work-package/techniques/resolve-artifact-publish.md b/work-package/techniques/resolve-artifact-publish.md index 9032f33f8..2d9d5cbea 100644 --- a/work-package/techniques/resolve-artifact-publish.md +++ b/work-package/techniques/resolve-artifact-publish.md @@ -37,7 +37,3 @@ Every changed file under `{planning_folder_path}`, including `README.md`, the li ### publish-ref-is-a-branch The emitted ref is the branch, never a commit SHA. The planning folder keeps growing after a review is posted — close-out, retrospective, session trace and follow-ups all arrive later — so a reader following a branch link sees the current tree while a reader following a sha link sees the tree as it stood before those files existed. Re-resolving on a later activity refreshes the branch tip without changing any link already posted. - -### resolve-before-linking - -The file set and the ref are resolved together, in that order, before any hyperlink carrying the ref is rendered. The commit that puts those files on that branch is a separate activity step — [manage-git](./manage-git/TECHNIQUE.md)::[artifact-commits](./manage-git/artifact-commits.md) — so a link is written only after the step that pushed its target has run ([push-before-linking](./manage-artifacts/TECHNIQUE.md#push-before-linking)). From c3b7ec2f1099b98c945fdda9ecc6dba7c4d3ab5f Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Thu, 30 Jul 2026 14:35:03 +0100 Subject: [PATCH 3/7] fix(meta,work-package): cite the home, not its step number A rule that points into a Protocol by position rots on the next renumber, and the invariant it carries does not need the position: commit-after-activity constrains which scopes must be committed and pushed before transitions, and which primitive each scope takes is what the Protocol phases are for. The parentheticals naming the primitives come out with the positional reference. agent-conduct and engineering-link-mandatory cite the technique that owns each resolution, without the phase number. sync-progress-status gains the hyperlink that resolves in place of the phase it sat in. --- meta/techniques/agent-conduct.md | 2 +- meta/techniques/workflow-engine/commit-and-persist.md | 2 +- work-package/techniques/update-pr/TECHNIQUE.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/meta/techniques/agent-conduct.md b/meta/techniques/agent-conduct.md index b2ace20b7..6992f26fe 100644 --- a/meta/techniques/agent-conduct.md +++ b/meta/techniques/agent-conduct.md @@ -95,7 +95,7 @@ On resume, still dispatch a worker via [dispatch-activity](./workflow-engine/dis ### orchestrator-component-path-scope -Branch creation, PR creation, and code commits MUST be performed inside the component directory (the submodule), NEVER in the host monorepo root. Planning artifact commits (`.engineering/artifacts/`) land on the current branch of the checkout that holds that directory — which checkout that is, and the primitive it takes, are resolved by [commit-and-persist](./workflow-engine/commit-and-persist.md) step 5. Do NOT create a new branch for them. +Branch creation, PR creation, and code commits MUST be performed inside the component directory (the submodule), NEVER in the host monorepo root. Planning artifact commits (`.engineering/artifacts/`) land on the current branch of the checkout that holds that directory — which checkout that is, and the primitive it takes, are resolved by [commit-and-persist](./workflow-engine/commit-and-persist.md). Do NOT create a new branch for them. ### orchestrator-automatic-transitions diff --git a/meta/techniques/workflow-engine/commit-and-persist.md b/meta/techniques/workflow-engine/commit-and-persist.md index f1c6fcddb..08c1ba5b7 100644 --- a/meta/techniques/workflow-engine/commit-and-persist.md +++ b/meta/techniques/workflow-engine/commit-and-persist.md @@ -38,7 +38,7 @@ Path to the planning folder. ### commit-after-activity -After every completed activity, BOTH source-side changes (under `{host_repo_path}/{component_path}`, via [commit-submodule](../version-control/commit-submodule.md)) AND engineering artifacts (under `.engineering/artifacts/`, via the primitive step 5 resolves for the layout) MUST be committed and **pushed** before evaluating transitions to the next activity. Skipping either scope leaves a dirty or remote-stale tree that breaks resume, Engineering links, and downstream activities. The submodule commit may be skipped only when the working tree at `{host_repo_path}/{component_path}` is clean. The engineering commit may be skipped only when the planning folder has no local changes **and** README Progress Status for `{activity_id}` already shows the intended post-activity status on the remote (complete, or cancelled/N/A when `{mark_progress_na}` applied) per [Status vocabulary](../../resources/planning-readme.md#status-vocabulary) — otherwise Apply sync-progress-status (step 1) then commit and push. Scope: this orchestrator post-activity hook only — distinct from [explicit-commit](../version-control/TECHNIQUE.md#explicit-commit), which governs ad-hoc commits outside this hook. +After every completed activity, BOTH source-side changes (under `{host_repo_path}/{component_path}`) AND engineering artifacts (under `.engineering/artifacts/`) MUST be committed and **pushed** before evaluating transitions to the next activity. Skipping either scope leaves a dirty or remote-stale tree that breaks resume, Engineering links, and downstream activities. The submodule commit may be skipped only when the working tree at `{host_repo_path}/{component_path}` is clean. The engineering commit may be skipped only when the planning folder has no local changes **and** README Progress Status for `{activity_id}` already shows the intended post-activity status on the remote (complete, or cancelled/N/A when `{mark_progress_na}` applied) per [Status vocabulary](../../resources/planning-readme.md#status-vocabulary) — otherwise Apply [sync-progress-status](./sync-progress-status.md) then commit and push. Scope: this orchestrator post-activity hook only — distinct from [explicit-commit](../version-control/TECHNIQUE.md#explicit-commit), which governs ad-hoc commits outside this hook. ### readme-progress-before-persist diff --git a/work-package/techniques/update-pr/TECHNIQUE.md b/work-package/techniques/update-pr/TECHNIQUE.md index 6fd70c27a..c9301a8bc 100644 --- a/work-package/techniques/update-pr/TECHNIQUE.md +++ b/work-package/techniques/update-pr/TECHNIQUE.md @@ -73,7 +73,7 @@ Typical binds: `plan-prepare` → `initial`; `strategic-review` and `submit-for- - all-mandated-sections-present: Every section the selected pr-description template variant mandates is present in the rendered body as a literal heading. The mandated sections are defined in the resource — [Template (Initial)](../../resources/pr-description.md#template-initial) or [Template (Final)](../../resources/pr-description.md#template-final) — and are checked by name (e.g. `grep -F` each `## ` the template requires, plus the Issue/Engineering link row). Optional sections (`Migration Notes`, `Screenshots`) are never required. A missing mandated section is a finding naming that section — the intra-section rules below do not substitute for this check, since a body that omits a section passes them vacuously. - summary-max-two-sentences: Summary section is 1-2 sentences, leads with the outcome, and includes measurable impact when available. -- engineering-link-mandatory: Engineering link is present, resolved from the remote and current branch of the checkout that holds the planning folder — never from the host repo's when that folder is a checkout of its own — and resolves to a committed file on the remote. [render](./render.md) step 3 owns that resolution. +- engineering-link-mandatory: Engineering link is present, resolved from the remote and current branch of the checkout that holds the planning folder — never from the host repo's when that folder is a checkout of its own — and resolves to a committed file on the remote. [render](./render.md) owns that resolution. - issue-link-or-explicit-placeholder: Issue line is present. When `issue-skipped == true`, render `🐛 _Issue: skipped_` as an explicit placeholder rather than dropping the line or fabricating a number. - no-commit-headings-in-changes: Changes section groups bullets by component (bold component name), not by Conventional Commits header or commit message. - no-files-changed-list: Changes section does not enumerate file paths. File-level detail belongs in the PR's Files-changed tab. From 2009d76a1791887163ef4ab7bd3d9e16730f5aa7 Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Thu, 30 Jul 2026 14:37:44 +0100 Subject: [PATCH 4/7] feat(canon): catalogue phase-cited-by-ordinal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A rule pointing at a Protocol phase by its number sits in a seam four entries leave open. no-rule-protocol-restatement tests whether the sentence could stand as a phase unaltered, and a pointer to a phase cannot. dotted-rule-address governs how a rule is addressed, not how a phase is. anchored-protocol-references asks whether a reference resolves, and an ordinal does resolve — to whichever phase now holds that index. stale-restatement-after-change catches it only once a renumber has already made the claim false. So the entry keys on the ordinal itself, with the insert-a-phase test, and carves out the numbering's own Protocol, heading anchors that fail a guard instead of drifting, and rules addressed by name. The workflow-design version stays where it is: the deprecated tree prints a mismatch warning to every session still running against it (#339). --- workflow-design/resources/anti-patterns.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/workflow-design/resources/anti-patterns.md b/workflow-design/resources/anti-patterns.md index 1518d4fd7..e74f0090a 100644 --- a/workflow-design/resources/anti-patterns.md +++ b/workflow-design/resources/anti-patterns.md @@ -1780,3 +1780,15 @@ Protocol restates a tool parameter's shape, which the tool's own schema already **Do not flag:** The call signature naming which arguments a step passes (`next_activity { session_index, activity_id, step_manifest }`) — that is routing, not shape. What the caller does with the response. A workflow-specific constraint on an argument's *value* rather than its form, such as relaying a worker's map verbatim; and an obligation the schema cannot express, such as which dispatches must carry the argument at all. **Fix:** Keep the obligation and the reason; drop the shape. The schema is its one home ([Match the Harness Surface](./design-principles.md#21-match-the-harness-surface), [One Authoritative Home](./design-principles.md#6-one-authoritative-home)), and a restatement drifts from it — a Protocol bullet describing "two string fields" contradicts a schema that also accepts a keyed object for multi-output steps, and the caller cannot tell which governs. + +### AP-136. phase-cited-by-ordinal + +"the primitive step 5 resolves for the layout" / "[render](./render.md) step 3 owns that resolution" + +A durable reference identifies a Protocol phase by its position, so it keeps resolving after a renumber and points at work it no longer names. + +**Detect:** A rule, I/O description, Capability, resource body, README, or another technique's Protocol cites a phase of some `## Protocol` by ordinal — "step N", "phase N", "the Nth step" — rather than by the technique or op that owns it. An ordinal is not a symbol: it survives insertion, deletion and reordering by silently addressing whichever phase now holds that index, so the claim goes false with nothing failing. Test: insert one phase above the cited one and re-read the citing sentence; if it now names the wrong work, flag it. + +**Do not flag:** Ordinals inside the same `## Protocol` that owns the numbering, where the phases and the reference move in one edit. A link to the phase's heading anchor, which fails a guard rather than drifting when the heading changes. Rules cited by dotted address — a rule name is not a position (`dotted-rule-address`). An ordinal that is part of a declared id, heading text, or quoted output rather than a citation. + +**Fix:** Cite the owner, not the index — name the technique or op holding the phase and let the reader find it there; anchor the heading where the citation genuinely needs that one phase. Where the pointer exists only to explain how the cited work happens, the citing invariant rarely needs it: delete the pointer and keep the constraint. See also `no-rule-protocol-restatement`, `anchored-protocol-references`, `stale-restatement-after-change`. From 17d3c1e873966e13398c60a405cdccc8aff75351 Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Thu, 30 Jul 2026 14:53:19 +0100 Subject: [PATCH 5/7] feat(meta): one operation owns the session read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading the live session had no owner. verify-outcomes and generate-summary each named inspect_session and each enumerated the views it accepts, and two work-package techniques cited those two as their home — a citation pointing sideways at fellow callers, which is what an author writes when no operation owns the capability. workflow-engine::read-session owns it now, declaring the variable bag and the execution trace as its products and naming the tool once. The activities bind it ahead of its consumers, so verify-outcomes, generate-summary, retrospective and select-next declare what they read and take it by name. That also repairs #320 C-2 properly. The unproduced state and trace bindings were not contract fiction to delete: the inputs were right and the producer was missing. session_state replaces the bare state id on the way through. --- meta/activities/04-end-workflow.yaml | 5 ++- .../workflow-engine/generate-summary.md | 9 ++++-- .../workflow-engine/read-session.md | 32 +++++++++++++++++++ .../workflow-engine/verify-outcomes.md | 13 ++++++-- meta/workflow.yaml | 2 +- work-package/activities/14-complete.yaml | 5 ++- .../conduct-retrospective/retrospective.md | 8 +++-- .../conduct-retrospective/select-next.md | 8 +++-- work-package/workflow.yaml | 2 +- 9 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 meta/techniques/workflow-engine/read-session.md diff --git a/meta/activities/04-end-workflow.yaml b/meta/activities/04-end-workflow.yaml index 6b7d5f0ad..a24a80b37 100644 --- a/meta/activities/04-end-workflow.yaml +++ b/meta/activities/04-end-workflow.yaml @@ -1,9 +1,12 @@ id: end-workflow -version: 4.3.0 +version: 4.4.0 name: End Workflow description: Close out the client workflow. required: true steps: + - kind: technique + id: read-session + technique: workflow-engine::read-session - kind: technique id: verify-outcomes technique: diff --git a/meta/techniques/workflow-engine/generate-summary.md b/meta/techniques/workflow-engine/generate-summary.md index 90ef49ceb..a56f85ab0 100644 --- a/meta/techniques/workflow-engine/generate-summary.md +++ b/meta/techniques/workflow-engine/generate-summary.md @@ -1,6 +1,6 @@ --- metadata: - version: 1.1.0 + version: 1.2.0 --- ## Capability @@ -13,6 +13,10 @@ Compose the markdown session summary presented at workflow close. Workflow definition (id, title, outcomes) +### execution_trace + +Completed activities, checkpoint decisions, and artifacts produced. + ## Outputs ### completion_summary @@ -21,8 +25,7 @@ Workflow definition (id, title, outcomes) ## Protocol -1. Resolve `{$execution_trace}`: the session's completed activities, checkpoint decisions and artifacts produced. Draw from `{execution_trace}` to compose the summary sections: workflow id and title, start/completion timestamps, activities completed, key checkpoint decisions, artifacts with paths, outcomes satisfied vs. unmet, follow-up items. Return the assembled markdown as `{completion_summary}`. - > Obtain `{execution_trace}` through the `inspect_session` tool — `view: activities` for completed activities, `view: checkpoints` for checkpoint decisions, `view: history` for the event trace, or `view: summary` for all of it — rather than reading `session.json` directly. It is resolved here, never supplied by a caller. +1. Draw from `{execution_trace}` to compose the summary sections: workflow id and title, start/completion timestamps, activities completed, key checkpoint decisions, artifacts with paths, outcomes satisfied vs. unmet, follow-up items. Return the assembled markdown as `{completion_summary}`. ## Rules diff --git a/meta/techniques/workflow-engine/read-session.md b/meta/techniques/workflow-engine/read-session.md new file mode 100644 index 000000000..470a3436d --- /dev/null +++ b/meta/techniques/workflow-engine/read-session.md @@ -0,0 +1,32 @@ +--- +metadata: + version: 1.0.0 +--- + +## Capability + +The live session record — its variable bag and its execution trace — for a consumer that reasons over what the session has actually done. + +## Outputs + +### session_state + +The session's variable bag as the server holds it. + +### execution_trace + +Completed activities, checkpoint decisions, artifacts produced, and the event history behind them. + +## Protocol + +1. Read the session through the `inspect_session` tool: `view: variables` yields `{session_state}`; `view: activities`, `view: checkpoints` and `view: history` each yield a slice of `{execution_trace}`, and `view: summary` yields both products in one call. + +## Rules + +### session-file-is-not-a-source + +The session file on disk is the server's own store, not a read surface: it may be sealed, and it lags a call still in flight. Every consumer of the two products above takes them from this operation, so one contract governs what a session read returns. + +### trace-is-not-the-only-witness + +A worker's `activity_complete` envelope holds ground truth from its own user interaction, so where the record and a just-completed envelope disagree on a value an orchestrator decision rests on, apply [dispatch-activity](./dispatch-activity.md#distrust-then-reconcile). diff --git a/meta/techniques/workflow-engine/verify-outcomes.md b/meta/techniques/workflow-engine/verify-outcomes.md index 62aef0562..9432e3540 100644 --- a/meta/techniques/workflow-engine/verify-outcomes.md +++ b/meta/techniques/workflow-engine/verify-outcomes.md @@ -1,6 +1,6 @@ --- metadata: - version: 1.3.0 + version: 1.4.0 --- ## Capability @@ -13,6 +13,14 @@ Compare a workflow's declared `outcomes` against state and identify gaps. Array of expected outcome strings to evaluate. +### session_state + +The session's variable bag. + +### execution_trace + +Completed activities and the event history behind them. + ## Outputs ### gaps @@ -22,5 +30,4 @@ Array of unsatisfied outcomes ## Protocol 1. Resolve the outcome list to evaluate: prefer a non-empty `{outcomes}` binding when supplied; otherwise fall back to the calling activity's declared `outcome:` list. Outcome strings are plain declarative prose — never encode or parse conditional predicates inside them. When a producing step was structurally gated out on the path taken, skip the outcomes that step would have satisfied rather than reporting them as unmet gaps. -2. Resolve `{$state}`: the session's variables and completed-activities trace. For each entry in that list, evaluate satisfaction against `{state}`'s variables, artifact presence in `planning_folder_path`, and its completed-activities trace; collect every unmet item into `{gaps}`. - > Read `{state}` through the `inspect_session` tool (`view: variables` and `view: activities`, or `view: summary` for both) rather than reading `session.json` directly. It is resolved here, never supplied by a caller — an orchestrator holding a stale copy of the bag is the disagreement the reconcile stance below exists for. When `inspect_session` disagrees with a just-completed worker envelope for a critical path, prefer the envelope and planning-folder evidence (same reconcile stance as [dispatch-activity](./dispatch-activity.md#distrust-then-reconcile)). +2. For each entry in that list, evaluate satisfaction against `{session_state}`, artifact presence in `planning_folder_path`, and `{execution_trace}`; collect every unmet item into `{gaps}`. diff --git a/meta/workflow.yaml b/meta/workflow.yaml index 05a17b1a9..ce39ab368 100644 --- a/meta/workflow.yaml +++ b/meta/workflow.yaml @@ -1,6 +1,6 @@ $schema: ../../schemas/workflow.schema.json id: meta -version: 5.13.0 +version: 5.14.0 title: Meta Workflow description: Top-level lifecycle workflow that orchestrates client workflow sessions. Excluded from list_workflows — bootstrap navigates here directly. author: m2ux diff --git a/work-package/activities/14-complete.yaml b/work-package/activities/14-complete.yaml index a8c43b1f7..e2da7ebf8 100644 --- a/work-package/activities/14-complete.yaml +++ b/work-package/activities/14-complete.yaml @@ -1,5 +1,5 @@ id: complete -version: 1.8.0 +version: 1.9.0 name: Complete Work Package description: Wrap up the work package after PR merge (or after review-mode close-out). required: true @@ -66,6 +66,9 @@ steps: variable: is_review_mode operator: "!=" value: true + - kind: technique + id: read-session + technique: workflow-engine::read-session - kind: technique id: conduct-retrospective technique: conduct-retrospective::retrospective diff --git a/work-package/techniques/conduct-retrospective/retrospective.md b/work-package/techniques/conduct-retrospective/retrospective.md index 6ea8c780f..741fbfd31 100644 --- a/work-package/techniques/conduct-retrospective/retrospective.md +++ b/work-package/techniques/conduct-retrospective/retrospective.md @@ -1,6 +1,6 @@ --- metadata: - version: 1.4.0 + version: 1.5.0 --- ## Capability @@ -25,6 +25,10 @@ Path to the planning folder where the final outcome, session-trace, and retrospe *(optional)* Opaque trace tokens accumulated across the run. +### execution_trace + +Completed activities, checkpoint decisions, and the event history behind them. + ## Outputs ### retrospective_document @@ -44,7 +48,7 @@ Lean mechanical summary of resolved trace events (dispatch counts, tool counts, ### 1. Capture History -- If metadata repository exists, capture session history via `inspect_session` (same stance as [generate-summary](../../../meta/techniques/workflow-engine/generate-summary.md) / [verify-outcomes](../../../meta/techniques/workflow-engine/verify-outcomes.md) — not by reading `session.json`). +- If metadata repository exists, capture session history from `{execution_trace}`. ### 2. Resolve Session Trace diff --git a/work-package/techniques/conduct-retrospective/select-next.md b/work-package/techniques/conduct-retrospective/select-next.md index bef896df3..782d47b36 100644 --- a/work-package/techniques/conduct-retrospective/select-next.md +++ b/work-package/techniques/conduct-retrospective/select-next.md @@ -1,6 +1,6 @@ --- metadata: - version: 1.0.0 + version: 1.1.0 --- ## Capability @@ -13,6 +13,10 @@ Identify the next work package and prepare context for the transition. Path to the current work package's planning folder, read for follow-up items and carried context that inform what the next work package should be. +### execution_trace + +*(optional)* Completed activities and the event history behind them. + ## Outputs ### next_work_package_context @@ -24,4 +28,4 @@ The identified next work package (when applicable) together with the context pre ### 1. Select Next - Identify next work package if applicable. -- Prepare context for transition. When carried context depends on session record, use `inspect_session` per [generate-summary](../../../meta/techniques/workflow-engine/generate-summary.md) / [verify-outcomes](../../../meta/techniques/workflow-engine/verify-outcomes.md). +- Prepare context for transition. Carried context that depends on the session record comes from `{execution_trace}`. diff --git a/work-package/workflow.yaml b/work-package/workflow.yaml index 509a9325f..49d588b44 100644 --- a/work-package/workflow.yaml +++ b/work-package/workflow.yaml @@ -1,6 +1,6 @@ $schema: ../../schemas/workflow.schema.json id: work-package -version: 3.38.0 +version: 3.39.0 title: Work Package Implementation Workflow description: Defines how to plan and implement ONE work package from inception to merged PR. A work package is a discrete unit of work such as a feature, bug-fix, enhancement, refactoring, or any other deliverable change. For multiple related work packages, use the work-packages workflow to create a roadmap first. Also supports review mode for auditing an existing PR or implementation end-to-end. author: m2ux From 6989d0e431f6ac2ea38c9d85adcc06e5d919074d Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Thu, 30 Jul 2026 14:53:27 +0100 Subject: [PATCH 6/7] feat(canon): catalogue unowned-harness-capability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three entries assume the wrapping operation already exists. canonical-technique-reference fires when a raw tool is named where a wrapper exists; duplicate-shared-capability carves out the case where no shared capability exists yet; and no-duplicated-guidance says to keep one home and reference it, which is satisfied by referencing a fellow consumer — the state this catalogue entry was written from, where two techniques cited two others that also called the tool. So the entry keys on the absence: one tool named for one capability at two or more sites with no operation declaring that capability's product. Its test asks the reader to name the operation a caller would bind, and the sideways citation is the written tell. --- workflow-design/resources/anti-patterns.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/workflow-design/resources/anti-patterns.md b/workflow-design/resources/anti-patterns.md index e74f0090a..2fcba7ebf 100644 --- a/workflow-design/resources/anti-patterns.md +++ b/workflow-design/resources/anti-patterns.md @@ -1792,3 +1792,15 @@ A durable reference identifies a Protocol phase by its position, so it keeps res **Do not flag:** Ordinals inside the same `## Protocol` that owns the numbering, where the phases and the reference move in one edit. A link to the phase's heading anchor, which fails a guard rather than drifting when the heading changes. Rules cited by dotted address — a rule name is not a position (`dotted-rule-address`). An ordinal that is part of a declared id, heading text, or quoted output rather than a citation. **Fix:** Cite the owner, not the index — name the technique or op holding the phase and let the reader find it there; anchor the heading where the citation genuinely needs that one phase. Where the pointer exists only to explain how the cited work happens, the citing invariant rarely needs it: delete the pointer and keep the constraint. See also `no-rule-protocol-restatement`, `anchored-protocol-references`, `stale-restatement-after-change`. + +### AP-137. unowned-harness-capability + +"capture session history via `inspect_session` (same stance as [generate-summary] / [verify-outcomes])" + +Several techniques reach a harness capability directly because no operation owns it, so each re-derives the call and the newest cites a fellow caller as though a caller were a home. + +**Detect:** One harness/MCP tool is named for the same capability in two or more technique bodies, and no operation in the tree declares that capability's product as its own Outputs. Signals: the tool's permitted argument values enumerated at more than one site; a citation whose target is another *consumer* of the tool rather than an owner of the capability — the bridge phrasings `single-rule-authority` lists, pointing sideways. Test: name the operation a caller would bind to obtain the value. If no file answers, the capability is unowned and every site is a private re-derivation that drifts on its own. + +**Do not flag:** A single call site — one consumer is not duplication, and inventing a wrapper against a hypothetical second is premature (`duplicate-shared-capability`). Sites that already bind or Apply a wrapping op, and the wrapper itself, where naming the tool is the point (`canonical-technique-reference`). Surfaces whose domain is the harness — engine, conduct, bootstrap and agent-entry prompts. Distinct callers of one tool for genuinely different capabilities. + +**Fix:** Author the operation that owns the capability, declaring its product on `## Outputs`; bind it as an activity step ahead of its consumers and let them declare that product as an input — never a Protocol `Apply` from each consumer (`pass-orchestration-in-technique`). Repoint every sideways citation at the owner. See also `no-duplicated-guidance`, `tool-contract-restated-in-protocol`. From 7c964e45a93cd5ec2eaa30147eef32ebab0f8f3a Mon Sep 17 00:00:00 2001 From: Mike Clay Date: Thu, 30 Jul 2026 15:09:57 +0100 Subject: [PATCH 7/7] refactor(work-package): the pr-description guide owns what a conforming body is MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pr-body-conformance held seven criteria describing the shape of a rendered PR body, inside a technique's Rules. One of them restated a form the guide already carried: the Issue-skipped placeholder, rationale and all, was written out in both files. The criteria are fill rules for a generated document, and that document already has a creation guide, so the guide is where they live — one `###` per criterion, each citable by anchor. The technique keeps the rule name its walker and its two variables reference, now stating the obligation and citing the home. verify-body stops re-authoring the mandated-sections check and cites it instead, which is the split it already had for the templates. render cites the placeholder form rather than a rule that described it. Nothing about the verdict changes: verify-body still emits body_conforms and body_findings, and activity 13 still loops on them. --- work-package/resources/pr-description.md | 34 ++++++++++++++++++- .../techniques/update-pr/TECHNIQUE.md | 10 ++---- work-package/techniques/update-pr/render.md | 2 +- .../techniques/update-pr/verify-body.md | 8 ++--- work-package/workflow.yaml | 6 ++-- 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/work-package/resources/pr-description.md b/work-package/resources/pr-description.md index 2d7160f8e..b24cc2c2d 100644 --- a/work-package/resources/pr-description.md +++ b/work-package/resources/pr-description.md @@ -2,7 +2,7 @@ name: pr-description description: PR description templates and link-row rendering forms. metadata: - version: 1.7.0 + version: 1.8.0 order: 12 legacy_id: 12 --- @@ -158,3 +158,35 @@ _Jira: [{JIRA_ISSUE_KEY}](https://{JIRA_DOMAIN}/browse/{JIRA_ISSUE_KEY})_ ``` ADR and test-plan links are added to the row when those artifacts exist (see [architecture-review](architecture-review.md), [test-plan](test-plan.md)). + +## Rules + +Conformance criteria for a rendered body. Each is evaluated against the rendered text and yields one finding per failure, named by its heading here. + +### Mandated sections present + +Every section the selected template variant mandates appears in the rendered body as a literal heading, checked by name — each `## ` the variant requires, plus the Issue and Engineering link row. `Migration Notes` and `Screenshots` are never required. A missing section is a finding naming that section, and the per-section criteria below do not substitute for this one: a body that omits a section passes them vacuously. + +### Summary length + +The Summary section is one or two sentences, leads with the outcome, and carries measurable impact where a figure is known. + +### Engineering link present + +The Engineering link is present and resolves to a committed file on the remote. Its ref and repository come from the checkout holding the planning folder, never from the host repo's when that folder is a checkout of its own. + +### Issue line present + +The Issue line is present. When `issue_skipped` is true it renders the [Issue-skipped placeholder](#link-row-forms) rather than dropping the line or carrying a fabricated number. + +### Changes grouped by component + +The Changes section groups bullets by component, the component name in bold — not by Conventional Commits header and not by commit message. + +### Changes carry no file list + +The Changes section does not enumerate file paths. File-level detail is already in the PR's Files-changed tab. + +### Changes carry no code + +The Changes section is plain-language bullets saying what changed and why: no fenced blocks, no snippets, no pasted signatures, and no inline code beyond an unavoidable bare identifier. The diff is the source of truth for code. diff --git a/work-package/techniques/update-pr/TECHNIQUE.md b/work-package/techniques/update-pr/TECHNIQUE.md index c9301a8bc..c712954f7 100644 --- a/work-package/techniques/update-pr/TECHNIQUE.md +++ b/work-package/techniques/update-pr/TECHNIQUE.md @@ -1,6 +1,6 @@ --- metadata: - version: 2.6.0 + version: 2.7.0 --- ## Capability @@ -71,13 +71,7 @@ Typical binds: `plan-prepare` → `initial`; `strategic-review` and `submit-for- ### pr-body-conformance -- all-mandated-sections-present: Every section the selected pr-description template variant mandates is present in the rendered body as a literal heading. The mandated sections are defined in the resource — [Template (Initial)](../../resources/pr-description.md#template-initial) or [Template (Final)](../../resources/pr-description.md#template-final) — and are checked by name (e.g. `grep -F` each `## ` the template requires, plus the Issue/Engineering link row). Optional sections (`Migration Notes`, `Screenshots`) are never required. A missing mandated section is a finding naming that section — the intra-section rules below do not substitute for this check, since a body that omits a section passes them vacuously. -- summary-max-two-sentences: Summary section is 1-2 sentences, leads with the outcome, and includes measurable impact when available. -- engineering-link-mandatory: Engineering link is present, resolved from the remote and current branch of the checkout that holds the planning folder — never from the host repo's when that folder is a checkout of its own — and resolves to a committed file on the remote. [render](./render.md) owns that resolution. -- issue-link-or-explicit-placeholder: Issue line is present. When `issue-skipped == true`, render `🐛 _Issue: skipped_` as an explicit placeholder rather than dropping the line or fabricating a number. -- no-commit-headings-in-changes: Changes section groups bullets by component (bold component name), not by Conventional Commits header or commit message. -- no-files-changed-list: Changes section does not enumerate file paths. File-level detail belongs in the PR's Files-changed tab. -- no-code-in-changes: Changes section is plain-language summary bullets describing what changed and why; no fenced code blocks, code snippets, or pasted signatures, and no inline code beyond unavoidable bare identifiers. The diff is the source of truth for code. +A rendered body satisfies every criterion in [Rules](../../resources/pr-description.md#rules), which is their home — the guide that lays out the body owns what a conforming body looks like. Each failure is one finding named by the criterion it breaks. ### draft-first diff --git a/work-package/techniques/update-pr/render.md b/work-package/techniques/update-pr/render.md index 33a93b1bb..5e216db35 100644 --- a/work-package/techniques/update-pr/render.md +++ b/work-package/techniques/update-pr/render.md @@ -52,5 +52,5 @@ The rendered PR description body now live on the `{pr_number}` PR — composed f - `{$target_repo_url}`: `git -C {target_path} remote get-url origin`, strip the `.git` suffix, convert SSH form to HTTPS (`git@github.com:org/repo.git` → `https://github.com/org/repo`). - `{$eng_repo_url}`: same remote commands against `{eng_git_dir}`. Target and engineering remotes may differ. - `{$eng_branch}`: `git -C {eng_git_dir} branch --show-current` — do NOT assume `main`; planning artifacts may live on another branch. When `{eng_git_dir}` is `{host_repo_path}`, the Engineering link path includes `/.engineering/artifacts/planning/…`; when `{eng_git_dir}` is the eng checkout itself, the path is `/artifacts/planning/…` relative to that remote. The link must resolve to a committed file on the remote (manage-artifacts.push-before-linking). -4. Compose the link row per the [link-row forms](../../resources/pr-description.md#link-row-forms): the Issue link always present, pointing at the GitHub issue in the target repo via the `github_issue_number` variable — never the Jira key, never a guessed number; when `issue_skipped` is true, render the literal `🐛 _Issue: skipped_` placeholder per `rules.pr-body-conformance.issue-link-or-explicit-placeholder`. The Engineering link is always present on the same line. When `issue_platform` is `jira` and a `jira_issue_key` was captured, append the Jira ticket as the secondary reference line. Add ADR and test-plan links when those artifacts exist. +4. Compose the link row per the [link-row forms](../../resources/pr-description.md#link-row-forms): the Issue link always present, pointing at the GitHub issue in the target repo via the `github_issue_number` variable — never the Jira key, never a guessed number; when `issue_skipped` is true, render the [Issue-skipped placeholder](../../resources/pr-description.md#link-row-forms). The Engineering link is always present on the same line. When `issue_platform` is `jira` and a `jira_issue_key` was captured, append the Jira ticket as the secondary reference line. Add ADR and test-plan links when those artifacts exist. 5. Update the `{pr_number}` PR description via the GitHub REST API — write the body to a file and `gh api repos///pulls/ -X PATCH -F body=@`; do NOT use `gh pr edit`, whose GraphQL query fails on the Projects Classic deprecation. If the PR cannot be found because `{pr_number}` does not exist, verify the PR number and check `gh` auth before retrying. diff --git a/work-package/techniques/update-pr/verify-body.md b/work-package/techniques/update-pr/verify-body.md index 5221c74b3..7a0e23a43 100644 --- a/work-package/techniques/update-pr/verify-body.md +++ b/work-package/techniques/update-pr/verify-body.md @@ -1,6 +1,6 @@ --- metadata: - version: 1.1.1 + version: 1.2.0 --- ## Capability @@ -17,7 +17,7 @@ Final-template PR body markdown ([Template (Final)](../../resources/pr-descripti ### body_conforms -True when the rendered body passes every rule in `pr-body-conformance` against the [Final template](../../resources/pr-description.md#template-final) mandated sections and link row; false otherwise. +True when the rendered body satisfies every criterion in [Rules](../../resources/pr-description.md#rules); false otherwise. ### body_findings @@ -27,6 +27,6 @@ List of `{ rule_id, detail }` entries, one per failed conformance rule, in rule- ## Protocol 1. Render the Final-template body to `/tmp/pr-body.md`. -2. Evaluate `all-mandated-sections-present` first: check that each mandated section heading for the selected template variant appears literally in the rendered text, per the mandates of [Template (Initial)](../../resources/pr-description.md#template-initial) or [Template (Final)](../../resources/pr-description.md#template-final) (e.g. `grep -F` each `## ` the template variant requires, plus the Issue/Engineering link row). Append a `{ rule_id: all-mandated-sections-present, detail }` finding naming every mandated section that is absent. Do not treat a matching `## Summary` as evidence the remaining sections exist. -3. Evaluate each remaining rule in `pr-body-conformance` against the rendered text. For each failure append `{ rule_id, detail }` to `{body_findings}`. +2. Evaluate [Mandated sections present](../../resources/pr-description.md#mandated-sections-present) first, against the variant's own template — [Template (Initial)](../../resources/pr-description.md#template-initial) or [Template (Final)](../../resources/pr-description.md#template-final). Append one finding naming every mandated section that is absent. +3. Evaluate each remaining criterion in [Rules](../../resources/pr-description.md#rules) against the rendered text. For each failure append `{ rule_id, detail }` to `{body_findings}`. 4. Set `{body_conforms}` = true when `{body_findings}` is empty after all rules are evaluated; false otherwise. diff --git a/work-package/workflow.yaml b/work-package/workflow.yaml index 49d588b44..08212e8bf 100644 --- a/work-package/workflow.yaml +++ b/work-package/workflow.yaml @@ -1,6 +1,6 @@ $schema: ../../schemas/workflow.schema.json id: work-package -version: 3.39.0 +version: 3.40.0 title: Work Package Implementation Workflow description: Defines how to plan and implement ONE work package from inception to merged PR. A work package is a discrete unit of work such as a feature, bug-fix, enhancement, refactoring, or any other deliverable change. For multiple related work packages, use the work-packages workflow to create a roadmap first. Also supports review mode for auditing an existing PR or implementation end-to-end. author: m2ux @@ -502,11 +502,11 @@ variables: defaultValue: "" - name: body_conforms type: boolean - description: "True once the rendered PR body has passed every rule in update-pr::rules.pr-body-conformance." + description: "True once the rendered PR body satisfies every conformance criterion in the pr-description guide." defaultValue: false - name: body_findings type: array - description: List of pr-body-conformance violations. + description: List of PR-body conformance violations. defaultValue: [] - name: body_override_recorded type: boolean