Skip to content

feat(publish): unified publish modes, review default#17

Merged
vraspar merged 3 commits into
mainfrom
feat/unified-publish-modes
Jul 23, 2026
Merged

feat(publish): unified publish modes, review default#17
vraspar merged 3 commits into
mainfrom
feat/unified-publish-modes

Conversation

@vraspar

@vraspar vraspar commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

publish.mode now governs all publishing with one uniform rule, whether the user asked or the agent derived an answer after a lookup MISS:

  • review (the new default): every publish surfaces as one in-harness yes/no. An unconfigured user can never hit a promptless publish.
  • auto: a clean scan publishes immediately, including agent-derived answers; findings surface the same yes/no; detected secrets always refuse.
  • full-auto: warnings do not stop it; only detected secrets do. The committed-.tenjin.json downgrade is unchanged.

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

vraspar and others added 2 commits July 22, 2026 18:20
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 A1igator left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
@vraspar

vraspar commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

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 A1igator left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delta re-review (53db2d0, comment-only). All three findings resolved.

  1. (was medium) Search-skill review sequencing: fixed. skills/tenjin-search/SKILL.md review bullet is now run-then-render, matching the publish skill: draft, run tenjin publish (no --yes), render the exit-3 payload's own findings and price as the yes/no, --yes only 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.

  2. (was low) Nudge overfiring: fixed. src/commands/lookup.ts:89 now gates the nudge to response.decision === 'MISS', and the comment matches the behavior. New regression test does NOT nudge on a HIT, even with candidates parked (src/commands/lookup.test.ts:173) locks it. lookup suite green locally (11 passed).

  3. (was low/heads-up) Migration note: added. .changeset/unified-publish-modes.md now spells out that an unconfigured setup relying on promptless clean-scan publishing must tenjin 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.

@vraspar
vraspar merged commit 686c613 into main Jul 23, 2026
2 checks passed
@vraspar
vraspar deleted the feat/unified-publish-modes branch July 23, 2026 02:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants