gossipcat 0.4.30 → 0.4.31

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/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  </p>
8
8
 
9
9
  <p align="center">
10
- <a href="https://www.npmjs.com/package/gossipcat"><img src="https://img.shields.io/npm/v/gossipcat?color=0ea5e9" alt="npm version" /></a>
10
+ <a href="https://www.npmjs.com/package/gossipcat"><img src="https://img.shields.io/npm/v/gossipcat?color=0ea5e9&v=0430" alt="npm version" /></a>
11
11
  <a href="https://www.npmjs.com/package/gossipcat"><img src="https://img.shields.io/npm/dw/gossipcat?color=0ea5e9" alt="npm weekly downloads" /></a>
12
12
  <a href="https://github.com/gossipcat-ai/gossipcat-ai/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT License" /></a>
13
13
  <a href="#quickstart"><img src="https://img.shields.io/badge/node-22%2B-green" alt="Node 22+" /></a>
@@ -85,15 +85,14 @@ The core difference: gossipcat verifies findings against actual `file:line` cita
85
85
 
86
86
  ## Real-world session
87
87
 
88
- What a typical gossipcat session looks like in practice (2026-04-29):
88
+ What a typical gossipcat session looks like in practice (2026-05-22, v0.4.30 ship):
89
89
 
90
- - **2 PRs shipped** — #317 (env-scrub fix, e180d41) and #318 (test hardening, cac57db), both through full consensus before merge
91
- - **1 consensus round** on PR #317round `591af14b-3f674c9c`, 9 confirmed / 0 disputed findings
92
- - **1 stale backlog item correctly identified** — write-time insight filter was already shipped in a prior session; the `verify-the-premise` skill caught it before sonnet-implementer started redundant implementation work
93
- - **1 spec correctly deferred** — age-based archive pruning: full scan found 0 candidates meeting the threshold; design locked in docs, not built (right call)
94
- - **1 hallucination caught** on haiku-researcher — extrapolated from a 50-row sample when the full dataset was needed; `hallucination_caught` signal recorded, accuracy score updated, no fix shipped on bad data
90
+ - **1 feature shipped end-to-end** — consensus auto-verify (PR #448, master commit `4b28a1c`, 1255+ LOC, 50/50 new tests, zero regressions). Full design ↔ ship arc through gossipcat itself: 6 consensus rounds on the spec before any code was written.
91
+ - **6 consensus rounds on the spec** caught **21+ HIGH-severity defects** across rev-1 → rev-6 including a double-dispatch bug on the `run()` path (rev-3, opus-implementer), a phantom `AgentTeam` type the implementer would have invented if shipped (rev-5, sonnet-reviewer grep-grounded against live `AgentConfig`), and a `metadata` field that didn't exist on `ConsensusSignal` at all (rev-4, sonnet — `metadata` lives only on `MetaSignal` / `PipelineSignal`). Each round produced a measurable rev: rev-1 had 4 HIGHs, rev-6 had 0.
92
+ - **1 post-merge bug caught by a pre-existing drift test** — `signal-allowlist-drift.test.ts:108` (which exists precisely to catch this same failure mode as PR #329's silent-drop of `transport_failure`) flagged that the implementer added the 2 new signals to `KNOWN_SIGNALS` + the type union + `OPERATIONAL_SIGNAL_NAMES` but missed `VALID_CONSENSUS_SIGNALS` in `performance-writer.ts`. 7-line fix landed in the same PR before merge.
93
+ - **Methodology lesson recorded** — sonnet-reviewer's habit of grepping cited file:line against live code (rather than trusting prose claims) is what ultimately closed the spec. Recorded as a `citation_grounding` agreement signal so the agent's pattern compounds across sessions.
95
94
 
96
- The signal pipeline ran the whole session. Nothing landed without cross-review. One agent's score dropped for the sample-extrapolation error.
95
+ Nothing landed without cross-review. Two agents got `+/-` score adjustments based on what they caught vs. what they missed. The spec is now usable as a worked example of what 6 rounds of multi-agent design review looks like — `docs/superpowers/specs/2026-05-21-consensus-auto-verify-design.md`.
97
96
 
98
97
  <br/>
99
98
 
@@ -149,6 +148,12 @@ Real-time view of tasks, consensus reports, agent scores, and activity feed. Ter
149
148
  Per-agent cognitive memory persists across sessions. Agents remember past findings, patterns, and project context.
150
149
  </td>
151
150
  </tr>
151
+ <tr>
152
+ <td align="center" colspan="3">
153
+ <h3>Auto-Verify (v0.4.30)</h3>
154
+ Opt-in. Every UNVERIFIED finding gets <code>file_read</code>-checked by a verifier agent before the report is returned. <code>tag</code> stays <code>'unverified'</code> — auto-verify is metadata, not state transition. Flag: <code>GOSSIP_CONSENSUS_AUTO_VERIFY_UNVERIFIED=1</code>.
155
+ </td>
156
+ </tr>
152
157
  </table>
153
158
 
154
159
  <br/>
@@ -50040,10 +50040,16 @@ function stampConcurrencyTaint(map2) {
50040
50040
  }
50041
50041
  return true;
50042
50042
  }
50043
- function elidePromptIfRequested(projectRoot, taskId, agentPrompt, promptFormat, warmCached = false) {
50043
+ function elidePromptIfRequested(projectRoot, taskId, agentPrompt, promptFormat, warmCached = false, writeMode) {
50044
50044
  if (promptFormat !== "elided") return { elided: false };
50045
- const bytes = Buffer.byteLength(agentPrompt, "utf8");
50046
- const promptPath = writeDispatchPrompt(projectRoot, taskId, agentPrompt);
50045
+ const body = writeMode === "worktree" ? `// GOSSIP_ISOLATION: worktree
50046
+ // This task was dispatched with write_mode: "worktree".
50047
+ // The orchestrator MUST invoke Agent() with isolation: "worktree".
50048
+ // Do not paraphrase this requirement.
50049
+
50050
+ ` + agentPrompt : agentPrompt;
50051
+ const bytes = Buffer.byteLength(body, "utf8");
50052
+ const promptPath = writeDispatchPrompt(projectRoot, taskId, body);
50047
50053
  const warmSuffix = warmCached ? " \u2014 warm-cached (skills) + live task" : "";
50048
50054
  const marker = `[skills section elided: see ${promptPath}, ${bytes} bytes${warmSuffix} \u2014 READ this file and pass its CONTENTS verbatim as the Agent(prompt: ...) value. Do NOT pass the path string.]`;
50049
50055
  return { elided: true, promptPath, marker, bytes };
@@ -50415,17 +50421,31 @@ Task: ${task}`;
50415
50421
  worktreePath: void 0,
50416
50422
  timestamp: Date.now()
50417
50423
  });
50418
- const elision = elidePromptIfRequested(process.cwd(), taskId, agentPrompt, prompt_format, singleWarm);
50424
+ const elision = elidePromptIfRequested(
50425
+ process.cwd(),
50426
+ taskId,
50427
+ agentPrompt,
50428
+ prompt_format,
50429
+ singleWarm,
50430
+ useWorktree ? "worktree" : void 0
50431
+ );
50419
50432
  if (elision.elided) {
50420
50433
  const info = ctx.nativeTaskMap.get(taskId);
50421
50434
  if (info) info.promptPath = elision.promptPath;
50422
50435
  }
50423
50436
  persistNativeTaskMap();
50437
+ const promptRef = elision.elided ? "<file contents>" : `<AGENT_PROMPT:${taskId} below>`;
50438
+ const agentCall = useWorktree ? `Agent(
50439
+ model: "${nativeConfig.model}",
50440
+ prompt: ${promptRef},
50441
+ isolation: "worktree", // REQUIRED \u2014 do not omit
50442
+ run_in_background: true
50443
+ )` : `Agent(model: "${nativeConfig.model}", prompt: ${promptRef}, run_in_background: true)`;
50424
50444
  const promptInstruction = elision.elided ? `Step 1 \u2014 ${elision.marker}
50425
- Agent(model: "${nativeConfig.model}", prompt: <file contents>${useWorktree ? ', isolation: "worktree"' : ""}, run_in_background: true)
50445
+ ${agentCall}
50426
50446
 
50427
50447
  ` : `Step 1 \u2014 Pass the AGENT_PROMPT:${taskId} content item below verbatim to Agent(prompt: ...):
50428
- Agent(model: "${nativeConfig.model}", prompt: <AGENT_PROMPT:${taskId} below>${useWorktree ? ', isolation: "worktree"' : ""}, run_in_background: true)
50448
+ ${agentCall}
50429
50449
 
50430
50450
  `;
50431
50451
  return { content: [
@@ -50437,8 +50457,10 @@ NATIVE_DISPATCH: Execute this via Claude Code Agent tool, then relay the result.
50437
50457
  Task ID: ${taskId}
50438
50458
  Agent: ${agent_id}
50439
50459
  Model: ${nativeConfig.model}
50460
+ ` + (useWorktree ? `Worktree isolation: REQUIRED \u2014 Agent() MUST be invoked with isolation: "worktree"
50440
50461
 
50441
- ` + promptInstruction + `Step 2 \u2014 REQUIRED after agent completes:
50462
+ ` : `
50463
+ `) + promptInstruction + `Step 2 \u2014 REQUIRED after agent completes:
50442
50464
  gossip_relay(task_id: "${taskId}", relay_token: "${relayToken}", result: "<agent output>")
50443
50465
  (VERBATIM \u2014 pass the agent's raw output; do NOT paraphrase or summarize, or <agent_finding> tags will be lost)
50444
50466
 
@@ -50680,15 +50702,24 @@ Task: ${def.task}`;
50680
50702
  worktreePath: void 0,
50681
50703
  timestamp: Date.now()
50682
50704
  });
50683
- const parallelElision = elidePromptIfRequested(process.cwd(), taskId, agentPrompt, prompt_format, parallelWarm);
50705
+ const parallelElision = elidePromptIfRequested(process.cwd(), taskId, agentPrompt, prompt_format, parallelWarm, def.write_mode);
50684
50706
  if (parallelElision.elided) {
50685
50707
  const info = ctx.nativeTaskMap.get(taskId);
50686
50708
  if (info) info.promptPath = parallelElision.promptPath;
50687
50709
  }
50688
50710
  const parallelPromptRef = parallelElision.elided ? parallelElision.marker : `<AGENT_PROMPT:${taskId} below>`;
50711
+ const parallelUseWorktree = def.write_mode === "worktree";
50712
+ const parallelWorktreeBanner = parallelUseWorktree ? `
50713
+ Worktree isolation: REQUIRED \u2014 Agent() MUST be invoked with isolation: "worktree"` : "";
50714
+ const parallelAgentCall = parallelUseWorktree ? `Agent(
50715
+ model: "${nativeConfig.model}",
50716
+ prompt: ${parallelPromptRef},
50717
+ isolation: "worktree", // REQUIRED \u2014 do not omit
50718
+ run_in_background: true
50719
+ )` : `Agent(model: "${nativeConfig.model}", prompt: ${parallelPromptRef}, run_in_background: true)`;
50689
50720
  lines.push(` ${taskId} \u2192 ${def.agent_id} (native \u2014 dispatch via Agent tool)`);
50690
50721
  nativeInstructions.push(
50691
- `[${taskId}] Agent(model: "${nativeConfig.model}", prompt: ${parallelPromptRef}${def.write_mode === "worktree" ? ', isolation: "worktree"' : ""}, run_in_background: true)
50722
+ `[${taskId}] ${parallelAgentCall}${parallelWorktreeBanner}
50692
50723
  \u2192 then: gossip_relay(task_id: "${taskId}", relay_token: "${relayToken}", result: "<output>")`
50693
50724
  );
50694
50725
  if (!parallelElision.elided) {
@@ -50898,16 +50929,25 @@ Task: ${def.task}`;
50898
50929
  }
50899
50930
  }
50900
50931
  agentPrompt = maybeApplyUnverifiedNote(agentPrompt, def.task, def.agent_id);
50901
- const consensusElision = elidePromptIfRequested(process.cwd(), taskId, agentPrompt, prompt_format, consensusWarm);
50932
+ const consensusElision = elidePromptIfRequested(process.cwd(), taskId, agentPrompt, prompt_format, consensusWarm, def.write_mode);
50902
50933
  if (consensusElision.elided) {
50903
50934
  const info = ctx.nativeTaskMap.get(taskId);
50904
50935
  if (info) info.promptPath = consensusElision.promptPath;
50905
50936
  persistNativeTaskMap();
50906
50937
  }
50907
50938
  const consensusPromptRef = consensusElision.elided ? consensusElision.marker : `<AGENT_PROMPT:${taskId} below>`;
50939
+ const consensusUseWorktree = def.write_mode === "worktree";
50940
+ const consensusWorktreeBanner = consensusUseWorktree ? `
50941
+ Worktree isolation: REQUIRED \u2014 Agent() MUST be invoked with isolation: "worktree"` : "";
50942
+ const consensusAgentCall = consensusUseWorktree ? `Agent(
50943
+ model: "${nativeConfig.model}",
50944
+ prompt: ${consensusPromptRef},
50945
+ isolation: "worktree", // REQUIRED \u2014 do not omit
50946
+ run_in_background: true
50947
+ )` : `Agent(model: "${nativeConfig.model}", prompt: ${consensusPromptRef}, run_in_background: true)`;
50908
50948
  lines.push(` ${taskId} \u2192 ${def.agent_id} (native \u2014 dispatch via Agent tool)`);
50909
50949
  nativeInstructions.push(
50910
- `[${taskId}] Agent(model: "${nativeConfig.model}", prompt: ${consensusPromptRef}, run_in_background: true)
50950
+ `[${taskId}] ${consensusAgentCall}${consensusWorktreeBanner}
50911
50951
  \u2192 then: gossip_relay(task_id: "${taskId}", relay_token: "${relayToken}", result: "<output>")`
50912
50952
  );
50913
50953
  if (!consensusElision.elided) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gossipcat",
3
- "version": "0.4.30",
3
+ "version": "0.4.31",
4
4
  "description": "Multi-agent orchestration for Claude Code — parallel review, consensus, adaptive dispatch",
5
5
  "mcpName": "io.github.ataberk-xyz/gossipcat",
6
6
  "repository": {