@tekyzinc/gsd-t 3.23.11 → 3.25.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/README.md +7 -0
- package/bin/cli-preflight-checks/branch-guard.cjs +110 -0
- package/bin/cli-preflight-checks/contracts-stable.cjs +128 -0
- package/bin/cli-preflight-checks/deps-installed.cjs +89 -0
- package/bin/cli-preflight-checks/manifest-fresh.cjs +98 -0
- package/bin/cli-preflight-checks/ports-free.cjs +110 -0
- package/bin/cli-preflight-checks/working-tree-state.cjs +149 -0
- package/bin/cli-preflight.cjs +265 -0
- package/bin/gsd-t-context-brief-kinds/design-verify.cjs +139 -0
- package/bin/gsd-t-context-brief-kinds/execute.cjs +205 -0
- package/bin/gsd-t-context-brief-kinds/qa.cjs +130 -0
- package/bin/gsd-t-context-brief-kinds/red-team.cjs +131 -0
- package/bin/gsd-t-context-brief-kinds/scan.cjs +118 -0
- package/bin/gsd-t-context-brief-kinds/verify.cjs +157 -0
- package/bin/gsd-t-context-brief.cjs +395 -0
- package/bin/gsd-t-ratelimit-probe-worker.cjs +236 -0
- package/bin/gsd-t-ratelimit-probe.cjs +648 -0
- package/bin/gsd-t-verify-gate-judge.cjs +224 -0
- package/bin/gsd-t-verify-gate.cjs +612 -0
- package/bin/gsd-t.js +45 -1
- package/bin/live-activity-report.cjs +615 -0
- package/bin/m55-substrate-proof.cjs +134 -0
- package/bin/parallel-cli-tee.cjs +206 -0
- package/bin/parallel-cli.cjs +478 -0
- package/commands/gsd-t-execute.md +31 -0
- package/commands/gsd-t-help.md +21 -0
- package/commands/gsd-t-verify.md +38 -0
- package/docs/architecture.md +194 -0
- package/docs/diagrams/.gsd-t/.context-meter-state.json +10 -0
- package/docs/diagrams/.gsd-t/context-meter.log +9 -0
- package/docs/diagrams/.gsd-t/events/2026-05-08.jsonl +45 -0
- package/docs/diagrams/.gsd-t/events/2026-05-09.jsonl +1 -0
- package/docs/diagrams/.gsd-t/heartbeat-cd9e7f59-ba5b-406a-9ed6-16762f039e81.jsonl +48 -0
- package/docs/diagrams/01-top-level-map-d2.png +0 -0
- package/docs/diagrams/01-top-level-map.d2 +77 -0
- package/docs/diagrams/01-top-level-map.mmd +48 -0
- package/docs/diagrams/01-top-level-map.png +0 -0
- package/docs/diagrams/01-top-level-map.svg +126 -0
- package/docs/diagrams/02-milestone-lifecycle-d2.png +0 -0
- package/docs/diagrams/02-milestone-lifecycle.d2 +38 -0
- package/docs/diagrams/02-milestone-lifecycle.mmd +36 -0
- package/docs/diagrams/02-milestone-lifecycle.png +0 -0
- package/docs/diagrams/02-milestone-lifecycle.svg +114 -0
- package/docs/diagrams/03-wave-mode-d2.png +0 -0
- package/docs/diagrams/03-wave-mode.d2 +33 -0
- package/docs/diagrams/03-wave-mode.mmd +21 -0
- package/docs/diagrams/03-wave-mode.png +0 -0
- package/docs/diagrams/03-wave-mode.svg +113 -0
- package/docs/diagrams/04-design-to-code-d2.png +0 -0
- package/docs/diagrams/04-design-to-code.d2 +35 -0
- package/docs/diagrams/04-design-to-code.mmd +29 -0
- package/docs/diagrams/04-design-to-code.png +0 -0
- package/docs/diagrams/04-design-to-code.svg +115 -0
- package/docs/diagrams/05-backlog-d2.png +0 -0
- package/docs/diagrams/05-backlog.d2 +40 -0
- package/docs/diagrams/05-backlog.mmd +20 -0
- package/docs/diagrams/05-backlog.png +0 -0
- package/docs/diagrams/05-backlog.svg +113 -0
- package/docs/diagrams/06-automation-utilities-d2.png +0 -0
- package/docs/diagrams/06-automation-utilities.d2 +48 -0
- package/docs/diagrams/06-automation-utilities.mmd +47 -0
- package/docs/diagrams/06-automation-utilities.png +0 -0
- package/docs/diagrams/06-automation-utilities.svg +110 -0
- package/docs/diagrams/_theme.d2 +86 -0
- package/docs/requirements.md +48 -0
- package/docs/workflow-diagram.md +338 -0
- package/package.json +1 -1
- package/scripts/gsd-t-dashboard-server.js +190 -0
- package/scripts/gsd-t-transcript.html +200 -0
- package/templates/CLAUDE-global.md +46 -0
- package/templates/prompts/design-verify-subagent.md +3 -0
- package/templates/prompts/qa-subagent.md +3 -0
- package/templates/prompts/red-team-subagent.md +3 -0
|
@@ -209,6 +209,32 @@
|
|
|
209
209
|
.frame.tool-use > .ts, .frame.thinking > .ts { padding: 8px 0 0 12px; }
|
|
210
210
|
.frame.tool-result > .ts { padding-top: 8px; }
|
|
211
211
|
.frame.compact-marker > .ts { padding: 0; min-width: 64px; }
|
|
212
|
+
|
|
213
|
+
/* M54 D2 T1 — LIVE ACTIVITY rail section.
|
|
214
|
+
Additive only. No existing CSS renamed or removed. */
|
|
215
|
+
#rail-live-activity { padding: 0 0 8px 0; border-bottom: 1px solid var(--border); margin-bottom: 4px; }
|
|
216
|
+
#rail-live-activity .la-heading { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px 4px 12px; font-size: 11px; text-transform: uppercase; color: var(--fg-xdim); letter-spacing: 0.08em; }
|
|
217
|
+
.la-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
|
|
218
|
+
.la-entry { display: grid; grid-template-columns: 10px 18px 1fr auto; align-items: center; gap: 4px; padding: 5px 12px; cursor: pointer; border-radius: 4px; font-size: 12px; }
|
|
219
|
+
.la-entry:hover { background: var(--bg-soft); }
|
|
220
|
+
.la-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
|
221
|
+
.la-dot-running { background: #2dd4bf; }
|
|
222
|
+
.la-dot-stale { background: var(--fg-xdim, #6b7280); }
|
|
223
|
+
.la-icon { font-family: var(--mono); font-size: 13px; text-align: center; color: var(--fg-dim); }
|
|
224
|
+
.la-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40ch; color: var(--fg); font-family: var(--mono); font-size: 11px; }
|
|
225
|
+
.la-duration { font-family: var(--mono); font-size: 11px; color: var(--fg-xdim); text-align: right; white-space: nowrap; }
|
|
226
|
+
.la-empty { padding: 4px 12px 0 12px; color: var(--fg-xdim); font-size: 11px; font-style: italic; }
|
|
227
|
+
/* Kind icon slots — glyphs set in JS via KIND_ICONS map */
|
|
228
|
+
.la-icon-bash { color: var(--accent-warm, #f0a500); }
|
|
229
|
+
.la-icon-monitor { color: var(--accent, #58a6ff); }
|
|
230
|
+
.la-icon-tool { color: var(--fg-dim, #8b949e); }
|
|
231
|
+
.la-icon-spawn { color: var(--green, #3fb950); }
|
|
232
|
+
@keyframes accent-pulse {
|
|
233
|
+
0% { box-shadow: inset 2px 0 0 0 #2dd4bf; opacity: 1; }
|
|
234
|
+
50% { box-shadow: inset 2px 0 0 0 #2dd4bf; opacity: 0.6; }
|
|
235
|
+
100% { box-shadow: inset 2px 0 0 0 #2dd4bf; opacity: 1; }
|
|
236
|
+
}
|
|
237
|
+
.la-pulsing { animation: accent-pulse 1.5s ease-in-out infinite; }
|
|
212
238
|
</style>
|
|
213
239
|
</head>
|
|
214
240
|
<body data-spawn-id="__SPAWN_ID__">
|
|
@@ -226,6 +252,15 @@
|
|
|
226
252
|
<div class="rail-header"><span>★ Main Session</span></div>
|
|
227
253
|
<div class="rail-body" id="rail-main-body"><div class="empty">No in-session conversation captured yet.</div></div>
|
|
228
254
|
</section>
|
|
255
|
+
<!-- M54 D2 T1 — LIVE ACTIVITY section (additive, between Main Session and Live Spawns).
|
|
256
|
+
Populated by 5s polling JS (D2 T2). CSS @keyframes accent-pulse in <style> block above. -->
|
|
257
|
+
<section id="rail-live-activity">
|
|
258
|
+
<div class="la-heading"><span>⚡ Live Activity</span></div>
|
|
259
|
+
<ul id="la-list" class="la-list">
|
|
260
|
+
<!-- Entries injected by polling JS (T2). Empty section header visible when list is empty. -->
|
|
261
|
+
</ul>
|
|
262
|
+
<div class="la-empty" id="la-empty-msg">No active operations detected.</div>
|
|
263
|
+
</section>
|
|
229
264
|
<section class="rail-live" data-rail-section="live">
|
|
230
265
|
<div class="rail-header"><span>Live Spawns</span></div>
|
|
231
266
|
<div class="rail-body">
|
|
@@ -1615,6 +1650,171 @@
|
|
|
1615
1650
|
poll();
|
|
1616
1651
|
setInterval(poll, 5000);
|
|
1617
1652
|
})();
|
|
1653
|
+
|
|
1654
|
+
// ── M54 D2 T2 — Live Activity Rail ────────────────────────────────────
|
|
1655
|
+
// Polls /api/live-activity every 5s (same cadence as /api/parallelism).
|
|
1656
|
+
// Appends entries to #la-list, applies .la-pulsing on new entries,
|
|
1657
|
+
// removes entries when they disappear from the API response.
|
|
1658
|
+
// Click handler: stopPulse + loadTailUrl (NO auto-switch on arrival).
|
|
1659
|
+
// Additive only — no existing function renamed or removed.
|
|
1660
|
+
(function wireLiveActivity() {
|
|
1661
|
+
const laList = document.getElementById('la-list');
|
|
1662
|
+
const laEmpty = document.getElementById('la-empty-msg');
|
|
1663
|
+
if (!laList) return; // section not present in this page variant
|
|
1664
|
+
|
|
1665
|
+
// Map of id → { element, startedAt, stopPulseTimer }
|
|
1666
|
+
const _current = new Map();
|
|
1667
|
+
|
|
1668
|
+
// Format duration in seconds as human-readable string
|
|
1669
|
+
function fmtDuration(ms) {
|
|
1670
|
+
const s = Math.floor(ms / 1000);
|
|
1671
|
+
if (s < 60) return s + 's';
|
|
1672
|
+
const m = Math.floor(s / 60), rs = s % 60;
|
|
1673
|
+
if (m < 60) return m + 'm ' + rs + 's';
|
|
1674
|
+
const h = Math.floor(m / 60), rm = m % 60;
|
|
1675
|
+
return h + 'h ' + rm + 'm';
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
// Kind icon mapping
|
|
1679
|
+
const KIND_ICONS = { bash: '$', monitor: '👁', tool: '🔧', spawn: '↳' };
|
|
1680
|
+
|
|
1681
|
+
// Load the tailUrl content into the bottom pane (mirrors existing bottom-pane loaders)
|
|
1682
|
+
function loadTailUrl(tailUrl) {
|
|
1683
|
+
const streamEl = document.getElementById('stream');
|
|
1684
|
+
if (!streamEl) return;
|
|
1685
|
+
fetch(tailUrl)
|
|
1686
|
+
.then(function(r) { return r.text(); })
|
|
1687
|
+
.then(function(text) {
|
|
1688
|
+
streamEl.innerHTML = '<pre style="margin:0;padding:12px;font-family:var(--mono);font-size:12px;white-space:pre-wrap;word-break:break-word;">' + _esc(text) + '</pre>';
|
|
1689
|
+
})
|
|
1690
|
+
.catch(function(err) {
|
|
1691
|
+
console.log('[la] tail load error:', err && err.message);
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
function _esc(s) {
|
|
1696
|
+
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
// Remove .la-pulsing from entry element
|
|
1700
|
+
function stopPulse(id) {
|
|
1701
|
+
const item = _current.get(id);
|
|
1702
|
+
if (!item || !item.element) return;
|
|
1703
|
+
item.element.classList.remove('la-pulsing');
|
|
1704
|
+
if (item.stopPulseTimer) { clearTimeout(item.stopPulseTimer); item.stopPulseTimer = null; }
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
// Append a new .la-entry to #la-list
|
|
1708
|
+
function appendActivity(entry) {
|
|
1709
|
+
const li = document.createElement('li');
|
|
1710
|
+
li.className = 'la-entry la-pulsing';
|
|
1711
|
+
li.setAttribute('data-id', entry.id);
|
|
1712
|
+
li.setAttribute('data-kind', entry.kind);
|
|
1713
|
+
li.setAttribute('data-tail-url', entry.tailUrl || '');
|
|
1714
|
+
|
|
1715
|
+
const dot = document.createElement('span');
|
|
1716
|
+
dot.className = 'la-dot la-dot-running';
|
|
1717
|
+
li.appendChild(dot);
|
|
1718
|
+
|
|
1719
|
+
const icon = document.createElement('span');
|
|
1720
|
+
icon.className = 'la-icon la-icon-' + entry.kind;
|
|
1721
|
+
icon.textContent = KIND_ICONS[entry.kind] || '?';
|
|
1722
|
+
li.appendChild(icon);
|
|
1723
|
+
|
|
1724
|
+
const label = document.createElement('span');
|
|
1725
|
+
label.className = 'la-label';
|
|
1726
|
+
const labelText = String(entry.label || '').slice(0, 40);
|
|
1727
|
+
label.textContent = labelText;
|
|
1728
|
+
label.title = entry.label || '';
|
|
1729
|
+
li.appendChild(label);
|
|
1730
|
+
|
|
1731
|
+
const dur = document.createElement('span');
|
|
1732
|
+
dur.className = 'la-duration';
|
|
1733
|
+
dur.textContent = fmtDuration(entry.durationMs || 0);
|
|
1734
|
+
li.appendChild(dur);
|
|
1735
|
+
|
|
1736
|
+
li.addEventListener('click', function() {
|
|
1737
|
+
stopPulse(entry.id);
|
|
1738
|
+
if (entry.tailUrl) loadTailUrl(entry.tailUrl);
|
|
1739
|
+
});
|
|
1740
|
+
|
|
1741
|
+
laList.appendChild(li);
|
|
1742
|
+
|
|
1743
|
+
// Schedule pulse stop after 30s (condition c)
|
|
1744
|
+
const timer = setTimeout(function() { stopPulse(entry.id); }, 30000);
|
|
1745
|
+
_current.set(entry.id, { element: li, startedAt: entry.startedAt, stopPulseTimer: timer });
|
|
1746
|
+
|
|
1747
|
+
if (laEmpty) laEmpty.style.display = 'none';
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
// Remove a .la-entry from #la-list
|
|
1751
|
+
function removeActivity(id) {
|
|
1752
|
+
const item = _current.get(id);
|
|
1753
|
+
if (!item) return;
|
|
1754
|
+
if (item.stopPulseTimer) clearTimeout(item.stopPulseTimer);
|
|
1755
|
+
if (item.element && item.element.parentNode) item.element.parentNode.removeChild(item.element);
|
|
1756
|
+
_current.delete(id);
|
|
1757
|
+
if (laEmpty && _current.size === 0) laEmpty.style.display = '';
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
// Update the duration counter for an existing entry
|
|
1761
|
+
function updateDuration(id, startedAt) {
|
|
1762
|
+
const item = _current.get(id);
|
|
1763
|
+
if (!item || !item.element) return;
|
|
1764
|
+
const dur = item.element.querySelector('.la-duration');
|
|
1765
|
+
if (!dur) return;
|
|
1766
|
+
const start = startedAt ? new Date(startedAt).getTime() : 0;
|
|
1767
|
+
const elapsed = start ? Math.max(0, Date.now() - start) : 0;
|
|
1768
|
+
dur.textContent = fmtDuration(elapsed);
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
// Fetch /api/live-activity, return envelope (or {activities:[]} on error)
|
|
1772
|
+
async function fetchLiveActivity() {
|
|
1773
|
+
try {
|
|
1774
|
+
const r = await fetch('/api/live-activity');
|
|
1775
|
+
if (!r.ok) {
|
|
1776
|
+
console.log('[la] /api/live-activity returned', r.status);
|
|
1777
|
+
return { activities: [] };
|
|
1778
|
+
}
|
|
1779
|
+
return await r.json();
|
|
1780
|
+
} catch (err) {
|
|
1781
|
+
console.log('[la] fetch error:', err && err.message);
|
|
1782
|
+
return { activities: [] };
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
// Reconcile current DOM state with new API response
|
|
1787
|
+
function reconcile(activities) {
|
|
1788
|
+
// Build a Map of new activities by id
|
|
1789
|
+
const newById = new Map();
|
|
1790
|
+
for (const entry of (activities || [])) {
|
|
1791
|
+
newById.set(entry.id, entry);
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
// Remove entries no longer present
|
|
1795
|
+
for (const id of Array.from(_current.keys())) {
|
|
1796
|
+
if (!newById.has(id)) removeActivity(id);
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
// Add new entries; update durations for existing ones
|
|
1800
|
+
for (const [id, entry] of newById) {
|
|
1801
|
+
if (_current.has(id)) {
|
|
1802
|
+
updateDuration(id, entry.startedAt);
|
|
1803
|
+
} else {
|
|
1804
|
+
appendActivity(entry);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
// Initial poll + 5s interval (same cadence as /api/parallelism)
|
|
1810
|
+
async function poll() {
|
|
1811
|
+
const data = await fetchLiveActivity();
|
|
1812
|
+
reconcile(data.activities);
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
poll();
|
|
1816
|
+
setInterval(poll, 5000);
|
|
1817
|
+
})();
|
|
1618
1818
|
})();
|
|
1619
1819
|
</script>
|
|
1620
1820
|
</body>
|
|
@@ -412,6 +412,52 @@ No command file ships a bare `Task(...)` or `claude -p` line outside of a wrappe
|
|
|
412
412
|
|
|
413
413
|
Rationale: the pre-M41 convention silently wrote `N/A` tokens because no caller parsed the `usage` envelope. The wrapper is the single place that parses it. Bypassing the wrapper re-introduces blind spots.
|
|
414
414
|
|
|
415
|
+
## Mandatory Preflight Before Spawn (M55 — v3.25.10+)
|
|
416
|
+
|
|
417
|
+
Every command that spawns a Task subagent or invokes `claude -p` MUST run `gsd-t preflight` first. Hard-fails on any `severity:"error"` check (wrong branch, occupied required port). Non-error checks (warn/info) record but do not block.
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
gsd-t preflight --json > /tmp/gsd-t-preflight.json || exit 4
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Catches drift early — wrong branch, port collision, DRAFT contracts past PARTITIONED — before any LLM work fires. Same envelope is consumed by `gsd-t verify-gate` Track 1, so failing fast at execute time saves the verify round-trip.
|
|
424
|
+
|
|
425
|
+
Library: `bin/cli-preflight.cjs::runPreflight({projectDir, checks?})`.
|
|
426
|
+
Contract: `.gsd-t/contracts/cli-preflight-contract.md` v1.0.0 STABLE.
|
|
427
|
+
|
|
428
|
+
## Brief-First Worker Rule (M55 — v3.25.10+)
|
|
429
|
+
|
|
430
|
+
Every parallel worker prompt scaffold MUST thread `$BRIEF_PATH` — a ≤2,500-token JSON snapshot generated once per spawn by `bin/gsd-t-context-brief.cjs`. The brief replaces the 30–60k context re-read every parallel worker would otherwise perform (CLAUDE.md + contracts + scope + relevant code) — the dominant ITPM-relief lever in M55.
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
SPAWN_ID="execute-${DOMAIN}-$(date -u +%Y%m%dT%H%M%SZ)"
|
|
434
|
+
gsd-t brief --kind execute --domain "${DOMAIN}" --spawn-id "${SPAWN_ID}" --out ".gsd-t/briefs/${SPAWN_ID}.json"
|
|
435
|
+
export BRIEF_PATH=".gsd-t/briefs/${SPAWN_ID}.json"
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
The 3 validation-subagent protocols (`templates/prompts/{qa,red-team,design-verify}-subagent.md`) carry the canonical instruction "If you're about to grep, read, or run a test, check the brief first at `$BRIEF_PATH`." Workers grep the brief instead of re-walking the repo.
|
|
439
|
+
|
|
440
|
+
`.gsd-t/briefs/` is gitignored — briefs are per-spawn ephemera, not committed artifacts.
|
|
441
|
+
|
|
442
|
+
Library: `bin/gsd-t-context-brief.cjs::generateBrief(...)`.
|
|
443
|
+
Contract: `.gsd-t/contracts/context-brief-contract.md` v1.0.0 STABLE.
|
|
444
|
+
|
|
445
|
+
## Two-Track Verify-Gate (M55 — v3.25.10+)
|
|
446
|
+
|
|
447
|
+
`gsd-t verify-gate --json` is the canonical pre-merge gate. Track 1 = D1 preflight envelope (hard-fail on any `severity:"error"` check). Track 2 = D2 parallel-CLI substrate fans out off-the-shelf CLIs (`tsc`, `biome`/`ruff`, `npm test`, `knip`, `gitleaks`, `scc`/`lizard`). Both tracks always run; both report.
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
gsd-t verify-gate --json > /tmp/gate.json || exit 4
|
|
451
|
+
cat /tmp/gate.json | gsd-t verify-gate-judge > /tmp/judge-prompt.txt
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
`top-level ok = (skipTrack1 || track1.ok) && (skipTrack2 || track2.ok)` — purely deterministic. The LLM judge sees only the ≤500-token deterministic `summary`; never raw stdout/stderr. The judge confirms or contradicts the deterministic verdict; it never overrides `ok`.
|
|
455
|
+
|
|
456
|
+
Defensive on missing `.gsd-t/ratelimit-map.json` → fallback `maxConcurrency=2` with a structured note.
|
|
457
|
+
|
|
458
|
+
Library: `bin/gsd-t-verify-gate.cjs::runVerifyGate(...)` + `bin/gsd-t-verify-gate-judge.cjs::buildJudgePrompt(...)`.
|
|
459
|
+
Contract: `.gsd-t/contracts/verify-gate-contract.md` v1.0.0 STABLE.
|
|
460
|
+
|
|
415
461
|
## Always-Headless Spawn (M43 D4, v3.16.x+) — Channel Separation
|
|
416
462
|
|
|
417
463
|
Every GSD-T command spawns detached, unconditionally. There is no `--watch`, no `--in-session`, no `--headless` opt-in, no context-meter threshold that reroutes, no low-water-mark bypass. The dialog channel is reserved for human↔Claude conversation; everything else is a detached headless child. Interactive session shows a launch banner + live-transcript URL + event-stream path, then exits. Results surface via the read-back banner on the user's next message.
|
|
@@ -4,6 +4,9 @@ You are the Design Verification Agent. Your ONLY job is to visually compare the
|
|
|
4
4
|
|
|
5
5
|
**FAIL-BY-DEFAULT.** Every visual element starts UNVERIFIED. You must prove each one matches — never assume. "Looks close" is not a verdict. "Appears to match" is not a verdict. The only valid verdicts are `✅ MATCH` (with proof) or `❌ DEVIATION` (with specific values).
|
|
6
6
|
|
|
7
|
+
<!-- M55-D5: brief-first rule -->
|
|
8
|
+
**Brief first.** If you're about to grep, read, or run a test, check the brief first at `$BRIEF_PATH` (a ≤2,500-token JSON snapshot of design contracts + scope + design tokens + relevant component paths, generated by `bin/gsd-t-context-brief.cjs --kind design-verify`). The brief lists the design contracts, design-token files, and component paths in scope for this verification — your starting checklist. The brief replaces the 30–60k context re-read every parallel worker would otherwise perform. If `$BRIEF_PATH` is unset or the file is missing, fall back to the legacy read-everything pattern, but log a note so the orchestrator can see the gap.
|
|
9
|
+
|
|
7
10
|
## Step 0: Element Count Reconciliation (run BEFORE anything else)
|
|
8
11
|
|
|
9
12
|
A missing widget is the easiest deviation to miss in a 30-row comparison table — and the most catastrophic.
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
You are the QA agent. Your sole job is test generation, execution, and gap reporting. You write ZERO feature code. You never modify implementation files — only test files and reports.
|
|
4
4
|
|
|
5
|
+
<!-- M55-D5: brief-first rule -->
|
|
6
|
+
**Brief first.** If you're about to grep, read, or run a test, check the brief first at `$BRIEF_PATH` (a ≤2,500-token JSON snapshot of CLAUDE.md + contracts + scope + constraints, generated by `bin/gsd-t-context-brief.cjs`). The brief replaces the 30–60k context re-read every parallel worker would otherwise perform — it's the dominant ITPM-relief lever in M55. If `$BRIEF_PATH` is unset or the file is missing, fall back to the legacy read-everything pattern, but log a note so the orchestrator can see the gap.
|
|
7
|
+
|
|
5
8
|
## What to Do
|
|
6
9
|
|
|
7
10
|
1. **Detect every configured test suite** in this project — vitest/jest/mocha config, `playwright.config.*`, `cypress.config.*`. Run EVERY suite that exists.
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
You are a Red Team QA adversary. Your job is to BREAK the code that was just written for this domain. You operate with inverted incentives — your value is measured by REAL bugs found, not tests passed.
|
|
4
4
|
|
|
5
|
+
<!-- M55-D5: brief-first rule -->
|
|
6
|
+
**Brief first.** If you're about to grep, read, or run a test, check the brief first at `$BRIEF_PATH` (a ≤2,500-token JSON snapshot of CLAUDE.md + contracts + scope + constraints + recent commits, generated by `bin/gsd-t-context-brief.cjs --kind red-team`). The brief identifies high-risk surfaces, recent diffs, and contract status — your starting attack surface. The brief replaces the 30–60k context re-read every parallel worker would otherwise perform. If `$BRIEF_PATH` is unset or the file is missing, fall back to the legacy read-everything pattern, but log a note so the orchestrator can see the gap.
|
|
7
|
+
|
|
5
8
|
## Hard Rules
|
|
6
9
|
|
|
7
10
|
- **Bugs found = value.** A short attack list is failure.
|