fix(lead): declare ai.requiresConfirmation on convert_lead - #1589
Merged
os-steve merged 1 commit intoSep 5, 2026
Conversation
The action's AI description promises "Irreversible — requires human approval before it runs", while list_actions reported requiresConfirmation: false. The ai block declared exposed and description but no requiresConfirmation, and a comment attributed the AI gate to confirmText. Measured against the pinned @objectstack/runtime 17.3.0: actionLooksDestructive reads action.ai.requiresConfirmation and otherwise falls back to mode === 'delete' || variant === 'danger'. confirmText occurs zero times in the whole shipped runtime bundle — it is the console's confirm-dialog string for a human click, unrelated to the AI path. Rewrite the comment to name the key the AI path actually reads, and to state that the flag is surfaced in list_actions rather than enforced: run_action dispatches the flow with no server-side pause, so the retired "lands in the HITL queue" claim is not restated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
os-steve
marked this pull request as ready for review
September 5, 2026 15:36
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1578
convert_leadshipped anai.descriptionpromising "Irreversible — requires human approval before it runs" whilelist_actionsreportedrequiresConfirmation: false. Theaiblock declaredexposedanddescriptionand norequiresConfirmation; a code comment attributed the AI gate toconfirmText. This adds the key the runtime actually reads and rewrites the comment.The premise, re-verified against the installed packages
The card cited runtime 17.2.0; this repo pins and installs 17.3.0. Re-measured there rather than taken from the card:
convert_leadis neithermode: 'delete'norvariant: 'danger', so with noai.requiresConfirmationthe fallback returnedfalse.confirmTextoccurs zero times in the entire shipped runtime bundle — it never reaches the AI path at all.@objectstack/spec17.3.0 agrees in its own authoring guidance: "the AI human-in-the-loop override lives underai— writeai: { requiresConfirmation: true }.confirmTextis the separate UI confirm prompt." Its alias table mapsconfirm/requireConfirmation/hitl/humanInTheLoopontorequiresConfirmation(the card named three of those four).Premise holds.
requiresConfirmationwas 0 hits repo-wide before this change;confirmTextreturns 37 at this base from the same invocation shape as the working control.Evidence the fix is load-bearing
A probe applies the shipped predicate — extracted verbatim out of
node_modules, never hand-copied — to the real action metadata. Ablation was run from the committed state, restore proven by blob hash equality and an emptygit diff HEAD:The middle line is the point: with
confirmTextstill present and only the new key gone, the verdict isfalse. That is the defect reproduced, and it is direct proofconfirmTextdoes not gate.schedule_followuprides along as a negative control and staysfalsethroughout — it is additive and reversible and declares no gate, so the predicate is not simply returningtrue.End-to-end, the key survives
pnpm buildintodist/objectstack.jsonat all three registration sites (objects[].actions,actions[], and the page component that embeds it) — that artifact is whatlist_actionsreads.The comment
Rewritten to name the key the AI path reads and to stop attributing the gate to
confirmText, which remains the console's confirm-dialog string for a human click.It deliberately does not restate the retired "lands in the HITL queue" claim. Measured on the same bundle:
requiresConfirmationappears at exactly two sites — the read above and thelist_actionsprojection.approvalQueueanddestructiveHintare 0 occurrences; the singleHITLoccurrence is a comment calling the flag a hint.run_actionchecks exposure, permission, activation and params, then dispatches — no server-side pause. So the comment says surfaced, not enforced.That non-enforcement is a platform gap, not this repo's to work around. Deduped with a working control leg and filed at destination as objectstack#15942, unassigned and unlabelled for their triage.
Scope
src/actions/lead.actions.tsplus the changeset — the dispatched file surface, not exceeded. No locale pack is touched: the translated surface for this action islabel/confirmText/successMessage, andrequiresConfirmationis a boolean, so the fix needed nothing held by #1144.content/docs/reference/faq*untouched, so nothing held by #1402 is involved either.Verification
Every step of
pnpm verifyrun individually, exit code captured before any pipe:pnpm validatepnpm typecheckpnpm lintpnpm lint:i18n-gatepnpm hygienepnpm hygiene:tokenspnpm buildpnpm testtypecheckgreen is itself the contract check: theActiontype from@objectstack/spec/uiacceptsai.requiresConfirmation. Token ratchet stays clean — business semantics ~84,026 of a ~85,000 ceiling. The ratchet is comment-stripped, so the comment rewrite costs it nothing; only the one key moves the number.Validate/build warnings are pre-existing (flow
try_catchadvisories on unrelated flows) and are unchanged by this diff.🤖 Generated with Claude Code
https://claude.ai/code/session_01DuzfS5chho38Yx1jxx9DEj
Generated by Claude Code