Skip to content

TST Assist M2: intents, meter, GoalApps, executors - #2

Open
captcrock wants to merge 39 commits into
mainfrom
grok/m2
Open

captcrock wants to merge 39 commits into
mainfrom
grok/m2

Conversation

@captcrock

Copy link
Copy Markdown

Summary

  • Ships M1 closeout + M2 workstreams A–P on grok/m2 (intents, live meter, GoalApps, executors, provider policy, model profiles, docs).
  • §15 defaults: dial-only, SMS draft, calendar UI insert, Settings fallback for Wi-Fi/BT, validator→Ask, session spend cap, GoalApps.infer fallback, OpenRouter/kimi-k3 with CN host blocklist.

Test plan

  • :core:test green locally (386 pass, 1 skipped live suite)
  • Pixel 7 Pro verify (still open)
  • assembleDebug on a machine with Android SDK

claude and others added 30 commits September 7, 2026 18:18
- Closed verb grammar (plan §7): strict parser, first non-empty line only,
  one action per turn, hints checked against the current observation
- Observation model: node filter with z-order and dedupe (C4), coverage
  detector (C1), session-stable hint table with quarantine (C3), screen
  fingerprint, paging at 60 with more
- Formatter renders the <<OBS ... OBS>> block; labels are one bounded,
  escaped token so screen text can never open or close the block

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
- policy/policy.yaml: verb tiers as ordered data rules (plan §4), app
  allowlist, sensitive controls in EN and ES, settings packages
- policy/cases.yaml: shared conformance cases; every rule has one
- PolicyEnforcer: pure rule walk plus the gate (grant / card / refuse)
- Ports the phone implements: Observer, Planner, Executor,
  ApprovalSurface, KillSwitch, SqlExecutor, SecretStore

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
- Accessibility service: tree walker with stable identities, observer,
  executor (accessibility actions first, gestures second, plan §7)
- Approval surface: overlay highlight and card plus notification with
  Approve and Deny; timeout is deny (plan §4)
- Kill switch: Quick Settings tile and Stop action on the task notification
- Notification listener with inline reply; assistant role services;
  Keystore-wrapped secret store; SQLite executor; foreground task service;
  settings activity with the policy self-check
- Type-checked against the API 36 framework jar (tools/androidcheck);
  assembleDebug still needs the SDK

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
…t the root

CI's core job sets ANDROID_HOME="" to force the SDK-less path, which the
settings script converted to a File. The app job failed because
org.jetbrains.kotlin.android was requested with a version while the Kotlin
Gradle Plugin was already on the root classpath from kotlin.jvm.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
Hostile screen text, prose and JSON replies, multi-line replies, invented
hints, non-allowlisted apps, app drift, keyguard, and a missing task grant:
in every case nothing executes beyond the grammar and the policy gate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
The Kotlin Android plugin and the Android Gradle Plugin must load in one
classloader; with KGP at the root and AGP only in :app the app build
failed with NoClassDefFoundError com/android/build/gradle/BaseExtension.
AGP is added to the root buildscript classpath only when settings found an
SDK, so the SDK-less core build stays free of it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
…rovals and append-only triggers; AuditStore with redaction and desktop-shaped exports
…r client) and steering (rules boundary, instruction stack)
- CloudPlanner: one brain-tier chat call per step, metered; spend cap
  turns into an ask line so the turn ends cleanly
- AuditListener: every step, approval and model call is an INSERT through
  the redactor; unparsed replies are recorded too
- Planners: picks cloud-key, home or device from the active preset and says
  plainly what is missing (key, slug, unbuilt device mode)
- Graph: config presets, Endpoints allowlist, audit store with migrations,
  seeded agent-unwritable rules dir with RulesBoundary, per-device id

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
okhttp-android 5.5.0 requires compileSdk 37, beyond AGP 8.13's maximum of
36, and drags in AndroidX. The plain JVM artifact runs fine on Android and
keeps the dependency surface to what core actually uses.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
The net module's source scan (the no-telemetry promise) caught the wire
client holding its own OkHttpClient factory. It now asks Endpoints for the
WebSocket client, so the host is checked against config before any
connection exists.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vyo2hxtfWppNVyy99Q8GmZ
The previous session died after CI went green, with this file named and
not written, and two reviews in flight. This is that work.

- docs/reality-check.md: claim ledger against the v2.0 plan. TST Desk is
  private; copies in this repo are the desktop contract. Held vs code vs
  not-built, with the adversarial findings.
- TM-010: Cloud-key shipped first; TstdClient is not a planner.
- TM-011: drag hold used an empty RectF (0,0); PathMeasure at offset 0.
- TM-012: paste fallback no longer leaves typed text on the clipboard.
- TM-013: settings copy no longer claims Device mode.

Core tests still 254 green. Nothing has run on a phone.
Empty goal-apps, sensitive-before-outside-goal, password acts,
IME/overlay dropped, payload cards, more/wait skip loop detector,
kill after planner.next, no HTTP redirect hop, autofill off on the key.
262 core tests.
Sideload needs the grants in order. One paragraph so a Pixel does not
have to guess: a11y, OpenRouter key, WhatsApp named in the goal, Run.
The debug APK had no android:icon, so the drawer showed a blank
glyph. T-mark mipmaps plus roundIcon; activity labeled TST Assist.
OpenRouter, LAN Ollama/vLLM, or a custom OpenAI-compatible /v1 URL.
The host is the Endpoints allowlist. Local/custom keys are optional.
Add call/text/alarm/timer/event/contact/navigate, torch/dnd/brightness/volume,
media/whatsapp/spotify/gmail, and qs to the closed grammar. Policy pack gains
matching rules, an on_qs fact, and Contacts on the allowlist. ASSISTANT.md
lists every new verb. Intent verbs do not use hints; Wi-Fi/Bluetooth is qs
then tap, or Settings, never a silent adapter toggle.
SDK-less IntentSpec builders so app executors consume data objects
instead of inventing URI shapes. Dial is ACTION_DIAL, SMS is SENDTO
draft, calendar is INSERT UI; EXTRA_SKIP_UI is never true.
Outcome.Paused is loop-owned and session-scoped. CloudPlanner no longer
synthesizes an ask at the cap. Hint-only stale checks, HintCodec threaded
through the prompt, Planner.planGoalApps and EndStateValidator ports.
GoalAppsPlanner parses one apps line against the allowlist. CloudPlanner
planGoalApps is a metered brain call, not a loop step. TaskController
prefers the planner and falls back to GoalApps.infer when it is empty.
CompositeEndStateValidator runs deterministic gates, then an optional
validator-tier model call recorded as classifier. Fail is Outcome.Ask
(Q6), not Done. Per-step calls stay brain-only.
MeterText formats turn, session, day, by-tier, and remaining. A new
CostTracker seeds dayCost from AuditStore.daySpend so the chip survives
across tasks. OverlayMeter and the task notification show the same
string; pause copy includes PAUSED. CloudPlanner still does not
synthesize a spend-cap ask (TM-017).
ProviderPolicy blocks Chinese cloud hosts, not OpenRouter slugs; the
shipped moonshotai/kimi-k3 brain on openrouter.ai stays. Family mode
refuses a blocked host even if Custom names it. Settings add spend cap,
numeric/letters codec, and a family toggle. Letters is one codec per run
and loads profiles/letters.md. Device mode stays an honest refusal.
NodeExecutor dispatches the M2 verbs: phone intents (dial, SMS draft,
calendar UI insert), device APIs, App Function then intent for partners,
media sessions, and qs. Accessibility-off tasks run on EmptyObserver.
Wi-Fi/Bluetooth stay visible (QS tile or Settings panel), never silent
adapter toggles.
Per-endpoint ModelProfile JSON next to audit, HintProfile wrapping the
hint codec, and a fixture suite ScriptedPlanner runs in CI. Settings
prints the offline pass rate; live calls stay -Dassist.liveSuite=1
through Endpoints (Q9).
AppNoConnectionOutsideEndpointsTest walks app/ for sockets and the
silent-radio / skipped-composer markers. TM-023 recorded; reality-check
and README note that M2 code is on grok/m2 without claiming the live
suite ran in CI or inventing truncated plan sections.
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.

3 participants