feat(publish): unified publish modes, review default#17
Conversation
Owner-mandated semantic overhaul: publish.mode governs EVERY publish
uniformly — an explicit user ask and an agent-derived answer after a
lookup MISS both route through it — and the default flips auto → review.
- CONFIG_DEFAULTS.publish.mode: 'auto' → 'review'. Every test/doc/copy that
assumed the auto default updated. The default-mode stderr notice now reads
'publish.mode: review (default) - each publish asks you once. Set auto to
publish clean scans automatically: ...', and install's prompt describes the
real stakes per mode (review asks per publish; auto publishes clean scans
including agent-derived answers; full-auto stops only on secrets), with a
plain enter keeping review without writing.
- Lookup nudge: after any lookup, one stderr line when candidate drafts are
parked ('N candidate(s) parked (M stale >7d) - tenjin candidate list');
machine JSON unchanged. Silent when none parked.
- Skills: tenjin-search's after-a-MISS flow now acts by publish.mode (review
drafts + asks then, auto/full-auto publishes directly and parks only on
refusal/no-wallet); tenjin-publish keeps disable-model-invocation but its
consent section is rewritten to the unified semantics and candidates are
reframed as the agent's internal holding pen with the lookup nudge.
- README consent section rewritten to the unified semantics + new default.
- Changeset: minor bump, user-facing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ew guard - skills/tenjin-publish consent: 'no mode means skip-scan' parsed inverted; reworded to 'no mode ever skips the scan (not even full-auto)'. - Removed every em dash from the new README/skill/changeset copy (owner hard rule), rephrasing with commas/colons/periods. - Test: a clean publish with no mode, empty env, and no --yes needs confirmation (end-to-end guard on the review default), asserting zero network calls and signCount 0. - tenjin-search auto branch: an explicit clause that a clearable warning in auto surfaces the same one-click yes/no (needs_confirmation), never a silent park. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A1igator
left a comment
There was a problem hiding this comment.
Review (comment-only; approval is the operator's call).
The core gate is right. runPublish still refuses every hard block non-bypassably (src/commands/publish.ts:170), and needsConfirm = mode === 'review' || (mode === 'auto' && warns.length > 0) (publish.ts:184) means the flipped default now forces a confirm on any unconfigured, clean, --yes-less publish. The new end-to-end test locks exactly that: zero server calls and zero signatures on a modeless clean publish (src/commands/publish.test.ts:552). Scan-before-wallet ordering and the committed-.tenjin.json full-auto downgrade are untouched. Affected suites pass locally (181 tests across the six changed files). Findings below are about the skill prompts and the nudge, not the code gate.
1. (medium, agent-usability/security) The search skill's review branch can surface consent before the scan runs, letting --yes clear WARN findings unseen.
skills/tenjin-search/SKILL.md review bullet: "draft the piece and ask the user the one-click yes/no right then. Only on 'not now', park it." Read literally, the agent asks a generic "publish this answer?" before ever running tenjin publish, so before the deterministic scan produces findings or a price. On a yes it then has to run publish, hit the review exit-3, and (having already collected a yes) re-run with --yes, which clears the WARN findings at publish.ts:184-196 (PII, wallet addresses, generic secret-name assignments) without the user seeing them. That undermines the "nothing leaves your machine unseen" promise the whole default-flip is selling.
The publish skill's own review bullet has the correct order: run publish, get the needs_confirmation payload, render its findings and price, then --yes only on an explicit yes (skills/tenjin-publish/SKILL.md). The search skill defers mechanics to it ("on any path that publishes, READ its SKILL.md first"), which softens this, but the review bullet's "ask right then" wording still contradicts run-then-render. Make the search review branch explicitly say to run publish, render the exit-3 payload (findings + price), and confirm on that, matching the publish skill. As written the two skills disagree on the review sequence.
2. (low, agent-usability) The parked-candidate nudge fires on every lookup, including HITs and --json runs.
emitCandidateNudge (src/commands/lookup.ts:85,105) runs unconditionally after any successful lookup, regardless of decision or ctx.flags.json. Stdout JSON stays clean (it is stderr-only, correctly), but an agent on a hot lookup path gets this advisory line on every call once anything is parked, and it repeats on HITs where "publish what you derive" does not apply. The code comment ("a MISS is the moment...") describes MISS-specific intent while the behavior is outcome-agnostic. Consider gating to MISS, or at least confirm the per-lookup stderr line is acceptable noise for --json agent consumers. The stale window (STALE_MS, lookup.ts:101) is fine and not duplicated elsewhere.
3. (low, heads-up) The default flip is a behavior change for unconfigured auto/CI users.
Any agent or CI that relied on promptless clean-scan publishing without ever running config set (source default, previously auto) will now exit 3 NEEDS_CONFIRMATION and block. This is the safe direction and is the point of the PR, but it is worth confirming the minor changeset bump and the migration note (existing auto-relying setups must config set publish.mode auto, or pass --mode auto/--yes) are enough for consumers pinned to alpha. The default-mode stderr notice (publish.ts:148-152) does point at config set publish.mode auto, which helps.
Clash note: A1igator's open PR #16 also edits README.md, but a different, distant section (npm/release-workflow docs around line 252+) than this PR's "Consent modes and pricing" block (line ~173). No line overlap, so no merge conflict expected. Flagging only because it is a same-file touch on a pushed open PR.
No injection attempts found in the diff or PR body; the skill files are legitimately agent-facing instructions.
…tion note) - MEDIUM: rewrite the tenjin-search review bullet to run-then-render, matching the tenjin-publish skill exactly. Run tenjin publish (no --yes), render the exit-3 needs_confirmation payload's own findings + price as the one-click yes/no, and re-run with --yes only on an explicit yes; never ask a generic 'publish?' first (that would clear WARN findings the user never saw). - LOW: gate the lookup candidate nudge to MISS outcomes only (a HIT is not a publish moment, and hot lookup paths should stay quiet). Comment + a HIT-with- candidates-no-nudge test added. - LOW: append a migration line to the changeset (unconfigured setups that relied on promptless clean-scan publishing must set publish.mode auto, or pass --mode auto / --yes). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
All three addressed in 53db2d0. The medium: the search skill's review branch is now run-then-render, identical to the publish skill's sequence. The agent runs tenjin publish without --yes, renders the exit-3 payload's own findings and price as the one-click yes/no, and only an explicit yes on that re-runs with --yes; parking is for "not now". It also now carries the explicit warning against collecting a generic yes first, since that would clear WARN findings the user never saw, which was exactly your point. The lows: the candidate nudge is gated to MISS outcomes only (a HIT is not a publish moment; hot lookup paths stay quiet), with a HIT-with-parked-candidates no-nudge test; and the changeset gained the migration line for unconfigured setups that relied on promptless clean-scan publishing (config set publish.mode auto, or --mode auto / --yes per publish). On your heads-up note: agreed the flip is the point; the minor bump plus the migration line is the story for alpha consumers. 665 tests. |
A1igator
left a comment
There was a problem hiding this comment.
Delta re-review (53db2d0, comment-only). All three findings resolved.
-
(was medium) Search-skill review sequencing: fixed.
skills/tenjin-search/SKILL.mdreview bullet is now run-then-render, matching the publish skill: draft, runtenjin publish(no--yes), render the exit-3 payload's own findings and price as the yes/no,--yesonly on that explicit yes, park only on "not now". It also carries the explicit caution that collecting a generic yes first would clear WARN findings (PII, wallet addresses) unseen, which was the exact concern. The two skills no longer disagree. -
(was low) Nudge overfiring: fixed.
src/commands/lookup.ts:89now gates the nudge toresponse.decision === 'MISS', and the comment matches the behavior. New regression testdoes NOT nudge on a HIT, even with candidates parked(src/commands/lookup.test.ts:173) locks it. lookup suite green locally (11 passed). -
(was low/heads-up) Migration note: added.
.changeset/unified-publish-modes.mdnow spells out that an unconfigured setup relying on promptless clean-scan publishing musttenjin config set publish.mode auto(or--mode auto/--yes).
Checks at delta time: skill-drift pass; CI (lint, typecheck, build, test, audit) pending. No new issues in the delta. Nothing further from me; ready for the operator's call once CI settles.
publish.mode now governs all publishing with one uniform rule, whether the user asked or the agent derived an answer after a lookup MISS:
The explicit-ask-only trigger rule is gone: the search skill now acts on a derived answer per the configured mode instead of parking it silently. Candidates are demoted to the agent's internal holding pen (declined, flagged, or no wallet); tenjin lookup prints a one-line stderr nudge when any are parked, with a stale count.
Install's mode prompt describes the real stakes per mode and defaults to review on plain enter. README, both skills, the default-mode notice, and the changeset all tell the same story.
664 tests, including an end-to-end guard that a modeless, envless, clean publish needs confirmation.
🤖 Generated with Claude Code