docs: document the attended-decision path and its ingress requirement - #86
Merged
Conversation
A run that cannot confirm something halts and puts a bounded question in front of a person, reachable from a phone. That path shipped across openadapt-types, openadapt-flow, openadapt-desktop, and openadapt-cloud, and the docs said nothing about it beyond auto-generated changelog lines. Extends the existing halt-learn-loop page rather than adding a new one: the phone's "teach the correction" answer is literally the front door to the learn loop already documented there, so the two halves now read as one page — where a halt goes, and what happens when someone teaches the fix. Nav label and closing rationale updated to match. The properties that distinguish this path, all established from origin/main rather than from a summary: - The phone returns a signed decision, not an execution result. The engine re-reads live state and re-verifies before continuing, and refuses when the application has not actually changed. An operator's answer never marks a run verified. - The operator's own completed step is verified, not replayed. - Full evidence stays on the customer-controlled runner. The hosted envelope carries no free-text field at all, so a hosted dashboard shows less than the phone by design — documented as the feature it is rather than hidden as a limitation. - Pairing is a one-use QR whose confirmation code is minted on the claiming phone and typed back on the runner. The reversal is what makes it phishing-resistant, so the reasoning is written down. The ingress requirement is deliberately not a footnote. The portal is loopback-only by default and a phone cannot reach it until the customer terminates trusted TLS themselves. A reader who installs and then discovers that has been misled, so it appears in three places they hit before trying: a warning in the concept page, the exact variables and fail-closed rules in the configuration reference, and a plan-for-this callout in the on-prem guide. It is framed as what it is — we did not open a listening surface on someone else's network for our convenience, and in a governance sale that is a strength. Also cross-links from the durable-runtime handover and the identity gate, which both end at a halt and previously said nothing about where it goes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM
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.
What
When a run cannot confirm something it halts and puts a bounded question in front of a person, reachable from a phone. That path shipped across four repos —
openadapt-types#12/#13,openadapt-flow#289/#290,openadapt-desktop#75/#78/#79/#80/#82,openadapt-cloud#175 — anddocs.openadapt.aisaid nothing about it beyond auto-generated changelog lines.This extends the existing
concepts/halt-learn-loop.mdrather than adding a page. The phone's "teach the correction" answer is the front door to the learn loop already documented there, so the two halves now read as one page: where a halt goes, then what happens when someone teaches the fix.Established from
origin/main, not from a summaryEvery property below was verified by reading
origin/mainof the four repos (viagit show origin/main:…, since several checkouts are on feature branches):continue_runcallsrevalidate_attended_completionagainst a fresh observation and returnsrefusedwhen it fails — before any resume.checkpoint_human_completed_step— "advance a linear resume point after outcome verification, without acting" — recordsactuation="human_attended"and refuses if postconditions or the independent effect check did not pass.portable_remote_decision_taskdiscards the localpresentationblock; the hosted envelope has no free-text field anywhere, enforced by exact-key checks in both TypeScript and SQL.engine/portal/ingress.py.One correction to the brief I was given
The brief said the hosted envelope carries
safe_slotsnull. It does not —safe_slotsis a typed object of three nullable bounded integers, individually null per task. What Cloud actually loses is the entire localpresentationblock. The docs state the accurate version. The conclusion the brief drew is still right, and for a stronger reason: the hosted surface shows less because values and prose have no field to travel in, not because a field was nulled.The ingress requirement
Deliberately not a footnote. The portal is loopback-only by default and a phone cannot reach it until the customer terminates trusted TLS themselves. A reader who installs and only then discovers this has been misled, so it appears in three places they hit before trying:
!!! warningin the concept page, plus the constraint stated in the section's opening sentence so a skimmer sees it too.reference/configuration.md— a new The mobile decision portal section with the exact variables and every fail-closed rule.guides/deploy-on-prem.md— a "plan the ingress before you pilot the phone path" callout in the deployment-planning flow.Framed as what it is: we did not open a listening surface on someone else's network for our convenience. The runner is published under the customer's certificate, access policy, and logging, so the phone path inherits controls their security team already audits. In a governance sale that is a strength, not an apology.
Files
concepts/halt-learn-loop.mdreference/configuration.mdguides/deploy-on-prem.mdguides/security-and-data-handling.mdconcepts/durable-runtime.md,concepts/identity-gate.mdmkdocs.ymlDeliberately not included
.private/mobile_demo/shots/2026-07-27-hf-review-after-02-decision-viewport.pngand it is a synthetic fixture — a "button labelled Open", no MockMed data, no identifiers, no real application. But copying out of.private/into a public repo was blocked by the workspace guardrail, and that guardrail exists to force exactly this decision to a human. I did not work around it. Adding it later is a one-line follow-up if wanted.openadapt.aiwould imply a self-serve availability that does not exist.pages/dental.jsalready promises a "ready-to-finish queue", which remains accurate and unchanged.halt_detail) is on Flowmainbut not in releasedv1.25.1, and Desktop pinsopenadapt-flow==1.25.0/openadapt-types==0.6.1. The documented loop works on the pinned versions via the compat mapping Desktop already ships; only the narration fidelity differs. That skew is transient and would go stale in the docs within days.Verification
scripts/validate_docs.py— passedpytest— 101 passedmkdocs build --strict— clean; all three new cross-page anchors confirmed present in the built HTML🤖 Generated with Claude Code
https://claude.ai/code/session_01NyCHrzA1psrKMFfroYbzaM