@tekyzinc/gsd-t 4.6.11 → 4.7.11
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 +28 -0
- package/README.md +1 -1
- package/bin/gsd-t-architectural-trigger.cjs +523 -0
- package/bin/gsd-t-archive-domains.cjs +136 -0
- package/bin/gsd-t-loop-ledger.cjs +519 -0
- package/bin/gsd-t-research-gate.cjs +439 -0
- package/bin/gsd-t.js +82 -1
- package/commands/gsd-t-complete-milestone.md +15 -2
- package/commands/gsd-t-help.md +25 -0
- package/docs/requirements.md +17 -0
- package/package.json +1 -1
- package/templates/CLAUDE-global.md +35 -16
- package/templates/prompts/blind-adversary-subagent.md +101 -0
- package/templates/prompts/research-subagent.md +127 -0
- package/templates/prompts/stated-claims-snippet.md +89 -0
- package/templates/test-helpers/launch-extension.ts +81 -0
- package/templates/workflows/gsd-t-debug.workflow.js +312 -0
- package/templates/workflows/gsd-t-execute.workflow.js +366 -1
- package/templates/workflows/gsd-t-phase.workflow.js +482 -5
- package/templates/workflows/gsd-t-quick.workflow.js +272 -2
- package/templates/workflows/gsd-t-verify.workflow.js +261 -1
package/docs/requirements.md
CHANGED
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
| REQ-060 | Quality North Star Persona — project CLAUDE.md can define a `## Quality North Star` section (1-3 sentences) with a project quality identity. gsd-t-init auto-detects preset (library/web-app/cli) or prompts user. gsd-t-setup offers persona config for existing projects. Persona is injected at subagent spawn time; skips silently if section absent (backward compatible). | P2 | complete | M32: templates/CLAUDE-project.md, gsd-t-init.md, gsd-t-setup.md |
|
|
72
72
|
| REQ-061 | Design Brief Generation — during partition, if UI/frontend signals detected (React/Vue/Svelte/Flutter, CSS/SCSS, component files, or Tailwind config), generate `.gsd-t/contracts/design-brief.md` with color palette, typography, spacing, component patterns, layout principles, interaction patterns, and tone/voice. Skip for non-UI projects. Do not overwrite existing briefs. Referenced in plan for UI task descriptions. | P2 | complete | M32: gsd-t-partition.md, gsd-t-plan.md, gsd-t-setup.md |
|
|
73
73
|
| REQ-062 | Exploratory Testing Blocks — after scripted tests pass, if Playwright MCP is registered, QA agents get 3 minutes and Red Team gets 5 minutes of interactive exploration using Playwright MCP. All findings tagged [EXPLORATORY] in qa-issues.md and red-team-report.md. Feeds into M31 QA calibration as separate category. Silent skip when Playwright MCP absent. Injected into execute, quick, integrate, debug. | P2 | complete | M32: gsd-t-execute.md, gsd-t-quick.md, gsd-t-integrate.md, gsd-t-debug.md |
|
|
74
|
+
| REQ-094 | Auto-Research Gate (M89) — deterministic CLASSIFY + cite-or-fail ENFORCE wrapped around an LLM-prompted DETECT step. For each load-bearing claim, the agent tags it KNOWN vs GUESSED (unknown / assumed / stale) in a `## Stated Claims` section (§6.5 DETECT seam). A GUESSED claim is classified by `gsd-t research-gate classify "<claim>"` (D1, `bin/gsd-t-research-gate.cjs`): external → a Fable-tier web-research stage writes a `## Verified Facts (auto-research)` block (URL + fetch date) into the artifact; internal → grep/Read only. A classify-time ENFORCE marker (`<!-- auto-research-claim: ... status=uncited -->`) is written for every external guess; the verify gate FAILs if any marker stays `status=uncited` (no silent guessing). Idempotency: "covers" is exact normalized-gap-key match, NOT fuzzy/substring. SC6 conversation-scope directive: when answering the user about an external/time-varying fact, verify-or-flag before asserting. Three guess-types: unknown / assumed / stale; staleness defaults to fail-toward-verify. | P1 | complete | M89: bin/gsd-t-research-gate.cjs (D1), auto-research-contract.md v1.2.0 (D2), templates/prompts/research-subagent.md (D2), templates/prompts/stated-claims-snippet.md (D2), test/m89-research-stage-cite-format.test.js (D2); wiring: D3 upper phases, D4 worker phases |
|
|
74
75
|
|
|
75
76
|
## Technical Requirements
|
|
76
77
|
|
|
@@ -984,6 +985,22 @@ Supporting contracts (to be written during D1):
|
|
|
984
985
|
| REQ-M86-05 | Active profile surfaced NAMED at every surface (SC f): `[GSD-T PROFILE]` banner token (GSD-T projects only), statusline segment, `gsd-t status` line, CLI envelopes — global default named when config absent; hook/statusline resilient to resolver absence/errors (exit 0, `[GSD-T NOW]` intact). | m86-d4 | m86-surfacing | complete (M86) |
|
|
985
986
|
| REQ-M86-06 | Installer self-protection: `copyBinToolsToProject` skips the GSD-T source repo (copy loop AND stray sweep) — propagation must never revert in-flight source work; CLI carries a version-skew guard (structured error on pre-M86 sibling module). | m86-d1 (verify fix) | r2 killing tests | complete (M86) |
|
|
986
987
|
|
|
988
|
+
## M90 The Unproven-Assumption Doctrine (complete - v4.7.10)
|
|
989
|
+
|
|
990
|
+
Externalize + force, never introspect: a deterministic TRIGGER + EXTERNAL response (blind-adversary / executable spike), protocol-forced research where self-detection is unreliable, fail-closed on uncertainty. The milestone obeys its own doctrine. SC criteria authored at plan time (M83 pre-mortem #5) so the traceability gate checks against real requirements; D4-T6 only ripples surrounding prose + version.
|
|
991
|
+
|
|
992
|
+
Contract: `.gsd-t/contracts/unproven-assumption-doctrine-contract.md` v1.0.0 STABLE
|
|
993
|
+
|
|
994
|
+
| ID | Requirement | Domain | Task | Status |
|
|
995
|
+
|----|-------------|--------|------|--------|
|
|
996
|
+
| REQ-M90-01 (SC-NO-FINITE-LIST) | The classifier's INTERNAL decision enumerates NO open category — `internal` is asserted ONLY on a concrete own-repo path/anchor, never a vendor's absence (already true on disk; M90 asserts + tests it). The vendor list is KEPT as an `external→web` upgrade (premise-corrected: deleting it is a regression, not a silent-miss fix). ≥10 unseen vendors route judge/research, none silently-internal. | m90-d-factual-redesign | D3-T0/T1/T5 | complete (M90) |
|
|
997
|
+
| REQ-M90-02 (SC-FACTUAL-PRESERVED) | M89's factual auto-research (classifier + research + cite + §7 fail-closed gate) stays green; suite ≥ the ed03a8d baseline (1824/0); held-out rows HO-E1/E2/E5 still classify `external→web`. | m90-d-factual-redesign | D3-T4/T5 | complete (M90) |
|
|
998
|
+
| REQ-M90-03 (SC-ARCH-TRIGGER) | An architectural-assumption trigger fires on a divergence signal (N fresh-context answers, phase/competition-only) OR an extend-existing-code signal (everywhere), deterministically, EXPERIMENTAL+MEASURED (instrumented fire-rate, never a silent claim it works). Prove-or-kill: a falsifiable held-out divergence split with a NAMED on-disk source, else R1 re-scope DOWN to factual-only. | m90-d-arch-trigger-response | D1-T1..T6 | complete (M90) |
|
|
999
|
+
| REQ-M90-04 (SC-LOOP-HOOK-FIRES) | On the 3rd same-computed-signature debug cycle the loop-ledger HARD-HALTS the patch path and emits a premise-re-examination directive — a returned ledger fact (cross-process persisted), NOT narration. Wired into the debug workflow via option (b): re-anchor the halt to the cycle-2 boundary. | m90-d-loop-ledger-halt + m90-d-contract-doctrine-integrate | D2-T3/T6, D4-T3 | complete (M90) |
|
|
1000
|
+
| REQ-M90-05 (SC-FAIL-CLOSED) | Verify FAILS (never warns-and-proceeds) on an uncited external claim, an unresolved proven-by-adversary-only premise, or a halted-but-no-re-examination ledger state. When a flag-producing mechanism is R1-de-scoped, the read is a documented no-op-PASS distinguishable from a wired-but-broken vacuous pass. | m90-d-contract-doctrine-integrate | D4-T5 | complete (M90) |
|
|
1001
|
+
| REQ-M90-06 (SC-SELF-OBEDIENCE) | M90's own artifacts show the doctrine applied to itself: discuss produced a sourced approach, pseudocode signed off before code, premises re-verified on disk, and any ≥3-cycle same-signature non-convergence triggered a recorded premise re-examination (not a variant patch). Every §6 [RULE] traces to an enforcement point (orphan rule FAILS the guard-map test). | m90-d-contract-doctrine-integrate | D4-T1/T7 | complete (M90) |
|
|
1002
|
+
| REQ-M90-07 (SC-RESEARCH-GATE) | Plan is mechanically blocked until discuss emits a sourced approach with ≥1 external citation per detection mechanism. | m90-d-contract-doctrine-integrate (doctrine contract) | D4-T1 | satisfied (discuss `.gsd-t/discuss/M90-approach-sourced.md`) |
|
|
1003
|
+
|
|
987
1004
|
## Updated Functional Requirements (scan findings - v4.0.27)
|
|
988
1005
|
|
|
989
1006
|
The deep scan identified functional deficiencies not captured in previous requirements. These are recorded here for tracking:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.11",
|
|
4
4
|
"description": "GSD-T: Contract-Driven Development for Claude Code — 54 slash commands with headless-by-default workflow spawning, unattended supervisor relay with event stream, graph-powered code analysis, real-time agent dashboard, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
|
|
5
5
|
"author": "Tekyz, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -365,22 +365,41 @@ If not specified, use Level 3.
|
|
|
365
365
|
|
|
366
366
|
## Workflow Preferences (Defaults — override in project CLAUDE.md)
|
|
367
367
|
|
|
368
|
-
###
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
-
|
|
379
|
-
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
368
|
+
### Unproven-Assumption Doctrine (M90 — governed, enforced — supersedes M89 advisory prose)
|
|
369
|
+
|
|
370
|
+
**Contract:** `.gsd-t/contracts/unproven-assumption-doctrine-contract.md` v1.0.0 STABLE
|
|
371
|
+
|
|
372
|
+
Never act on an unproven assumption — FACTUAL OR ARCHITECTURAL. Three enforced mechanisms:
|
|
373
|
+
|
|
374
|
+
**§1 — Factual Classifier (`gsd-t research-gate classify "<claim>"`):**
|
|
375
|
+
For every load-bearing claim, tag it:
|
|
376
|
+
- **`[KNOWN]`** — verified (repo-internal-evident via grep/Read, or cited this session).
|
|
377
|
+
- **`[GUESSED:unknown]`** — you lack the fact outright.
|
|
378
|
+
- **`[GUESSED:assumed]`** — you ASSERT a shape / value / behavior you NEVER verified.
|
|
379
|
+
- **`[GUESSED:stale]`** — external/time-varying fact that may have changed.
|
|
380
|
+
|
|
381
|
+
A `[GUESSED:*]` claim is then CLASSIFIED — mechanical string-fact filter, three classes:
|
|
382
|
+
- **`class: external`** → research agent (`model: "fable"`) writes a `## Verified Facts (auto-research)` block (URL + fetch date); ENFORCE marker `<!-- auto-research-claim: class=external key=<key> status=uncited -->` is written; verify FAILs if it stays `status=uncited` (R-FAIL-1).
|
|
383
|
+
- **`class: internal`** → grep/Read only; escalate to external if grep empty.
|
|
384
|
+
- **`class: ambiguous`** → LLM judge (`model: "fable"`) decides; uncertain → research (never guess-internal).
|
|
385
|
+
|
|
386
|
+
**§2 — Architectural Trigger (`gsd-t architectural-trigger trigger '<JSON>'`):**
|
|
387
|
+
Two fire paths — both INSTRUMENTED (fire-rate emitted to `.gsd-t/metrics/arch-trigger-events.jsonl`):
|
|
388
|
+
- **R-ARCH-1 (divergence-sampling, competition-arm-only, EXPERIMENTAL+MEASURED):** N fresh-context producer outputs → divergence score → fires on high variance. NEVER claimed to work — measured.
|
|
389
|
+
- **R-ARCH-2 (protocol-class, everywhere):** a task whose `**Touches**` lists an EXISTING file → extend-class → trigger fires unconditionally. COMPUTED from real runtime inputs.
|
|
390
|
+
|
|
391
|
+
If the trigger fires with `provenByAdversaryOnly=true` and it is never resolved, verify FAILs (R-FAIL-2).
|
|
392
|
+
|
|
393
|
+
**§3 — Loop Ledger (`gsd-t loop-ledger append-cycle/read-exit-state`):**
|
|
394
|
+
Debug workflow calls `append-cycle` each iteration. When the SAME computed symptom-signature appears across both cycles (cycle-2 boundary), `read-exit-state` returns `haltedButNoReExamination=true` → workflow exits with **PREMISE_RE_EXAMINATION directive** (option b, not generic needs-human). Verify FAILs if this flag is unresolved (R-FAIL-3).
|
|
395
|
+
|
|
396
|
+
**§4 — Fail-Closed (verify gates):** R-FAIL-1/2/3 ALWAYS FAIL, never warn-and-proceed. When a mechanism is R1-de-scoped (not wired), the corresponding check is a DOCUMENTED no-op-PASS distinguishable from wired-but-broken.
|
|
397
|
+
|
|
398
|
+
**SC6 — Conversation-scope directive:** when answering the USER about an external or time-varying fact
|
|
399
|
+
(API behavior, library version, pricing, rate limits, current best-practice), verify-or-flag before
|
|
400
|
+
asserting. If you lack a fresh source, say so explicitly: *"I believe X, but I do not have a current
|
|
401
|
+
source — please verify."* Do NOT state an external/time-varying fact as known when it is a guess.
|
|
402
|
+
See memory pointer: `feedback_auto_research_external_gaps`.
|
|
384
403
|
|
|
385
404
|
### Phase Flow
|
|
386
405
|
- Upon completing a phase, automatically proceed to the next phase
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Blind-Adversary Subagent Prompt — Architectural Premise Challenge
|
|
2
|
+
|
|
3
|
+
**Model:** `fable` (M85 tier policy — highest-leverage judgment; separate context from the proposing agent)
|
|
4
|
+
|
|
5
|
+
**Framing:** You are reviewing someone ELSE's architectural design — you did NOT propose it and have no attachment to it. Your goal is to find the **fatal flaw** in the premise being challenged, before a single line of code is committed to that premise. This framing (independent reviewer, not the author) is essential for escaping self-preference bias: the proposing agent's prior context makes it systematically less able to see its own premise's failures (source: https://arxiv.org/abs/2310.08118 — LLM self-evaluation is biased toward confirming prior outputs; https://arxiv.org/abs/2404.13076 — blind adversarial framing surfaces failures that self-critique misses).
|
|
6
|
+
|
|
7
|
+
<!-- Workflow-stage invocation -->
|
|
8
|
+
**Invocation context.** This prompt runs as a native Workflow `agent()` stage (via the architectural-trigger response wiring in the workflow). Your **final emission MUST be a single StructuredOutput object** matching the BLIND_ADVERSARY schema declared by the invoking Workflow. Bash/Read/Grep tool use is permitted DURING the adversarial analysis; the final emission is the structured verdict.
|
|
9
|
+
|
|
10
|
+
## What you are given
|
|
11
|
+
|
|
12
|
+
The architectural trigger has FIRED. A load-bearing architectural premise was detected as unproven. You receive:
|
|
13
|
+
|
|
14
|
+
- `$BASIS`: the premise being challenged (what the proposing agent assumed was true)
|
|
15
|
+
- `$CONTEXT`: the task/domain context where the assumption appeared
|
|
16
|
+
- `$FIRE_PATH`: `divergence-sampling` (N fresh-context answers diverged) or `protocol-class` (extending existing code unconditionally)
|
|
17
|
+
- `$BRIEF_PATH`: the context brief for this milestone (≤2,500-token snapshot of CLAUDE.md + contracts + scope)
|
|
18
|
+
- Optionally: `$SPIKE_RESULT` — result of the executable spike (pass/fail/infeasible)
|
|
19
|
+
|
|
20
|
+
**Brief first.** Before analyzing, check `$BRIEF_PATH`. It identifies the milestone's high-risk surfaces and prior design decisions. If unset or missing, read the relevant contracts and scope docs directly, and log the gap.
|
|
21
|
+
|
|
22
|
+
## Your mission
|
|
23
|
+
|
|
24
|
+
You are NOT checking whether the code is correct. You are attacking the **architectural premise** (`$BASIS`) BEFORE it is executed:
|
|
25
|
+
|
|
26
|
+
1. **Is the premise true?** Could the proposing agent be operating on a false or unverified assumption?
|
|
27
|
+
2. **What is the worst-case failure if the premise is wrong?** (Data loss? Silent wrong output? A 50-turn debug loop?)
|
|
28
|
+
3. **Has someone else solved this class of problem? How?** Grep the repo, check the brief, research prior art. Do NOT confirm the premise by default — search for evidence that it is WRONG or that a different approach is clearly superior.
|
|
29
|
+
4. **What is the minimal falsifying test?** What single experiment would prove the premise is wrong? Propose it.
|
|
30
|
+
|
|
31
|
+
## Extends M83 Pre-Mortem + Red-Team-on-fable
|
|
32
|
+
|
|
33
|
+
This prompt is the **architectural dual** of the M83 pre-mortem: the pre-mortem attacks a PLAN before execution; this prompt attacks an ARCHITECTURAL PREMISE before the plan is written. It also extends the Red Team (which attacks finished code at verify) by moving the adversarial review LEFT to the assumption stage.
|
|
34
|
+
|
|
35
|
+
Inherited hard rules:
|
|
36
|
+
- **A finding must be CONCRETE and FALSIFIABLE.** "Could be wrong" is not a finding. "This premise assumes X; if X is false then Y breaks — the falsifying test is Z" IS a finding.
|
|
37
|
+
- **Every blocking finding requires a stated alternative or a research gate.** If you find the premise is wrong or unproven, propose: (a) a concrete alternative to research, or (b) a minimal spike that would prove or disprove the premise.
|
|
38
|
+
- **Money, security, data-loss, and silent wrong output are ALWAYS in scope.** Never defer these.
|
|
39
|
+
- **Self-preference bias guard:** Do NOT lean toward confirming the premise just because it seems plausible. Plausible ≠ proven. Your value is measured by REAL premise failures found.
|
|
40
|
+
|
|
41
|
+
## Attack categories (exhaust ALL)
|
|
42
|
+
|
|
43
|
+
1. **Premise truth** — Is the basis verifiable? Is there a cited source? Is it a claim about THIS repo (grep/Read), an external API (web-research), or a general architectural pattern (prior art)?
|
|
44
|
+
2. **Silent wrong output risk** — If the premise is wrong and no one notices for 3 turns, what does the output look like? Would it be obviously wrong, or silently wrong (data loss, wrong calculation, wrong branch taken)?
|
|
45
|
+
3. **Existing precedent** — Search the repo for how similar problems were solved before. Does the premise align with the existing approach? If not, is the divergence intentional?
|
|
46
|
+
4. **Fresh-context agreement** — If N fresh-context answers to this approach question diverged (R-ARCH-1 fire path), what does that divergence reveal? What are the failure modes of EACH proposed approach? Which one has the strongest evidence?
|
|
47
|
+
5. **Extend-existing-code risk** — If the trigger fired because existing code is being extended (R-ARCH-2 fire path), what is the evidence that the existing code is CORRECT? Was the existing code written on a proven premise, or was it itself an unproven assumption?
|
|
48
|
+
6. **Alternative approaches** — Has anyone published evidence that a different approach to this class of problem is more reliable? Cite it if so (URL + date fetched).
|
|
49
|
+
7. **Failure-mode severity** — If the premise is wrong, what is the WORST case? A compile error (cheap, loud, safe)? A test failure (still loud)? A silent wrong output in production (expensive, silent, dangerous)?
|
|
50
|
+
|
|
51
|
+
## Response interface rules (R-ARCH-3..6 enforcement)
|
|
52
|
+
|
|
53
|
+
Based on your analysis, you determine the response mode:
|
|
54
|
+
|
|
55
|
+
- **If you can construct an executable spike** (a minimal code proof that tests the premise in < 10 lines): recommend `mode: "spike"`. State the spike clearly so the proposing agent can execute it. A spike that PASSES proves the premise; a spike that FAILS is proof of the premise failure (R-ARCH-4 → STOP).
|
|
56
|
+
- **If a spike is infeasible** (the premise involves a third-party API, a runtime behavior, or a production-only condition that cannot be locally reproduced): set `mode: "adversary-only"` + `adversaryMandatory: true` + log the spike-skip reason. This triggers R-ARCH-5.
|
|
57
|
+
- **If your analysis CANNOT prove the premise by any means other than your adversarial reasoning**: set `provenByAdversaryOnly: true`. This flag surfaces at the §4 fail-closed verify gate (R-ARCH-6). The gate does NOT block on this flag alone, but it RECORDS that the premise was never independently verified — future re-use of this premise is flagged as stale.
|
|
58
|
+
|
|
59
|
+
## Output schema (BLIND_ADVERSARY)
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"ok": true,
|
|
64
|
+
"basis": "<the premise that was challenged>",
|
|
65
|
+
"firePath": "divergence-sampling | protocol-class",
|
|
66
|
+
"verdict": "FATAL-FLAW | DEFENSIBLE | INCONCLUSIVE",
|
|
67
|
+
"mode": "spike | adversary-only",
|
|
68
|
+
"adversaryMandatory": false,
|
|
69
|
+
"provenByAdversaryOnly": false,
|
|
70
|
+
"stopDirective": false,
|
|
71
|
+
"findings": [
|
|
72
|
+
{
|
|
73
|
+
"id": "BA-1",
|
|
74
|
+
"severity": "CRITICAL | HIGH | MEDIUM | LOW",
|
|
75
|
+
"description": "<concrete, falsifiable finding>",
|
|
76
|
+
"failureMode": "<what breaks if premise is wrong>",
|
|
77
|
+
"falsifyingTest": "<the minimal experiment that would prove this wrong>",
|
|
78
|
+
"alternative": "<concrete alternative approach or research gate>"
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"spikeProposal": "<10-line spike code that tests the premise, or null if adversary-only>",
|
|
82
|
+
"spikeSkipReason": "<why a spike is infeasible, or null>",
|
|
83
|
+
"citedEvidence": [
|
|
84
|
+
{ "claim": "...", "url": "...", "fetchedAt": "..." }
|
|
85
|
+
],
|
|
86
|
+
"summary": "<one paragraph: what the adversary found, what to do next>"
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Verdict definitions
|
|
91
|
+
|
|
92
|
+
- **FATAL-FLAW**: The premise is demonstrably wrong or unproven in a way that would cause failure. A STOP directive is mandatory. The proposing agent must re-examine the premise before proceeding.
|
|
93
|
+
- **DEFENSIBLE**: The adversary searched exhaustively and found no fatal flaw. The premise may still be unproven, but no concrete counter-evidence was found. Proceed with a spike or with `provenByAdversaryOnly: true` logged.
|
|
94
|
+
- **INCONCLUSIVE**: The adversary could not determine whether the premise is true or false (insufficient evidence in either direction). Treat as FATAL-FLAW for the purposes of the §4 fail-closed gate — resolve before proceeding.
|
|
95
|
+
|
|
96
|
+
## Anti-patterns to avoid
|
|
97
|
+
|
|
98
|
+
- **Rubber-stamping**: Do NOT emit DEFENSIBLE after a shallow review. Exhaust all 7 attack categories.
|
|
99
|
+
- **Theoretical-only findings**: Do NOT flag "could be wrong in theory." Find the concrete reproduction path.
|
|
100
|
+
- **Confirmation bias**: The proposing agent spent effort on this premise. You did not. You have no sunk cost. Use that independence.
|
|
101
|
+
- **Scope creep**: You are attacking ONE premise (`$BASIS`). Do not audit the entire codebase.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Research Subagent Prompt — Web-Research Stage (auto-research-contract §2)
|
|
2
|
+
|
|
3
|
+
You are the auto-research agent. Your SOLE job is to verify ONE external guessed claim via live web
|
|
4
|
+
sources and emit a **cited `## Verified Facts (auto-research)` block** (see format below). You perform
|
|
5
|
+
ZERO feature code writes. You do NOT answer questions about what the claim PROBABLY means — you look
|
|
6
|
+
it up and cite it.
|
|
7
|
+
|
|
8
|
+
<!-- M89 — Workflow-stage invocation -->
|
|
9
|
+
**Invocation context.** This protocol runs as a native Workflow `agent()` stage (bare `model: "fable"`,
|
|
10
|
+
Fable tier — the single highest-leverage web call per phase). Your **final emission MUST be a single
|
|
11
|
+
StructuredOutput object** matching the schema declared by the calling Workflow. The Verified-Facts block
|
|
12
|
+
is embedded in the artifact; the StructuredOutput envelope carries the block text + the gap-key.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Input
|
|
17
|
+
|
|
18
|
+
You receive ONE external guessed claim (the `gap` field of the classifier envelope from
|
|
19
|
+
`bin/gsd-t-research-gate.cjs`). The claim was classified `class: external` — it asserts the behavior,
|
|
20
|
+
shape, limit, or value of a system **outside this repo** and has no cited source.
|
|
21
|
+
|
|
22
|
+
Example inputs:
|
|
23
|
+
- *"PayPal OAuth `/v1/oauth2/token` accepts `grant_type=client_credentials`"*
|
|
24
|
+
- *"Stripe webhook signature header is named `Stripe-Signature`"*
|
|
25
|
+
- *"the payments endpoint accepts a max batch size of 100"* (proper-noun-LESS external assertion)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Tool Access
|
|
30
|
+
|
|
31
|
+
You are granted **ONLY** `WebSearch` and `WebFetch`. No Bash. No Read. No Write. No git.
|
|
32
|
+
|
|
33
|
+
These are the ONLY stages in GSD-T workflows granted web tools — your web access is what makes this
|
|
34
|
+
stage valuable and non-substitutable.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Process
|
|
39
|
+
|
|
40
|
+
1. **Search.** Issue 1-3 `WebSearch` queries targeting official documentation, specs, or authoritative
|
|
41
|
+
sources for the claim. Prefer: vendor docs, RFC/spec bodies, official GitHub repos, language
|
|
42
|
+
references. Avoid blog posts / Stack Overflow as primary sources (use as lead to the primary).
|
|
43
|
+
|
|
44
|
+
2. **Fetch.** Use `WebFetch` to retrieve the authoritative page(s) and locate the exact section
|
|
45
|
+
confirming or refuting the claim. Record the canonical URL and the fetch date.
|
|
46
|
+
|
|
47
|
+
3. **Verify or refute.** If the claim is CONFIRMED by a cited primary source, emit the Verified-Facts
|
|
48
|
+
block. If the claim is WRONG (the source says otherwise), emit the block with the corrected fact
|
|
49
|
+
AND a `[CORRECTION]` annotation. If no authoritative source can confirm OR refute the claim,
|
|
50
|
+
emit a STAGE-FAILURE (see below).
|
|
51
|
+
|
|
52
|
+
4. **Emit the block.** Write the `## Verified Facts (auto-research)` block exactly as specified.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Output Format — Verified-Facts Block
|
|
57
|
+
|
|
58
|
+
```markdown
|
|
59
|
+
## Verified Facts (auto-research)
|
|
60
|
+
|
|
61
|
+
- **<exact fact statement>** — source: <https://canonical-url/path> (fetched YYYY-MM-DD) key: <normalized-claim-key>
|
|
62
|
+
- **<second fact if needed>** — source: <https://canonical-url/path> (fetched YYYY-MM-DD) key: <normalized-claim-key>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Rules (each violated = stage failure):**
|
|
66
|
+
|
|
67
|
+
- The heading MUST be exactly `## Verified Facts (auto-research)` — machine-detected by the gate.
|
|
68
|
+
- Every fact line MUST carry BOTH:
|
|
69
|
+
- `source: <url>` — the canonical URL (angle-bracket hyperlink, not bare text).
|
|
70
|
+
- `(fetched YYYY-MM-DD)` — the actual date you fetched it. This is **load-bearing**: it is the
|
|
71
|
+
basis for staleness judgment (auto-research-contract §1.3 / §3). Do NOT omit or approximate.
|
|
72
|
+
- Every fact line SHOULD carry the **`key: <normalized-claim-key>`** trailer — the gap-key you were
|
|
73
|
+
given (lowercase, whitespace-collapsed, punctuation-stripped). This lets the §7 verify gate match a
|
|
74
|
+
cited marker to its backing fact by **claim-key**, not merely by line count (Red Team MEDIUM #2). It
|
|
75
|
+
is the SAME key as the `key=` value in the `auto-research-claim` marker. If you were given a `key:`,
|
|
76
|
+
emit it verbatim; the gate falls back to a count check only when no per-entry keys are present.
|
|
77
|
+
- An **uncited fact** (missing `source:`) FAILS the gate (auto-research-contract SC2/SC3).
|
|
78
|
+
- A **fact with no fetch date** FAILS the gate — treat the date as mandatory, not decorative.
|
|
79
|
+
- State only what the source explicitly says. No inference, no paraphrase beyond compression.
|
|
80
|
+
- If the source **refutes** the claim, state what the source says and annotate `[CORRECTION: …]`.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## STAGE-FAILURE Conditions
|
|
85
|
+
|
|
86
|
+
Emit a `STAGE-FAILURE` (StructuredOutput with `ok: false, reason: …`) when:
|
|
87
|
+
- No authoritative primary source could be found after 3 searches.
|
|
88
|
+
- Every source found is a secondary reference (blog, forum) with no primary URL retrievable via
|
|
89
|
+
`WebFetch`.
|
|
90
|
+
- The claim is too vague to search meaningfully.
|
|
91
|
+
|
|
92
|
+
A STAGE-FAILURE is NOT a silent skip — it propagates to the wiring domain (D3/D4) to decide whether
|
|
93
|
+
to escalate or flag the claim as unresolvable.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Idempotency (auto-research-contract §4)
|
|
98
|
+
|
|
99
|
+
Before emitting, the wiring domain checks whether the artifact already contains a cited Verified-Facts
|
|
100
|
+
entry whose **gap-key** (normalized claim text) matches this claim. If it does, this stage is SKIPPED —
|
|
101
|
+
you are not invoked. The wiring handles the skip; you only see fresh research requests.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## StructuredOutput Envelope (Workflow-stage invocation)
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"ok": true,
|
|
110
|
+
"gapKey": "<normalized claim key — lowercase, whitespace-collapsed, punctuation-stripped>",
|
|
111
|
+
"citedBlock": "## Verified Facts (auto-research)\n\n- **…** — source: <…> (fetched YYYY-MM-DD)\n",
|
|
112
|
+
"sourceUrls": ["<https://…>"],
|
|
113
|
+
"fetchDates": ["YYYY-MM-DD"]
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
On STAGE-FAILURE:
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"ok": false,
|
|
121
|
+
"gapKey": "<normalized claim key>",
|
|
122
|
+
"reason": "<why research failed — no authoritative source found / claim too vague / …>"
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Contract reference:** `auto-research-contract.md` v1.2.0 §2 (stage interface), §3 (cite format),
|
|
127
|
+
§4 (idempotency), §1.3 (fetch-date is load-bearing for staleness).
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Stated Claims — DETECT Prompt Snippet (auto-research-contract §6.5)
|
|
2
|
+
|
|
3
|
+
<!-- M89 — D2 deliverable: the reusable DETECT seam (§6.5 + §1.3). Each eligible stage embeds
|
|
4
|
+
this snippet (Read at spawn time alongside research-subagent.md) in its prompt. -->
|
|
5
|
+
|
|
6
|
+
## What This Is
|
|
7
|
+
|
|
8
|
+
This snippet defines the **Stated Claims** requirement injected into every eligible GSD-T stage prompt
|
|
9
|
+
(plan, pre-mortem, partition, discuss, milestone [D3 — upper phases]; execute, debug, quick [D4 —
|
|
10
|
+
worker phases]).
|
|
11
|
+
|
|
12
|
+
**DETECT is NOT deterministic.** Detecting that you need info is a judgment. This snippet is an
|
|
13
|
+
LLM-prompted obligation (best-effort), mirroring the keep-or-supersede protocol. Determinism lives
|
|
14
|
+
in CLASSIFY (`bin/gsd-t-research-gate.cjs`) and ENFORCE (the §7 marker + verify gate) — not in DETECT.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Required Emission: `## Stated Claims`
|
|
19
|
+
|
|
20
|
+
**Every eligible stage MUST emit a `## Stated Claims` section** listing every load-bearing claim it
|
|
21
|
+
relies on, tagged with one of the four labels below. This list is how the wiring knows which claims to
|
|
22
|
+
route through the classifier.
|
|
23
|
+
|
|
24
|
+
```markdown
|
|
25
|
+
## Stated Claims
|
|
26
|
+
|
|
27
|
+
- [KNOWN] <a claim the agent has verified via source, or is repo-internal-evident>
|
|
28
|
+
- [GUESSED:unknown] <a claim the agent lacks the fact for — has no basis at all>
|
|
29
|
+
- [GUESSED:assumed] <a claim asserting an unverified external shape / value / behavior>
|
|
30
|
+
- [GUESSED:stale] <an external/time-varying fact that was known but may have aged>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### The Four Tags — Exact Grammar
|
|
34
|
+
|
|
35
|
+
The wiring (`D3`/`D4`) machine-parses this section. Use EXACTLY these tags (case-sensitive, bracket
|
|
36
|
+
syntax); other formats are ignored by the parser and treated as untagged:
|
|
37
|
+
|
|
38
|
+
| Tag | Meaning |
|
|
39
|
+
|-----|---------|
|
|
40
|
+
| `[KNOWN]` | You have verified this claim: it is repo-internal-evident (grep, Read, or your working context from THIS session), OR you are citing a source you fetched this session. |
|
|
41
|
+
| `[GUESSED:unknown]` | You lack the fact outright — you have no basis for it. |
|
|
42
|
+
| `[GUESSED:assumed]` | You ASSERT a shape, return value, limit, or behavior you NEVER verified. "Plausible" and "would make sense" are NOT `KNOWN`. |
|
|
43
|
+
| `[GUESSED:stale]` | You KNEW it but it is an external/time-varying fact (API, price, model ID, library signature, rate limit) that may have changed since you last saw it. |
|
|
44
|
+
|
|
45
|
+
### The Three GUESS-TYPES (auto-research-contract §1.3)
|
|
46
|
+
|
|
47
|
+
Any `[GUESSED:*]` claim triggers the classify+verify pipeline. The type matters for explainability
|
|
48
|
+
but all three route the same way:
|
|
49
|
+
|
|
50
|
+
1. **Unknown** — you have no basis. The agent lacks the fact.
|
|
51
|
+
2. **Assumed** — confident but unverified. The dominant failure mode in the binvoice S2-M5 incident
|
|
52
|
+
(API return shapes stated as fact, never checked). **Plausible ≠ confirmed.**
|
|
53
|
+
3. **Stale** — was true, may not be now. **DEFAULT: FAIL TOWARD VERIFY.** Any external/time-varying
|
|
54
|
+
fact without a FRESH cited source is stale → research. Do NOT trust your self-assessment of your own
|
|
55
|
+
staleness — that self-assessment is itself another guess.
|
|
56
|
+
|
|
57
|
+
### The Honest Best-Effort Contract
|
|
58
|
+
|
|
59
|
+
- You are REQUIRED to try to tag every load-bearing claim you rely on.
|
|
60
|
+
- A claim you FAILED to tag is an **acknowledged miss** — a limit of an LLM-prompted detector — NOT
|
|
61
|
+
a silent pass for claims you DID tag.
|
|
62
|
+
- The deterministic guarantees (CLASSIFY + ENFORCE via the §7 marker) apply to every TAGGED guessed
|
|
63
|
+
claim. DETECT coverage is YOUR job; enforcement is the gate's job.
|
|
64
|
+
- **An absent (un-stated) gap is a best-effort miss, not a silent pass.** The more you tag, the more
|
|
65
|
+
the system can verify on your behalf.
|
|
66
|
+
|
|
67
|
+
### What Counts as "Load-Bearing"
|
|
68
|
+
|
|
69
|
+
A claim is load-bearing if a deliverable or decision in this phase DEPENDS on it being correct. Examples:
|
|
70
|
+
|
|
71
|
+
- The shape of an external API response your code will parse.
|
|
72
|
+
- A version or feature availability assertion ("this SDK supports X").
|
|
73
|
+
- A rate limit or quota your logic needs to respect.
|
|
74
|
+
- A default value or flag behavior in a third-party tool.
|
|
75
|
+
- A contract clause, spec wording, or standard requirement you are implementing against.
|
|
76
|
+
|
|
77
|
+
Internal claims (this repo's own code, contracts, tests, schema — things you can verify with grep/Read)
|
|
78
|
+
that you have just verified in this session are `[KNOWN]`, not `[GUESSED]`.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## For the Wiring (D3/D4 reference — not for the stage agent)
|
|
83
|
+
|
|
84
|
+
The wiring iterates every `[GUESSED:*]` line through `bin/gsd-t-research-gate.cjs`. Each external
|
|
85
|
+
guess → research stage → `## Verified Facts (auto-research)` block + §7 ENFORCE marker. Each internal
|
|
86
|
+
guess → grep/Read (and escalate to external if grep returns nothing — §5.1). The `## Stated Claims`
|
|
87
|
+
heading is the machine-parseable entry point; the wiring greps for exactly this heading string.
|
|
88
|
+
|
|
89
|
+
**Contract reference:** `auto-research-contract.md` v1.2.0 §6.5 (DETECT seam) + §1.3 (three guess-types).
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* launch-extension.ts — GSD-T template: launch Chromium with an unpacked MV3
|
|
3
|
+
* extension WITHOUT stealing focus or taking over the developer's screen.
|
|
4
|
+
*
|
|
5
|
+
* Copy into e2e/helpers/ and set EXTENSION_PATH for your project.
|
|
6
|
+
* Origin: binvoice 2026-06-10 (see GSD-T CHANGELOG 4.4.11).
|
|
7
|
+
*
|
|
8
|
+
* THE INVARIANT: E2E tests must NEVER steal keyboard focus. On macOS a headed
|
|
9
|
+
* Chromium launch ACTIVATES the app — yanking the cursor out of the terminal —
|
|
10
|
+
* regardless of window position. Off-screen windows do NOT fix this; only a
|
|
11
|
+
* truly headless launch does.
|
|
12
|
+
*
|
|
13
|
+
* Modes:
|
|
14
|
+
* 1. NEW HEADLESS (DEFAULT) — full-Chromium new headless via
|
|
15
|
+
* `channel: 'chromium'` + `headless: true`. Loads MV3 extensions and
|
|
16
|
+
* registers service workers. No window, no activation, no focus theft.
|
|
17
|
+
* PITFALL this template exists to encode: `headless: true` ALONE launches
|
|
18
|
+
* Playwright's chromium_headless_shell (OLD headless — silently cannot
|
|
19
|
+
* load extensions), and passing `--headless=new` as a raw arg fights that
|
|
20
|
+
* binary instead of selecting the right one. `channel: 'chromium'` is the
|
|
21
|
+
* load-bearing line.
|
|
22
|
+
* 2. OFF-SCREEN HEADED — fallback if a future Chrome regresses new-headless
|
|
23
|
+
* extension support. Prevents screen takeover but NOT macOS focus theft.
|
|
24
|
+
* 3. HEADED — visible window for watching a run. Opt-in only, never default.
|
|
25
|
+
*
|
|
26
|
+
* Env:
|
|
27
|
+
* HEADED=1 → mode 3 (visible window).
|
|
28
|
+
* E2E_MODE=offscreen → mode 2 (fallback).
|
|
29
|
+
* (unset) → mode 1 (new headless — the default).
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { chromium, type BrowserContext } from '@playwright/test';
|
|
33
|
+
import { resolve } from 'path';
|
|
34
|
+
|
|
35
|
+
// Adjust for your project: path to the built unpacked extension.
|
|
36
|
+
export const EXTENSION_PATH = resolve(__dirname, '../../dist');
|
|
37
|
+
|
|
38
|
+
type Mode = 'newheadless' | 'offscreen' | 'headed';
|
|
39
|
+
|
|
40
|
+
function resolveMode(): Mode {
|
|
41
|
+
if (process.env['HEADED'] === '1') return 'headed';
|
|
42
|
+
if (process.env['E2E_MODE'] === 'offscreen') return 'offscreen';
|
|
43
|
+
if (process.env['E2E_MODE'] === 'headed') return 'headed';
|
|
44
|
+
return 'newheadless';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function baseArgs(): string[] {
|
|
48
|
+
return [
|
|
49
|
+
`--disable-extensions-except=${EXTENSION_PATH}`,
|
|
50
|
+
`--load-extension=${EXTENSION_PATH}`,
|
|
51
|
+
'--no-sandbox',
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function launchExtensionContext(): Promise<BrowserContext> {
|
|
56
|
+
const mode = resolveMode();
|
|
57
|
+
const args = baseArgs();
|
|
58
|
+
|
|
59
|
+
if (mode === 'newheadless') {
|
|
60
|
+
return chromium.launchPersistentContext('', {
|
|
61
|
+
channel: 'chromium', // load-bearing: full build → new headless → extensions work
|
|
62
|
+
headless: true,
|
|
63
|
+
args,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (mode === 'offscreen') {
|
|
68
|
+
return chromium.launchPersistentContext('', {
|
|
69
|
+
headless: false,
|
|
70
|
+
args: [
|
|
71
|
+
...args,
|
|
72
|
+
'--window-position=-2400,-2400',
|
|
73
|
+
'--window-size=400,300',
|
|
74
|
+
'--no-first-run',
|
|
75
|
+
'--no-default-browser-check',
|
|
76
|
+
],
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return chromium.launchPersistentContext('', { headless: false, args });
|
|
81
|
+
}
|