* fix(#2431): self-suppress TDD Audit section when all commits are missing The TDD Audit section in ship.md step 8 was always emitted — but the execute pipeline only writes gate_status: git trailers when TDD mode is active. Without TDD mode (the default), every commit's trailer is absent and the section normalizes to 100% missing, producing a noise table with no way to disable it. Fix: add a self-suppress instruction at the point where gate_status values are normalized. When every commit in the scan normalizes to 'missing', skip both step 8 (TDD Audit section) and step 9 (aggregate gate_status trailer) entirely. Only emit when at least one commit carries a real value (skill, fallback, or exempt). This is data-driven, NOT config-gated. An earlier iteration used inline 'gsd_run query config-get workflow.tdd_mode' — but workflow.tdd_mode is owned by the tdd capability, and ADR-857 Phase 6 forbids host loop workflows from reading capability-owned keys via inline config-get. The self-suppress approach avoids any config-get entirely; it checks the actual trailer data and skips when there's nothing real to report. Matches the triage's suggested approach: 'have the audit gracefully degrade (skip the section)' when there is no real signal. Tests: tests/workflow-compat.test.cjs gains 3 #2431 assertions: - documents self-suppress when every commit is missing - step 9 (aggregate trailer) is also gated on real values existing - does NOT read workflow.tdd_mode inline (ADR-857 Phase 6 compliant) The existing feat-41 assertions still pass — the section content is preserved, only gated by the self-suppress instruction. References: #2431; PR #585 (consumer shipped, producer never wired); ADR-857 Phase 6 (capability-owned config keys must not be read inline by host loop workflows). * chore(#2431): backfill pr:2467 in .changeset/clever-moles-frolic.md
This commit is contained in:
5
.changeset/clever-moles-frolic.md
Normal file
5
.changeset/clever-moles-frolic.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 2467
|
||||
---
|
||||
**`/gsd-ship` no longer emits a 100%-missing TDD Audit noise table** — the TDD Audit PR-body section was always emitted, but the execute pipeline only writes `gate_status:` git trailers when TDD mode is active. Without TDD mode (the default), every commit was counted `missing` and the table was pure noise with no way to disable it. The section is now gated behind `workflow.tdd_mode`: when TDD mode is off, both the TDD Audit section and the aggregate `gate_status:` trailer are skipped entirely; when on, the existing behavior is preserved.
|
||||
@@ -289,6 +289,8 @@ Pair commits by their conventional-commit type (the `type:` prefix of the subjec
|
||||
|
||||
Surface each commit's `gate_status:` value, normalized to exactly one of `skill`, `fallback`, `exempt`, or `missing` — never the raw trailer text. A commit whose trailer is absent, whose value is none of the first three, or which carries more than one `gate_status:` trailer (ambiguous) is counted as **missing** and still listed. This section is informational; it never blocks the ship.
|
||||
|
||||
**Self-suppress when every commit is missing (#2431):** the execute pipeline only writes `gate_status:` trailers when TDD mode is active. If every commit in the scan normalizes to `missing`, skip this section and the aggregate trailer (step 9) entirely — a 100%-missing table is pure noise. Only emit when at least one commit carries a real value (`skill`, `fallback`, or `exempt`).
|
||||
|
||||
Harden every table cell against injection, not just subjects: escape `|` as `\|` and strip `\r`/`\n` from both commit subjects and the rendered `gate_status` value. Prefer NUL (`-z` / `%x00`) record separation, and reject any record whose fields contain the `\x1f`/`\x1e` delimiters, so an adversarial commit message cannot corrupt record or field boundaries.
|
||||
|
||||
```markdown
|
||||
@@ -305,7 +307,7 @@ Aggregate: 2 skill, 1 fallback, 1 exempt — 0 missing.
|
||||
|
||||
This `## TDD Audit` section is the final body section — it renders after the configured `pr_body_sections`, immediately before the aggregate trailer — so the frozen core sections and the append-only configured sections both keep their existing order.
|
||||
|
||||
**9. Aggregate gate_status trailer (final line):**
|
||||
**9. Aggregate gate_status trailer (final line)** (only when step 8 was emitted — i.e., at least one real `gate_status` value exists):
|
||||
|
||||
After every other section — including any configured `pr_body_sections` — emit the audit aggregate as a single Git trailer on the **final line** of the PR body, preceded by a blank line so it parses as a valid trailer:
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "6d25100a9de15b31",
|
||||
"gsd-core/workflows/settings-integrations.md": "e1fda52e8c9afa5f",
|
||||
"gsd-core/workflows/settings.md": "9b7e0a34f4f41a80",
|
||||
"gsd-core/workflows/ship.md": "0eca9ab4bcdeeb17",
|
||||
"gsd-core/workflows/ship.md": "ea549dd991b366b9",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "0f842a609851a401",
|
||||
"gsd-core/workflows/sketch.md": "c42d993c1e9a6240",
|
||||
"gsd-core/workflows/smart-entry.md": "6d887ca5d9df9185",
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "414db4dbea97ba44",
|
||||
"gsd-core/workflows/settings-integrations.md": "effcef778d4a855f",
|
||||
"gsd-core/workflows/settings.md": "85ceb482dc713169",
|
||||
"gsd-core/workflows/ship.md": "09056fccdf20e41b",
|
||||
"gsd-core/workflows/ship.md": "6693c61fb6a5cd9b",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "5f5ebb6a80d610c6",
|
||||
"gsd-core/workflows/sketch.md": "efc5a794b4bd6e78",
|
||||
"gsd-core/workflows/smart-entry.md": "004b4060eab97cb9",
|
||||
|
||||
@@ -374,7 +374,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "94d61da368e9f85b",
|
||||
"gsd-core/workflows/settings-integrations.md": "9e0108e01e78832c",
|
||||
"gsd-core/workflows/settings.md": "a1a35e58da33b23b",
|
||||
"gsd-core/workflows/ship.md": "205632a5eb12e473",
|
||||
"gsd-core/workflows/ship.md": "dca31cebcd682c02",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "d52a5462bafda830",
|
||||
"gsd-core/workflows/sketch.md": "9bc12018344f8110",
|
||||
"gsd-core/workflows/smart-entry.md": "70445afde3a9ead6",
|
||||
|
||||
@@ -303,7 +303,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "339def28c34b0797",
|
||||
"gsd-core/workflows/settings-integrations.md": "9c9db643112b2371",
|
||||
"gsd-core/workflows/settings.md": "d3f05e22f21bfb3a",
|
||||
"gsd-core/workflows/ship.md": "965497167a9df93b",
|
||||
"gsd-core/workflows/ship.md": "2643b8a3fdc524ce",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "121ed4b8127abf04",
|
||||
"gsd-core/workflows/sketch.md": "ac7a5265c6970bdf",
|
||||
"gsd-core/workflows/smart-entry.md": "99c73236890605a1",
|
||||
|
||||
@@ -307,7 +307,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "69f3a19bf2c61160",
|
||||
"gsd-core/workflows/settings-integrations.md": "a2682897e663fec4",
|
||||
"gsd-core/workflows/settings.md": "17a5de032a64eb22",
|
||||
"gsd-core/workflows/ship.md": "d094208aca181f9c",
|
||||
"gsd-core/workflows/ship.md": "1e74e872bd310c27",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "1f44789553180d84",
|
||||
"gsd-core/workflows/sketch.md": "fadc2cbe6763c010",
|
||||
"gsd-core/workflows/smart-entry.md": "22ef18e897b67907",
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "414db4dbea97ba44",
|
||||
"gsd-core/workflows/settings-integrations.md": "effcef778d4a855f",
|
||||
"gsd-core/workflows/settings.md": "85ceb482dc713169",
|
||||
"gsd-core/workflows/ship.md": "09056fccdf20e41b",
|
||||
"gsd-core/workflows/ship.md": "6693c61fb6a5cd9b",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "2aba89ecd8f41a0d",
|
||||
"gsd-core/workflows/sketch.md": "2913d90416a3c0f0",
|
||||
"gsd-core/workflows/smart-entry.md": "004b4060eab97cb9",
|
||||
|
||||
@@ -410,7 +410,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "2431433811616f76",
|
||||
"gsd-core/workflows/settings-integrations.md": "d6d222af8690d09b",
|
||||
"gsd-core/workflows/settings.md": "3c8bd45b123b5db6",
|
||||
"gsd-core/workflows/ship.md": "a54841f23fd14626",
|
||||
"gsd-core/workflows/ship.md": "06bf9b4228299ffb",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "07724a390fbb43f6",
|
||||
"gsd-core/workflows/sketch.md": "3f6ed885d2ee5528",
|
||||
"gsd-core/workflows/smart-entry.md": "2914f9d54d365931",
|
||||
|
||||
@@ -305,7 +305,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "230a658de9c017a6",
|
||||
"gsd-core/workflows/settings-integrations.md": "58acee11162b4a4e",
|
||||
"gsd-core/workflows/settings.md": "876e954acd64cb18",
|
||||
"gsd-core/workflows/ship.md": "24fd52a74258aaad",
|
||||
"gsd-core/workflows/ship.md": "8358720a4df9b386",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "f2590cb6ddbfad94",
|
||||
"gsd-core/workflows/sketch.md": "9cbf5860b6a005e5",
|
||||
"gsd-core/workflows/smart-entry.md": "93f90cd7a12dbbc7",
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "bf8ea69c8f7ae019",
|
||||
"gsd-core/workflows/settings-integrations.md": "37d4212d83664224",
|
||||
"gsd-core/workflows/settings.md": "f90f106a9490c7c9",
|
||||
"gsd-core/workflows/ship.md": "4be3c89ccda1d856",
|
||||
"gsd-core/workflows/ship.md": "2afce4d73247fbe4",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "5be73b7bdf96b539",
|
||||
"gsd-core/workflows/sketch.md": "64543e59b00637d4",
|
||||
"gsd-core/workflows/smart-entry.md": "fdc5113754223df8",
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "49be159144d7f426",
|
||||
"gsd-core/workflows/settings-integrations.md": "75405795c8462a8a",
|
||||
"gsd-core/workflows/settings.md": "41c0f737bfd311fd",
|
||||
"gsd-core/workflows/ship.md": "7f27ba3add159c13",
|
||||
"gsd-core/workflows/ship.md": "cb1ac552708dda9b",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "f1ece50ac65ea281",
|
||||
"gsd-core/workflows/sketch.md": "592283400d70317b",
|
||||
"gsd-core/workflows/smart-entry.md": "4dc50d4af659c651",
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "edd858cd6cfddaf1",
|
||||
"gsd-core/workflows/settings-integrations.md": "3ec4f77c421b87b4",
|
||||
"gsd-core/workflows/settings.md": "0e3cf91e952b48a2",
|
||||
"gsd-core/workflows/ship.md": "aab2ad926f4613c6",
|
||||
"gsd-core/workflows/ship.md": "e6852cb78fce1582",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "888c0548e63197b3",
|
||||
"gsd-core/workflows/sketch.md": "75ffbd233fd9a762",
|
||||
"gsd-core/workflows/smart-entry.md": "2ad5b63a9deea0ce",
|
||||
|
||||
@@ -368,7 +368,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "414db4dbea97ba44",
|
||||
"gsd-core/workflows/settings-integrations.md": "effcef778d4a855f",
|
||||
"gsd-core/workflows/settings.md": "85ceb482dc713169",
|
||||
"gsd-core/workflows/ship.md": "09056fccdf20e41b",
|
||||
"gsd-core/workflows/ship.md": "6693c61fb6a5cd9b",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "b767a1d3db129a8a",
|
||||
"gsd-core/workflows/sketch.md": "5f0a7d3640cdff54",
|
||||
"gsd-core/workflows/smart-entry.md": "004b4060eab97cb9",
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "252b0d3edc315339",
|
||||
"gsd-core/workflows/settings-integrations.md": "1c3997dc6953e7eb",
|
||||
"gsd-core/workflows/settings.md": "a244850ce2f7b8dd",
|
||||
"gsd-core/workflows/ship.md": "b3dedb0506ba3ab6",
|
||||
"gsd-core/workflows/ship.md": "a4f14d4154451663",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "681800323681c5c6",
|
||||
"gsd-core/workflows/sketch.md": "da82c9be7074545c",
|
||||
"gsd-core/workflows/smart-entry.md": "c4c780d3aa2124f8",
|
||||
|
||||
2
tests/fixtures/golden-install-parity/pi.json
vendored
2
tests/fixtures/golden-install-parity/pi.json
vendored
@@ -271,7 +271,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "414db4dbea97ba44",
|
||||
"gsd-core/workflows/settings-integrations.md": "effcef778d4a855f",
|
||||
"gsd-core/workflows/settings.md": "85ceb482dc713169",
|
||||
"gsd-core/workflows/ship.md": "09056fccdf20e41b",
|
||||
"gsd-core/workflows/ship.md": "6693c61fb6a5cd9b",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "838c701bd072ae73",
|
||||
"gsd-core/workflows/sketch.md": "70df86d9d8eeba0f",
|
||||
"gsd-core/workflows/smart-entry.md": "004b4060eab97cb9",
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "5e05212fb5cba531",
|
||||
"gsd-core/workflows/settings-integrations.md": "c9fb71d26fd93527",
|
||||
"gsd-core/workflows/settings.md": "83a13de5926ead14",
|
||||
"gsd-core/workflows/ship.md": "8a4fe0b69f5c72f9",
|
||||
"gsd-core/workflows/ship.md": "59c6c30887206a69",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "89e0eab2af946b04",
|
||||
"gsd-core/workflows/sketch.md": "6e68bbff5c1e6db0",
|
||||
"gsd-core/workflows/smart-entry.md": "072ac6efe8aafc38",
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "39e66386f6c48025",
|
||||
"gsd-core/workflows/settings-integrations.md": "8bb1c2bdebbc56e6",
|
||||
"gsd-core/workflows/settings.md": "db6121276c6f63a4",
|
||||
"gsd-core/workflows/ship.md": "6c97dde34a8edcd7",
|
||||
"gsd-core/workflows/ship.md": "4114412c68dd845f",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "dbec602d104cb951",
|
||||
"gsd-core/workflows/sketch.md": "6a6e543f2b667278",
|
||||
"gsd-core/workflows/smart-entry.md": "5631e2e70b02abba",
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "2f86ec7b998f9485",
|
||||
"gsd-core/workflows/settings-integrations.md": "159d0ae32b511129",
|
||||
"gsd-core/workflows/settings.md": "26fff45b86d827aa",
|
||||
"gsd-core/workflows/ship.md": "7682321e294a2574",
|
||||
"gsd-core/workflows/ship.md": "6883c9a9cc4a1543",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "10063f56c2c7f141",
|
||||
"gsd-core/workflows/sketch.md": "c15716376df41c97",
|
||||
"gsd-core/workflows/smart-entry.md": "3fed94530109124b",
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
"gsd-core/workflows/settings-advanced.md": "414db4dbea97ba44",
|
||||
"gsd-core/workflows/settings-integrations.md": "effcef778d4a855f",
|
||||
"gsd-core/workflows/settings.md": "85ceb482dc713169",
|
||||
"gsd-core/workflows/ship.md": "09056fccdf20e41b",
|
||||
"gsd-core/workflows/ship.md": "6693c61fb6a5cd9b",
|
||||
"gsd-core/workflows/sketch-wrap-up.md": "86db87b16548117e",
|
||||
"gsd-core/workflows/sketch.md": "fcd52f8d9076e183",
|
||||
"gsd-core/workflows/smart-entry.md": "004b4060eab97cb9",
|
||||
|
||||
@@ -143,6 +143,39 @@ describe('feat-41: ship.md TDD Audit gate_status extraction', () => {
|
||||
assert.match(workflow, /final line|last line/i);
|
||||
});
|
||||
|
||||
// ─── #2431: TDD Audit section self-suppresses when all commits are missing ─
|
||||
//
|
||||
// The execute pipeline only writes `gate_status:` git trailers when TDD mode
|
||||
// is active. Without TDD mode, every commit is `missing` and the section is
|
||||
// pure noise. The fix adds a self-suppress instruction: skip the section
|
||||
// entirely when every commit normalizes to `missing`. This is data-driven
|
||||
// (no inline config-get of a capability-owned key — Phase 6 compliant).
|
||||
|
||||
test('#2431: documents self-suppress when every commit is missing', () => {
|
||||
assert.match(workflow, /self-suppress/i,
|
||||
'ship.md must instruct the agent to self-suppress the TDD Audit when all commits are missing (#2431)');
|
||||
assert.match(workflow, /100%.?missing|every commit.*missing/i,
|
||||
'ship.md must explain that a 100%-missing table is noise and should be skipped (#2431)');
|
||||
});
|
||||
|
||||
test('#2431: step 9 (aggregate trailer) is also gated on real values existing', () => {
|
||||
// The aggregate gate_status trailer is the companion to the TDD Audit
|
||||
// section; both must be skipped together when no real gate_status exists.
|
||||
const step9 = workflow.match(/\*\*9\.\s*Aggregate gate_status trailer[\s\S]*?(?=\*\*10\.|\z)/);
|
||||
assert.ok(step9, 'step 9 must exist in the workflow');
|
||||
assert.match(step9[0], /step 8|at least one|real/i,
|
||||
'step 9 must reference step 8 or require at least one real gate_status value (#2431)');
|
||||
});
|
||||
|
||||
test('#2431: does NOT read workflow.tdd_mode inline (ADR-857 Phase 6 compliant)', () => {
|
||||
// ADR-857 Phase 6 forbids host loop workflows from reading capability-owned
|
||||
// config keys via inline config-get. workflow.tdd_mode is owned by the tdd
|
||||
// capability. The self-suppress approach avoids any config-get — it's
|
||||
// purely data-driven (check the actual trailer values).
|
||||
assert.doesNotMatch(workflow, /config-get\s+workflow\.tdd_mode/,
|
||||
'ship.md must NOT read workflow.tdd_mode via inline config-get (ADR-857 Phase 6 violation — use self-suppress instead, #2431)');
|
||||
});
|
||||
|
||||
test('does not disturb the frozen #3167 core section order (Key Decisions precedes the new section)', () => {
|
||||
assert.match(workflow, /## Key Decisions[\s\S]*## TDD Audit/);
|
||||
});
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
"settings-advanced.md": 40019,
|
||||
"settings-integrations.md": 16257,
|
||||
"settings.md": 33832,
|
||||
"ship.md": 28310,
|
||||
"ship.md": 28782,
|
||||
"sketch-wrap-up.md": 14267,
|
||||
"sketch.md": 20369,
|
||||
"smart-entry.md": 11489,
|
||||
|
||||
Reference in New Issue
Block a user