Skip to content

Decision plane, phase 1: one decide(goal, hints) in jarvisd, knowledge on the decision path, measured speed - #60

Merged
jcdavis131 merged 21 commits into
mainfrom
claude/decision-plane
Sep 23, 2026
Merged

jcdavis131 merged 21 commits into
mainfrom
claude/decision-plane

Conversation

@jcdavis131

Copy link
Copy Markdown
Owner

Stacked on #58, which has been squash-merged. origin/main is merged in, not rebased; the 16 conflicts were files where main equals this branch's base, so each resolves to this branch's side. The normative description is now docs/ARCHITECTURE.md.

What changed and why, by deliverable

1. Context builder (packages/dottie-loop/dottie_loop/context.py)

  • ContextProvider protocol, plus build_context(goal, providers, budget). It returns a DecisionContext that is:
    • bounded: 5 items per provider, 12 items total, 160 characters per text, 4 KB serialized;
    • deterministic: items sorted, and the digest covers exactly the items kept;
    • timed and fail-soft: each provider gets a timeout (default 250 ms) and its latency is recorded; a failing provider is reported, not raised.
  • Items marked private (memories, goals, claim notes) carry their text only when DOTTIE_TRACE_TEXT=1.
  • Adapters:
    • JarvisStateProvider: runs in-process and only needs an object shaped like jarvisd.state.State. It pulls FTS5 memory recall, open goals and active claims.
    • RunHistoryProvider: success, recovery and latency per tier, plus failure rate per role.
    • GraphifyProvider: off unless DOTTIE_CONTEXT_GRAPH is set.
  • dottie_loop/run_history.py replaces the old full rescan in g_history_stats. It keeps an incremental index keyed by (size, mtime) and byte offset, stores partial totals per file, and reuses the merged result when nothing changed. It can persist the index so a cold process doesn't re-parse.
    • g_history_stats keeps its keys and adds per_tier.
    • SCOUT_CHECKPOINT_BASE overrides the store location.

2. One state builder

  • system_one_state(goal, context) is used by both SystemOneBackend when serving and scout router pack when training.
  • A trace line stores the context summary System One was served and state_sha256. The pack refuses any trace whose rebuilt state hashes differently.
  • Old traces still work: with no context, the builder produces the same state they were served with.
  • Outcomes are tagged executor: stub|real. The pack refuses stub outcomes and untagged pre-tag outcomes, and counts both in MANIFEST.executors.

3. Decision plane in jarvisd

  • dottie_loop.decide.decide: build context, call route_goal with the context passed to the backends, then write a decision record. The record has a latency breakdown (context, route, each backend, total), the context digest and ids, System One's answers, and whether the cache was hit. The goal text is included only on opt-in.
  • Served as POST /api/decide and MCP harness.decide, and recorded on the jarvisd timeline (kind=decide) and in the trace.
  • /api/route and harness.route stay as compatible aliases: the old fields plus decision.
  • api_route, api_plan and api_decide now run in the threadpool; a test checks this.
  • LRU cache per daemon (256 entries, 30 s TTL), keyed by goal sha256, context digest, backend config and hints. Hits are marked in the record.

4. Speed

  • scout plugins load lazily. Command names and help come from a checked-in entry table, held in sync by a test. scout --help lists the same 76 rows with the same text and imports no plugin.
  • Import failures are still silent on the command line. SCOUT_DEBUG_PLUGINS=1 prints the traceback, and scout doctor imports every plugin and reports failures.
  • bigbang.core.mcp_client imports mcp only on first use.
  • scout route and scout harness route try jarvisd /api/decide first (JARVIS_URL/JARVIS_BEARER, 0.1 s connect timeout) and fall back to the same code in-process.
  • SystemOneBackend: /health is cached per URL, one keep-alive http.client connection per thread with Nagle off, and one /decide request per route carrying all four questions.
  • jev-v0 SharedPrefixScorer encodes the shared state prefix once (KV cache) and runs only each question's suffix. The orchestration doesn't need torch; it is tested with a fake causal model. serve_decide now speaks HTTP/1.1 with Nagle off.

5. Bench: dottie-loop bench decide and scout router bench, backed by dottie_loop/bench_decide.py.

6. One copy of each thing

  • Heuristic: harness-api's own classifier had drifted: it ignored classify_moma's keyword overrides. It now serves lib/moma_lite.py, a verbatim copy vendored by scripts/vendor_router.py. Its --check flag and a golden parity test catch drift. The dormant heuristics.py and vector_router.py are deleted.
  • Recovery ladder: dottie_loop.execution.recovery_ladder is the one implementation. The two pipeline/ modules re-export it. The inline copy in the runner and bundles/ultra/recovery-ladder.js are removed. A test pins every input against the old function.
  • Ollama: OLLAMA_HOST is the one variable. OLLAMA_BASE, OLLAMA_URL and DOTTIE_OLLAMA_URL still work but warn that they are deprecated; this covers the scout clients and jarvisd's brain.
  • Deleted: src/harness (imported by nothing; its name collided with ava-open-harness) and apps/arxiviq/app/acd (imported by nothing).
  • HandoffEnvelope: the dangling references are replaced with the real handoff, jarvisd jarvis.send/jarvis.inbox.

7. Docs

  • docs/ARCHITECTURE.md is new and normative.
  • docs/ECOSYSTEM.md is now a pointer plus history.
  • Updated: ROUTER.md, the README, the jarvisd README and spec, and the HANDOFF top block.
  • The DAG gains Phase 2 nodes.

Measured before/after

dottie-loop bench decide --n 100 --cold-n 20, run on a 4-CPU Linux container with Python 3.11.15. "Before" is fa04d85. System One rows use a local untrained serve_decide, so they measure HTTP only and no model runs.

Scenario Before p50/p95 ms After p50/p95 ms
scout cold route (fresh interpreter) 826.2 / 892.9 136.0 / 150.2
scout --help (fresh interpreter) 765–1266 176–208
in-process route_goal 0.018 / 0.028 0.014 / 0.020
in-process decide + run-history context n/a 0.612 / 0.935
jarvisd warm /api/route 1.483 / 1.977 (no context) 3.805 / 4.817 (with context)
jarvisd warm /api/decide, no context n/a 2.132 / 2.678
jarvisd warm /api/decide + context n/a 3.833 / 4.888
jarvisd /api/decide + context + System One n/a 5.175 / 8.311
System One backend round trip 2.184 / 2.693 0.509 / 0.941
run-history stats (400 runs) 5.521 / 11.827 2.151 / 2.732

The budget targets were 10 ms for warm decide without System One and 250 ms for a cold scout route; both are met. The 150 ms System One on GPU target is not measured here because this box has no GPU or checkpoint.

Verification (local)

  • Test suites:
    • dottie-loop: 274 passed
    • jarvisd: 129 passed, 1 skipped
    • scout-cli: 2600 passed, 2 skipped
    • jev-v0: 20 OK
    • harness-api: 120 passed
    • dottie-os: 19 OK
    • factory: 104 passed
    • ava-skills: 115 passed
    • personal-graphify: 77 passed
    • ava-open-harness: 44 passed, 4 skipped
    • ava-factory flywheel and orchestration corpus: 44 passed
    • arxiviq node tests: 45 pass
  • Lint and lock:
    • uvx ruff@0.15.22 check packages/dottie-loop is clean.
    • The lint-debt figure in the docs (970) still reproduces; scout-cli is still at 750.
    • uv lock --check passes.
  • CI scripts: all pass.
    • gate audit: 0 new, 0 stale
    • declared capabilities
    • resolver fallbacks
    • CLI path args
    • shell=True sites
    • store symmetry
    • TODO timestamps
    • HANDOFF freshness
    • DAG check
    • factory check
    • leaks scan of the tree and of all history
    • all 6 scripts self-tests (after unshallowing the clone)
  • Parity: the golden route parity holds in dottie-loop, scout and harness-api.
  • No real state written: the state-pollution sweep around the scout, jarvisd and dottie-loop suites is CLEAN. The conftests pin SCOUT_CHECKPOINT_BASE, SCOUT_DECIDE_REMOTE=0 and the trace dir so tests never write real ~/.dottie data or jarvisd DBs.

Retirement and integration (owner decision, 2026-09-23)

  • Retire only apps/bluehenre: archive it in Phase 2, keep its history, and drop its CI job with it.
  • Keep and integrate apps/dottie-rlm: converge the three RLM implementations onto one.
  • Keep and integrate apps/dottie: fold its missions and research loop into the decision plane, and fix the dottie package-name collision.
  • Keep harness-api, which becomes a thin proxy to jarvisd /api/decide.
  • apps/ava-factory stays as is (the frozen trainer mirror).
  • Nothing is deleted in this PR beyond the orphans listed above.

Phase 2 (DAG nodes)

  • decision-plane-real-executors: today nearly every outcome is executor: stub, so no pack can be built from real labels. This is expected.
  • harness-api-jarvisd-proxy
  • retire-bluehenre
  • rlm-converge
  • agent-os-fold

Behaviour changes worth a look

  • harness-api now routes exactly like the router. Some goals change tier: for example, "pay the stripe invoice" now goes to deep_research, matching scout and jarvisd.
  • ollama.candidate_bases now checks OLLAMA_HOST before the old names.
  • jarvisd /api/route now builds context, which costs about 2 ms more.
  • The pack refuses untagged pre-tag traces, since their executors were all stubs.
  • scout --help lists plugins in sorted order.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2


Generated by Claude Code

…:8771

serve_decide.py --checkpoint <dir> lazy-imports torch (pointer_infer.py),
answers in mode=pointer-lora with real probabilities and shape_concentration,
and reports the checkpoint identity hash and its eval gate in /health.
Without --checkpoint it stays mode=untrained. dottie-os owns :8770; this dev
server defaults to :8771. decision_io gains answer_from_probabilities and
checkpoint_identity (the hash a promotion stamp names).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
…traces and the training loop

route_goal is the single routing policy for goal strings. MoMA-lite moves into
dottie_loop.backends (its only implementation); the orchestrator MLP and
System One over /decide are advisory unless gate_passed AND human-stamped, and
only for an equal-or-cheaper tier. Default decisions are golden-tested against
the pre-unification classifier. Each route appends a trace line
(~/.dottie/traces, never under pytest by default); router_training packs real
production traces into strict jev records, evaluates a checkpoint against the
heuristic through evaluate_gates/promotion_decision, and router_artifacts holds
the human promotion stamps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
… scout router

scout harness route, harness run (runner step 1) and jarvisd route/plan/run
now decide through dottie_loop.router.route_goal; decisions are unchanged (the
MoMA-lite goldens pass through the real CLI). Route output keeps every existing
key and adds authority, spec_tier and an advisory block. harness run appends its
observed outcome to the route's trace. New: scout route (top-level alias) and
the router plugin (status, pack, train, eval, promote). dottie-loop becomes a
workspace dependency of scout-cli and jarvisd. Test suites pin traces and
stamps into their throwaway homes; the state sweep watches ~/.dottie. Soft
ruff debt 983 -> 970 as the classifier code left scout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
…nance sidecar

Curation packs now carry only schema/id/state/questions/labels, validated by
apps/jev-v0/decision_io.py when present; tier, source, consent and pair ids
move to curated_pack_v2_provenance.jsonl. read_rows() and the pack smoke still
read the old dottie-os-decision-schema-1.0.0 rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
… the real eval

lib/orch_infer.py and lib/weights/champion_weights.json were never loaded by the
API. The weights were labelled orch-mlp-v1-v5 with no eval behind them while
every report names v4. The one weights file is ava-factory's and the one
inference path is the router's MLP backend. lib/meta/eval_summary.json is
re-vendored from ava-factory's eval_report.json (v4, gate_passed false);
corpus_builder's hardcoded hill-climb numbers are labelled simulated and no
longer overwrite it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
docs/ROUTER.md describes the router, its backends, authority (gate plus human
stamp), traces, the training loop and port ownership. scout's README,
INTEGRATION.md and docs/INSTALLER.md install with uv from the Dottie monorepo
and say what the curl shim actually writes. .dottie/ is gitignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
The stamp store is declared in the manifest and gated with fs_write; the
operator-named destinations (pack --out, train --out, the checkpoint's
eval_summary.json, a DOTTIE_ROUTER_STAMPS override) use fs_write_arg. Keeps the
fleet invariants in tests/test_policy.py (write:true declares paths, no new
ungated write-capable plugin).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
The flywheel cycle's promoted path vendors the freshly trained weights
through copy_artifacts._copy_weights and verifies their sha256; removing the
function broke three flywheel_cycle tests in codeact-sandbox. Restore it,
still skipped by the default main() so nothing is vendored unless the
flywheel promotes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
…lder, decide)

- context.py: ContextProvider protocol and build_context(goal, providers,
  budget) -> DecisionContext: bounded (per-provider/total items, text and
  byte caps), deterministic (sorted, digest over exactly the kept items),
  per-provider latency and timeout, fail soft. Private items (memories,
  goals, claims) carry text only under DOTTIE_TRACE_TEXT=1. Adapters:
  JarvisStateProvider (in-process, duck-typed on jarvisd.state.State),
  RunHistoryProvider, GraphifyProvider (off unless DOTTIE_CONTEXT_GRAPH).
- run_history.py: HistoryIndex, an incremental (size, mtime) + byte-offset
  index over scout's timeline store with per-file partial aggregates, a
  reused merge when nothing changed, per-tier success/recovery/latency, and
  an optional persisted index for cold processes.
- backends.system_one_state(goal, context): the ONE state builder for serve
  and pack; no context -> the pre-context state, so old traces rebuild
  unchanged. SystemOneBackend: /health cached per URL, one kept-alive
  http.client connection per thread (Nagle off), one /decide per route.
- route_goal(context=...) hands the context to backends that take it and
  records per-backend latency; traces store the served context summary and
  state_sha256.
- router_training.pack refuses stub-executor and untagged outcomes (counted
  in MANIFEST executors) and refuses a trace whose rebuilt state drifts.
- decide.py: decide(goal, hints) = context -> route_goal -> decision record
  (latency breakdown, context ids/digest, System One view) with an LRU+TTL
  cache keyed by goal sha, context digest, backend config and hints.
- execution.recovery_ladder: the harness ladder's one implementation.
- bench_decide.py: the checked-in decision-latency bench.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
…efix

pointer_infer.SharedPrefixScorer tokenizes each branch exactly as training
did, finds the longest shared token prefix (never past an option or decide
boundary), encodes it once with the KV cache and runs only each question's
suffix on a copy of the cache: the same causal computation as encoding every
branch whole, without re-encoding the state four times per request. The
orchestration is torch-free (tokenize/encode/copy/score injected) and tested
with a fake causal model; PointerPredictor.probabilities_many wires the torch
pieces, and serve_decide.decide uses it when the predictor offers it.

serve_decide speaks HTTP/1.1 with Nagle off so the router's System One
backend keeps one connection alive; unread-body errors close the connection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
decide(goal, hints) builds the context from this daemon's store (FTS5
memory recall, open goals, active claims) plus scout's run history and the
optional code graph, routes through dottie_loop.decide, and records the
decision (context digest and ids, System One answers, latency breakdown,
cache hit; the goal text only under DOTTIE_TRACE_TEXT=1) on the timeline as
kind=decide. A per-daemon LRU+TTL decision cache is keyed by goal sha,
context digest, backend config and hints.

/api/route and harness.route stay compatible aliases (old fields plus
decision); /api/plan decides the same way. route, plan and decide run in the
threadpool instead of blocking the event loop. harness.run passes the same
context providers to scout's runner. Tests pin the tool list, the record,
the cache, the no-text rule and the threadpool dispatch; conftest points
SCOUT_CHECKPOINT_BASE at tmp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
dottie_loop.env.ollama_host / ollama_env_values: OLLAMA_HOST first; the
spellings clients grew (OLLAMA_BASE, OLLAMA_URL, DOTTIE_OLLAMA_URL) are
accepted as deprecated aliases with a FutureWarning, once per alias per
process. scout's llm, ollama, ava, agent and write clients and jarvisd's
brain read it through that helper. ollama.candidate_bases now tries
OLLAMA_HOST before the aliases (test updated). apps/dottie still reads
DOTTIE_OLLAMA_URL; it is folded in Phase 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
…d outcomes

- Plugins register from a checked-in entry table (bigbang/core/plugin_entries.py,
  regenerated by python -m bigbang.core.plugin_loader --write-entries and
  held in sync by a test); a plugin module is imported only when its command
  runs. scout --help still lists every plugin, with the same help text, and
  imports none. A plugin missing from the table loads eagerly as before.
  Import failures stay silent on the command line; SCOUT_DEBUG_PLUGINS=1
  prints the traceback and scout doctor imports and reports every plugin.
  SCOUT_EAGER_PLUGINS=1 restores the old behaviour.
- bigbang.core.mcp_client imports the MCP SDK on first use.
- scout route / harness route ask jarvisd POST /api/decide (JARVIS_URL,
  JARVIS_BEARER; short connect timeout) and fall back to the same
  dottie_loop.decide in-process with the run-history provider; the output
  says decided_by and carries the decision record.
- harness run decides through dottie_loop.decide (context providers
  injectable, jarvisd passes its own), tags each timeline row with tier and
  executor kind, and tags the outcome executor: stub|real (only the MCP
  operator is real today). The one recovery ladder comes from
  dottie_loop.execution; the file-path import and inline replica are gone.
- g_history_stats delegates to dottie_loop.run_history (same keys plus
  per_tier); SCOUT_CHECKPOINT_BASE overrides the base.
- conftest: SCOUT_DECIDE_REMOTE=0 and the new env overrides are pinned so the
  suite never reaches a developer's jarvisd or real stores.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
dottie_loop.execution.recovery_ladder is the one implementation (a rung
table with a fail-closed escalate default instead of an == chain).
pipeline/recovery_ladder.py and pipeline/checkpoint_manager.py re-export it;
bundles/ultra/recovery-ladder.js (imported by nothing) is removed, as is
scout's inline replica (previous commit). tests/test_recovery_ladder_one_copy.py
pins every (class, side effect, attempt) against the replaced function and
checks each former copy now is the one. The three gate-audit baseline
entries for the removed == chains (and two already-stale harness-api ones)
are pruned; gate_audit --check reports 0 stale.

The scout README and install.sh cited a HandoffEnvelope in a
bundles/ultra/communication-pacing.js that never existed in this repo; they
now point at the real handoff (jarvisd jarvis.send/inbox, scout comms).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
lib/production_routing.py carried its own MoMA-lite classifier, which had
drifted from the router (it ignored the keyword overrides in classify_moma).
scripts/vendor_router.py now copies the MoMA-lite section of
packages/dottie-loop/dottie_loop/backends.py verbatim into lib/moma_lite.py
(Vercel deploys this app without the monorepo), stamped with the section's
sha256; --check fails when it is stale. production_routing keeps only the
API's fail-closed RoutingRejected guards and response shape.
tests/test_production_routing_parity.py runs the check and holds the API to
the router's goldens. The dormant lib/heuristics.py and lib/vector_router.py
(imported by nothing; the tests already forbade importing them) are deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
src/harness was imported by nothing (only docs cited it as src.harness) and
its top-level name collided with packages/ava-open-harness's real harness
package, which CI smoke-tests. apps/arxiviq/app/acd was a dormant ACD
simulation that the app's own contract test forbade importing; the ESLint
ignore for it goes too, and the contract test now asserts it stays deleted
(node --test test/*.test.mjs: 41 pass). The docs that cited them are marked
historical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
The checked-in decision-latency bench (dottie_loop/bench_decide.py) behind
two commands. It measures p50/p95 for a cold scout route (fresh interpreter,
forced in-process), in-process routing and decide with run-history context,
a jarvisd served by uvicorn on a free loopback port (route alias, decide
without and with context, decide with System One against a local untrained
serve_decide), scout's run-history stats over 400 runs, and the System One
backend round trip. It starts its own servers with temp state and writes
nothing real. The router plugin manifest now declares its loopback-only
network use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
PR #58 was squash-merged into main; its content equals this branch's base,
so the 16 add/add and content conflicts all resolve to this branch's side.
main's other changes (#57, #59) touch only apps/arxiviq and merge cleanly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
tests/test_recovery_ladder_one_copy.py keeps the replaced ladder verbatim as
the reference the one implementation is checked against; its == chain ends
in the terminal escalate rung (fail-closed). Accepted with that judgment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
… Phase 2 DAG

docs/ARCHITECTURE.md: the four planes, the runtime topology, every service
and port, the decide contract and record, which knowledge sources are on the
decision path, the learning loop (one state builder, executor-tagged
outcomes), the speed budget with the measured before/after bench, the rules,
one copy of each thing, and the owner's 2026-09-23 retirement decisions
(retire only apps/bluehenre; keep and integrate apps/dottie-rlm, apps/dottie
and harness-api). docs/ECOSYSTEM.md keeps only what was aspirational vs true
and the sections other documents cite. ROUTER.md, README, the jarvisd README
and spec gain decide / harness.decide. project_dag.json: decision-plane-phase1
done (factory done), Phase 2 nodes decision-plane-real-executors,
harness-api-jarvisd-proxy, retire-bluehenre, rlm-converge, agent-os-fold.
HANDOFF.md: a new top block stamped at the merge commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
@vercel

vercel Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
arxiviq Ready Ready Preview Sep 23, 2026 10:47pm UTC
dottie-os-console Ready Ready Preview Sep 23, 2026 10:47pm UTC

Request Review

CI runners set FORCE_COLOR/GITHUB_ACTIONS and an 80-column terminal, so
rich wrapped plugin names in ANSI codes and test_help_lists_every_plugin_
and_imports_none could not find ' a11y '. Pin a wide, colourless terminal
for the probe subprocess and strip ANSI before matching. Reproduced with
GITHUB_ACTIONS=true FORCE_COLOR=1 COLUMNS=80; passes under both that and
a plain local run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
@jcdavis131
jcdavis131 marked this pull request as ready for review September 23, 2026 22:49
@jcdavis131
jcdavis131 merged commit 8266088 into main Sep 23, 2026
11 checks passed

@cursor cursor 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.

Approved. Cursor Bugbot was not running after the first check poll, no approval policy required human review, and there is no prior approval from this automation. Reviewers were not assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

jcdavis131 pushed a commit that referenced this pull request Sep 24, 2026
The block named 07a2146, a claude/decision-plane commit that the squash merge
left off main, so check_handoff_fresh.py --check failed lint-and-test on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WH1hPpf3u1xWecEhS6AHD2
(cherry picked from commit d9aaa9b)
jcdavis131 added a commit that referenced this pull request Sep 24, 2026
Merged on Cameron's word 2026-09-23.

This branch was successfully deployed

2 active deployments
Preview – dottie-os-console — 437415a5 Deployed Sep 23, 2026 by vercel[bot]
Preview – arxiviq — 437415a5 Deployed Sep 23, 2026 by vercel[bot]
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.

2 participants