feat(publish): answer the marketplace scan gate instead of failing on it - #185
feat(publish): answer the marketplace scan gate instead of failing on it#185A1igator wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
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>
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>
b498ef0 to
b7edb15
Compare
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Rebased onto Two files conflicted, and both were semantic rather than textual, so recording how each resolved:
No What ran at this head: Still |
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.tsparses the two 422 codes and merges server findings with the local scan's, deduped by detector and offset.src/lib/consent.tsmaps them into the exit-3 flowpublishandeditalready share:scan_blockedis terminal with no acknowledgement path,scan_needs_ackrenders once and re-runs the identical content with the ack token on an explicit yes, exactly once. Risk is the wire body:scanAckonly 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.tsacksServerWarnings): review and auto stop on a server warn, full-auto acks it, andackServerWarnings: falsenever 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
scanand 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.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 inpublish.test.tsand 5 inedit.test.tsagainst 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 inoutput.test.tsfor the source marker.Definition of Done
RELEASING.mdgains a server-coupled-releases section: thetenjinrepo'sSCAN_WARN_MODE=enforceflip waits for this release to propagate, which is the whole reason the flag exists.docs/safety-model.mdstates 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.minor).Notes
A1igator/ingest-scan-gate), built against head5fbed15f. This lands after it merges.openapi.fixture.jsoncontract pin is deliberately untouched:scanAckis not in the deployed contract yet. Regenerate it with the tenjin deploy, not here.skill-drift (mirror is in sync)check does not fire here (noskills/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.