7 Commits

Author SHA1 Message Date
3ce543980d refactor(plugin): drop announce_* params from dialectic_propose_topic
Pairs with Dialectic.Backend@5cf4302 (backend cleanup). New model:

  - Agent calls dialectic_propose_topic (no announce target params)
  - After 201, agent posts a one-time recruitment fabric-send-message
    to an announce-type channel (topic_id + signup deadline + debate
    window + title in the message body)
  - Downstream agents read broadcast → `hf calendar schedule on_call` →
    `dialectic_signup`

Tool description rewritten to teach the new flow. Schema loses 2
properties; execute() loses 2 body fields. No backward compat needed —
backend also drops the columns in migration 003.
2026-05-23 23:46:29 +01:00
955f13d72a build(plugin): isolate dist/, add install.mjs, untrack .js artifacts
Closes the long-standing 'jiti picks stale .js over updated .ts' trap
that silently shipped wrong code at least 5 times during sim e2e. Root
cause was three things compounding:

  1. tsconfig.plugin.json had outDir=plugin (same as rootDir), so tsc
     emitted compiled .js next to .ts sources. jiti's extension resolver
     prefers .js, so the moment a .ts changed without a matching rebuild,
     the .js won and the new code never ran.

  2. The .js artifacts were tracked in git, so even on clean clones the
     stale files came back.

  3. There was no install script. Every deploy was an ad-hoc tar + rsync
     that copied both .ts and .js to the same target dir, recreating the
     race on the install side.

This commit fixes all three together:

  - tsconfig.plugin.json: outDir=dist/dialectic, module/moduleResolution
    flipped from ESNext/bundler to NodeNext/NodeNext (so emitted .js
    works under plain Node ESM at runtime, the only thing jiti and the
    openclaw gateway actually use).
  - .gitignore: /dist/ + plugin/**/*.{js,mjs,cjs,js.map,d.ts}, then
    git rm --cached the 4 existing tracked .js files.
  - scripts/install.mjs (new, ESM): mirrors Fabric.OpenclawPlugin's
    install.mjs pattern — detect, checkDeps, build (clean dist/ first),
    install (copy dist/dialectic/ + openclaw.plugin.json + package.json
    to ~/.openclaw/plugins/dialectic/), configure (plugins.allow,
    plugins.load.paths, plugins.entries.<id>.enabled). Supports
    --install / --build-only / --uninstall / --skip-check / --verbose /
    --openclaw-profile-path / --backend-url.

Verified on sim dind-t2: install.mjs --install produces a plugin
directory with ONLY .js files (no .ts left behind), gateway loads it,
8 tools register cleanly, dialectic_list_topics + fabric-guild-list
work end-to-end.

Plugin is now fully ESM-clean: type=module + NodeNext + .js import
extensions + no bundler-only knobs. Matches the project-wide invariant
[[project-fabric-esm]] (every Fabric subproject is ESM).
2026-05-23 22:44:01 +01:00
63fc342238 feat(plugin): dialectic_list_arguments tool + clarify topic_detail desc
Two changes that fix bug #1 from the first e2e debate run (judge could
not see arguments, returned a hollow 'tie' verdict despite real pro/con
posts being in the DB):

1. New tool `dialectic_list_arguments` — hits the existing backend
   endpoint GET /api/topics/{id}/arguments and returns the full
   transcript (pro/con/judge entries with camp, agent_id, content,
   posted_at) in posted order. Used by judges composing verdicts and
   by debaters reading what opponents have said.

2. Updated `dialectic_topic_detail` description to make the split
   explicit: it returns the new camps array (added in the matching
   backend commit) so agents can locate their own allocation, but
   does NOT return arguments — list_arguments is the right tool.

Manifest contracts.tools updated (jiti loader requires this — see
[[reference-meridian-plugin-contract]]) plus internal logger count
bumped from 7 → 8 tools.

E2e verified on sim:
  - main agent calls topic_detail → sees camps array with self as 'pro'
  - judge agent calls list_arguments → reads pro/con content
  - judge rationale directly quotes claims from both sides
  - topic → completed with non-trivial binary verdict

Deploy note: jiti prefers .js when colocated; deploy must rm src/*.js
or pre-build before the new .ts takes effect (see e2e findings memory).
2026-05-23 22:03:49 +01:00
dd4c58ec8c fix(plugin): inject pcexec env for secret-mgr + add DIALECTIC_PLUGIN_BYPASS_HF sim escape hatch
Two pre-existing issues surfaced during sim e2e of a full debate:

1. **secret-mgr env injection**: backend-client's resolveApiKey ran
   execSync('secret-mgr get dialectic-agent-apikey') without setting
   AGENT_ID/AGENT_WORKSPACE/AGENT_VERIFY in the child env. The plugin
   process inherits the openclaw gateway env (no agent context), so
   secret-mgr refused with 'AGENT_VERIFY mismatch' and the error
   surfaced to agents as the generic 'dialectic api key not provisioned'
   (stderr was swallowed by stdio:'ignore'). Now we explicitly inject
   the pcexec trio plus PATH=~/.openclaw/bin:..., capture stderr so
   underlying failures are visible, and use the standard
   ~/.openclaw/workspace/workspace-<id> layout if AGENT_WORKSPACE
   isn't already set.

2. **DIALECTIC_PLUGIN_BYPASS_HF=1 sim escape hatch**: HarborForge's
   hasOnCallCovering returns false on sim (sim agents have no real
   on_call slots), which blocks dialectic_signup before it ever reaches
   the backend. Added an env-gated skip so sim/test environments can
   run the full debate flow without provisioning real schedules.
   Bypass is opt-in via env, so prod is unaffected.

E2e verified on sim dind-t2 (openclaw) + dind-t3 (backend):
  - recruiter/main/simdev minted dialectic-agent-apikey
  - propose_topic created topic
  - 3 signups all 201
  - ticker allocated pro=main, con=simdev, judge=recruiter
  - pro+con posted arguments to round 0
  - judge submitted binary verdict after debate_end_at, topic→completed
  - view_verdict round-trips

Deploy note: jiti loader prefers .js over .ts when both are present in
src/, so updates that only change .ts need the colocated .js removed
(or properly rebuilt) before they take effect. The plugin still ships
src/*.js as pre-built artifacts; consider switching to .ts-only
sources or running 'npm run build' before deploy.
2026-05-23 20:19:14 +01:00
f6c1f392f6 feat(tools): propose_topic gains announce_guild_base_url + announce_channel_id
Operator decision: backend env hard-coding a single guild/channel was
wrong. Center can host multiple guilds, each can have multiple
announce channels for different purposes. The proposing agent picks
which one this topic broadcasts to.

dialectic_propose_topic tool schema adds:
- announce_guild_base_url (string, optional)
- announce_channel_id    (string, optional)
- both or neither - one-of-two rejected at backend POST time
- omit both - topic has no broadcasts (agents must poll detail)

Tool description points agents at "Fabric channel-list tools" for
candidate discovery. Workflow docs spell out the discovery pattern.
2026-05-23 17:54:12 +01:00
119d79ada3 feat: add dialectic_submit_verdict tool (was missing — judge had no way to submit)
7 tools total now:
- dialectic_list_topics
- dialectic_topic_detail
- dialectic_propose_topic
- dialectic_signup
- dialectic_post_argument
- dialectic_submit_verdict (NEW — POST /api/topics/{id}/verdict)
- dialectic_view_verdict

Also added contracts.tools entry for the new tool, updated README +
startup log line. Sim smoke verified the other 4 (list/propose/signup/
detail) via direct plugin import; submit_verdict not yet smoke-tested
end-to-end (requires running through a full debate to debate_end_at).
Code path is identical to other write tools — bearer + JSON body +
shape-coerced response.
2026-05-23 13:10:44 +01:00
db85d7dc69 feat: initial Dialectic.OpenclawPlugin — agent tools for Dialectic v2
Phase 3 of DIALECTIC-V2. Six tools wired to the Go backend running on
server.t3:

- dialectic_list_topics      GET  /api/topics
- dialectic_topic_detail     GET  /api/topics/{id}
- dialectic_propose_topic    POST /api/topics
- dialectic_signup           POST /api/topics/{id}/signups (HF pre-check)
- dialectic_post_argument    POST /api/topics/{id}/arguments
- dialectic_view_verdict     GET  /api/topics/{id}/verdict

All tools return MCP {content:[{type:text,text}]} shape. Errors caught
and surfaced as text payload so agents see actionable failure messages.

Per-agent API key resolved via secret-mgr key dialectic-agent-apikey
(cached in memory; AGENT_VERIFY env required). HF on_call coverage
check degrades gracefully to skipped if HarborForge.OpenclawPlugin
does not yet expose hasOnCallCovering() — backend stores pre_validated
flag as audit signal.

openclaw.plugin.json declares both contracts.tools (the 6 names) AND
activation.onStartup:true per loader gotchas memory; missing either
silently drops the plugin.

Plain export default {id, name, register} entry shape matching
prism-facet. No openclaw SDK imports (jiti runtime resolution of
openclaw was flaky in HF-style entries; structurally simpler avoids
the lookup entirely).

Defaults backendUrl to https://dialectic-api.hangman-lab.top; override
via openclaw.json plugins.entries.dialectic.config.backendUrl for sim.

Phase 3 deferred items (in README): agent key provisioning workflow,
HF window-coverage accessor, SSE subscription tool, token-cost
reporting.
2026-05-23 13:04:12 +01:00