Skip to content

feat(publish): answer the marketplace scan gate instead of failing on it - #185

Open
A1igator wants to merge 2 commits into
mainfrom
A1igator/scan-ack-flow
Open

feat(publish): answer the marketplace scan gate instead of failing on it#185
A1igator wants to merge 2 commits into
mainfrom
A1igator/scan-ack-flow

Conversation

@A1igator

@A1igator A1igator commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Scope

The CLI now answers the server-side ingest scan gate, so a warn-tier refusal becomes a decision the operator can act on instead of an opaque exit-4 write failure. src/lib/scan-gate.ts parses the two 422 codes and merges server findings with the local scan's, deduped by detector and offset. src/lib/consent.ts maps them into the exit-3 flow publish and edit already share: scan_blocked is terminal with no acknowledgement path, scan_needs_ack renders once and re-runs the identical content with the ack token on an explicit yes, exactly once. Risk is the wire body: scanAck only ships on a retry the server itself asked for, so a deployment predating the gate never sees the key on a body its strictObject schema would reject.

Mode semantics are the local ones (src/lib/consent.ts acksServerWarnings): review and auto stop on a server warn, full-auto acks it, and ackServerWarnings: false never acks whatever the mode says, which is the seam the unattended observer lane needs later.

Advisory findings on a success response reach the receipt as scan and the human summary as informational lines; findings travel as data, so a detector this release predates renders faithfully and the server stays authoritative under version skew.

Testing

  • pnpm lint, pnpm typecheck, pnpm format:check, pnpm build: clean.
  • pnpm test: 2173 passed, 10 skipped, 69 files.
  • New: 16 unit tests in src/lib/scan-gate.test.ts (envelope parsing, token-never-on-block, unknown detector and tier, merge/dedupe by offset and by value, malformed-finding drop), 11 command tests in publish.test.ts and 5 in edit.test.ts against a stubbed gate (needs_ack hold, token re-run with identical body, full-auto auto-ack, auto stop, never-ack override, unknown-detector render, blocked in every mode, advisory on success, no-token hold, no loop on a second needs_ack), and one renderer test in output.test.ts for the source marker.
  • Every gate test runs against a stubbed response. No live server.

Definition of Done

  • RELEASING.md gains a server-coupled-releases section: the tenjin repo's SCAN_WARN_MODE=enforce flip waits for this release to propagate, which is the whole reason the flag exists.
  • docs/safety-model.md states the client/server split: the local scan runs first so a block-tier secret never leaves the machine; the server is authoritative for the marketplace.
  • Changeset added (minor).

Notes

  • Server sibling: BackTrackCo/tenjin#723 (A1igator/ingest-scan-gate), built against head 5fbed15f. This lands after it merges.
  • The openapi.fixture.json contract pin is deliberately untouched: scanAck is not in the deployed contract yet. Regenerate it with the tenjin deploy, not here.
  • The skill-drift (mirror is in sync) check does not fire here (no skills/ change). Where it does run on a fresh branch it is red for a shared cause owned by feat(cli): tenjin pay and tenjin discover, with the bazaarPay toggle #151, and is not chased.

Refs #182, tenjin#723.

The tenjin backend now runs the publish scan server-side in its shared write
path (tenjin#723), so a publisher not running this CLI is gated too. Its
refusals reached `publish` and `edit` as opaque post-consent write failures,
which is the wrong shape for a decision the operator can act on.

Both writing commands map the gate's two codes into the consent flow they
already have: `scan_blocked` is a hard exit-3 failure with the redacted
findings and no acknowledgement path, and `scan_needs_ack` merges the server's
findings with the local scan's, deduped by detector and offset, renders them
once, and re-runs the identical content carrying the ack token on an explicit
yes. Mode semantics are the local ones: review and auto stop, full-auto acks,
and `ackServerWarnings: false` never acks whatever the mode says.

Findings travel as data, so a detector this release predates renders faithfully
and the server stays authoritative under version skew. Advisory findings on a
success response reach the receipt and the human summary as information.

Refs #182, tenjin#723.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your trial has ended. Reactivate Greptile to resume code reviews.

@A1igator A1igator added the priority: critical Blocks other PRs; merge-priority label Aug 18, 2026
A raw NUL byte in the source made git treat scan-gate.ts as binary, so its
diff never rendered for review. Same key, written as an escape.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your trial has ended. Reactivate Greptile to resume code reviews.

@A1igator A1igator added priority: high High priority and removed priority: critical Blocks other PRs; merge-priority labels Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: high High priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant