Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
ec738ae
fix: clear stale Governed Mode migrating flag on background poll + sh…
nikolanovoselec Jul 1, 2026
37fbfa2
[autonomous] fix: address PR #601 review + CI findings
nikolanovoselec Jul 1, 2026
1465edc
[autonomous] fix: apply round-2 review findings (spec sync, dep cycle…
nikolanovoselec Jul 1, 2026
7c7b30c
[autonomous] fix: round-3 review findings (halted trigger completenes…
nikolanovoselec Jul 1, 2026
f07456c
[autonomous] test: assert halted on retry-ceiling poison halt (REQ-EN…
nikolanovoselec Jul 1, 2026
a981c57
fix: Pi CI monitor shares the PR-boundary handoff trigger (REQ-AGENT-…
nikolanovoselec Jul 1, 2026
c59436c
[autonomous] docs: fix REQ-AGENT-068/070 spec-review findings (AC1 ve…
nikolanovoselec Jul 1, 2026
2100a0b
fix: revert no-op scrollbar hide, bump xterm to 6.1.0-beta for Pi fli…
nikolanovoselec Jul 1, 2026
bc92199
docs: split 3 over-cap REQs, fix cross-references and doc gaps
nikolanovoselec Jul 1, 2026
04136da
[autonomous] fix: reconcile REQ-ENTERPRISE-018 test anchors to REQ-020
nikolanovoselec Jul 1, 2026
5b9d2a4
[autonomous] fix: relabel changes.md REQ links, add REQ-MOB-004 to co…
nikolanovoselec Jul 1, 2026
fc179a0
[autonomous] fix: break REQ-VAULT-015/023 dependency cycle, remaining…
nikolanovoselec Jul 1, 2026
011a240
fix: default Pi web_search to auto-summary, avoiding upstream crash
nikolanovoselec Jul 1, 2026
60a963d
[autonomous] fix: drain review queue, split REQ-AGENT-005, fix Pi web…
nikolanovoselec Jul 1, 2026
6f41210
[autonomous] fix: complete review-queue drain with real word-cap comp…
nikolanovoselec Jul 1, 2026
da65342
[autonomous] fix: repoint stale REQ-VAULT-013 AC5 citation to REQ-VAU…
nikolanovoselec Jul 1, 2026
11f4f34
chore: rebuild knowledge graph from scratch, AST-only
nikolanovoselec Jul 1, 2026
7bfa4e0
fix: split REQ-VAULT-008 to close AC-count cap, fix orphaned test anc…
nikolanovoselec Jul 1, 2026
6797cde
chore(deps-dev): bump knip from 6.17.1 to 6.23.0 in /web-ui
dependabot[bot] Jul 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ graphify-out/.cache/
graphify-out/.chunks/
graphify-out/manifest.json
graphify-out/obsidian/
graphify-out/cost.json
# Working-tree intermediates - cleaned by the build's Step 9,
# gitignored as the safety net for runs interrupted before cleanup:
.graphify_ast.json
Expand Down
70 changes: 70 additions & 0 deletions documentation/.doc-coverage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Documentation Coverage Ledger

## 2026-07-01 — PR #601 (develop→main), delta review ec738ae5..1465edc

Scope: incremental diff only, restricted to `documentation/`. Files touched:
`documentation/decisions/README.md`, `documentation/lanes/troubleshooting.md`.

### Verified: prior findings resolved correctly

1. AD91 state-shape literal (`documentation/decisions/README.md:1829`) now includes
`halted?` alongside `total?`/`processed?`. Matches `src/lib/r2-regime-state.ts:59`.
2. The bloated "Revised 2026-07-01" note was lifted out of the AD91 "Backend gate +
container drain" bullet into a standalone paragraph after the "Dual-regime reads +
self-heal" bullet (`documentation/decisions/README.md:1835`). Word count: 98 words
(budget 120). The bullet itself is back to a single coherent sentence pair with no
dangling reference.
3. `documentation/lanes/troubleshooting.md`'s **Cause** paragraph (line 117) was split
at the sentence boundary about the button/poll UI behavior. Neither half exceeds
budget: first half 87 words, second half (line 119) 47 words (budget 120 each).
4. The **Diagnose** paragraph (`documentation/lanes/troubleshooting.md:121`) now names
`halted: true` as the definitive stalled signal — see MEDIUM finding below for a
completeness gap in the added clause.
5. `REQ-ENTERPRISE-018` backlink added to the Spec-Coverage index
(`documentation/lanes/troubleshooting.md:288`); anchor resolves against
`sdd/spec/enterprise-mode.md#req-enterprise-018-...`; no duplicate entry.
6. No leftover duplicate "Revised 2026-07-01" text anywhere else in `documentation/`.
7. All relative link depths correct for nested/nested layout (`../../sdd/spec/...` from
`documentation/lanes/` and `documentation/decisions/`, both depth-2).

### MEDIUM — doc-truth-incomplete: `halted` trigger conditions understated

**File:** `documentation/lanes/troubleshooting.md:121` (Diagnose paragraph, new clause
added in this delta)

**Current text:**
> `halted: true` is the definitive stalled signal (set at the verify-retry ceiling, and
> it is what suppresses the button's progress %).

**Problem:** The same commit (1465edc, per its own commit body: "code: halted flag is
also set on the key-rotation detect-only halt path (parity with the verify-retry-ceiling
halt)") added a SECOND trigger for `halted: true`. Confirmed in source:
- `src/lib/r2-migration.ts:553` — `halted: true` set on `ENCRYPTION_KEY rotated
mid-migration` (key-rotation detect-only halt).
- `src/lib/r2-migration.ts:676` — `halted: true` set when `stuckCount >=
MAX_VERIFY_RETRIES` (verify-retry ceiling).
- `src/routes/session/lifecycle.ts:194` — `bucketMigrationPercent` suppressed via
`!regimeState.halted` regardless of which trigger set it.

The Diagnose clause "(set at the verify-retry ceiling...)" attributes the flag to only
one of the two triggers the code actually implements, which could lead an operator
reading Diagnose in isolation to conclude a key-rotation-caused halt does NOT set
`halted: true` (contradicting the Fix section two lines below, which separately notes
"key rotation halts-with-error by design").

**Proposed fix (ready to apply):**
```
`halted: true` is the definitive stalled signal — set both at the verify-retry ceiling
and when key rotation is detected mid-migration — and it is what suppresses the
button's progress %.
```
Word count after fix: 84 words for the full Diagnose paragraph (was 78) — still well
under the 120-word budget.

### LOW — minor phrasing (defer to /sdd clean)

`documentation/lanes/troubleshooting.md:121` — "(set at the verify-retry ceiling, and it
is what suppresses...)" reads slightly awkwardly ("and it is what"); the proposed MEDIUM
fix above also resolves this incidentally.

---
30 changes: 20 additions & 10 deletions documentation/decisions/README.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions documentation/lanes/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ The in-container SilverBullet editor is reached through the Worker proxy. Under
| Method | Endpoint | Auth | Implements | Description |
|--------|----------|------|------------|-------------|
| GET | `/api/vault/:sid/` | Session cookie | [REQ-VAULT-005](../../sdd/spec/vault.md#req-vault-005-worker-proxy-exposes-the-in-container-vault-editor), [REQ-VAULT-021](../../sdd/spec/vault.md#req-vault-021-bucket-stable-vault-url-and-bucket-derived-key) | Entry: validates auth + tier, sets HttpOnly `cf_vault_sid` cookie, 302s to `/api/vault/<token>/`. Retains default security headers. |
| GET | `/api/vault/:sid/status` | Session cookie | [REQ-VAULT-018](../../sdd/spec/vault.md#req-vault-018-vault-browser-prewarm-readiness-gating) AC1 | JSON readiness probe `{ vaultReady }`. Retains full default security headers (CSP + `X-Frame-Options: DENY`). |
| GET | `/api/vault/:sid/status` | Session cookie | [REQ-VAULT-018](../../sdd/spec/vault.md#req-vault-018-vault-control-gating-and-on-demand-prewarm-trigger) AC1 | JSON readiness probe `{ vaultReady }`. Retains full default security headers (CSP + `X-Frame-Options: DENY`). |
| GET / WS | `/api/vault/<token>/*` | `cf_vault_sid` cookie | [REQ-VAULT-005](../../sdd/spec/vault.md#req-vault-005-worker-proxy-exposes-the-in-container-vault-editor), [REQ-VAULT-021](../../sdd/spec/vault.md#req-vault-021-bucket-stable-vault-url-and-bucket-derived-key) | Bucket-stable SilverBullet proxy. Rewrites `<base href>` to `/api/vault/<token>/`. Security headers: `frame-ancestors 'self'`, `X-Frame-Options: SAMEORIGIN`, no CSP. WS upgrades rate-limited (30/60s, shared with terminal). |
| GET | `/api/vault/<token>/service_worker.js` | None (browser-only `service-worker` header) | [REQ-VAULT-017](../../sdd/spec/vault.md#req-vault-017-silverbullet-native-service-worker) | Auth-short-circuited native SilverBullet SW (credential-less registration fetch). |
| GET | `/api/vault/<token>/.codeflare-bootstrap` | Session cookie | [REQ-VAULT-008](../../sdd/spec/vault.md#req-vault-008-zero-ui-vault-encryption) AC5, [REQ-VAULT-021](../../sdd/spec/vault.md#req-vault-021-bucket-stable-vault-url-and-bucket-derived-key) | Bootstrap hop: registers native SW, posts bucket-derived key via `set-encryption-key`, sets `codeflare_vault_bootstrap` cookie, redirects to token URL. |
| GET | `/api/vault/<token>/.vault-key` | Session cookie | [REQ-VAULT-008](../../sdd/spec/vault.md#req-vault-008-zero-ui-vault-encryption) AC7 | Returns `{ key }` JSON (bucket-derived HKDF key) for in-memory key recovery by the grafted SW. `Cache-Control: no-store`. |
| GET | `/api/vault/<token>/.codeflare-bootstrap` | Session cookie | [REQ-VAULT-024](../../sdd/spec/vault.md#req-vault-024-vault-bootstrap-hop-key-arming-and-service-worker-retention) AC1, [REQ-VAULT-021](../../sdd/spec/vault.md#req-vault-021-bucket-stable-vault-url-and-bucket-derived-key) | Bootstrap hop: registers native SW, posts bucket-derived key via `set-encryption-key`, sets `codeflare_vault_bootstrap` cookie, redirects to token URL. |
| GET | `/api/vault/<token>/.vault-key` | Session cookie | [REQ-VAULT-024](../../sdd/spec/vault.md#req-vault-024-vault-bootstrap-hop-key-arming-and-service-worker-retention) AC5 | Returns `{ key }` JSON (bucket-derived HKDF key) for in-memory key recovery by the grafted SW. `Cache-Control: no-store`. |

### User Management

Expand Down
20 changes: 10 additions & 10 deletions documentation/lanes/billing.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ Codeflare uses a multi-tier subscription system that controls monthly compute ho

**Default tier configuration** (from `getDefaultTiers()` in `src/lib/subscription.ts`):

| ID | Display Name | Hours/Month | Sessions | Modes | Storage |
|----|-------------|-------------|----------|-------|---------|
| `blocked` | Blocked | 0 | 0 | - | 0 |
| `pending` | Pending | 0 | 0 | - | 0 |
| `free` | Free | 4h | 1 | Standard | 250 MB |
| `trial` | Trial | 5h | 2 | Standard | 500 MB |
| `standard` | Starter | 40h | 1 | Standard, Pro | 500 MB |
| `advanced` | Advanced | 80h | 2 | Standard, Pro | 1 GB |
| `max` | Max | 160h | 3 | Standard, Pro | 2 GB |
| `unlimited` | Custom | Unlimited | 5 | Standard, Pro | Unlimited |
| ID | Display Name | Hours/Month | Sessions | Modes | Storage | canLogin |
|----|-------------|-------------|----------|-------|---------|----------|
| `blocked` | Blocked | 0 | 0 | - | 0 | false |
| `pending` | Pending | 0 | 0 | - | 0 | true |
| `free` | Free | 4h | 1 | Standard | 250 MB | true |
| `trial` | Trial | 5h | 2 | Standard | 500 MB | true |
| `standard` | Starter | 40h | 1 | Standard, Pro | 500 MB | true |
| `advanced` | Advanced | 80h | 2 | Standard, Pro | 1 GB | true |
| `max` | Max | 160h | 3 | Standard, Pro | 2 GB | true |
| `unlimited` | Custom | Unlimited | 5 | Standard, Pro | Unlimited | true |

Prices, trial hours, and other parameters are configurable per deployment via the admin Subscription Management panel. Prices come from Stripe via admin-configured price slots per tier: `stripePriceId` (Standard mode) and `stripeAdvancedPriceId` (Pro mode) (CF-027). The mode-on-plan-change reconcile (below) reverse-looks-up these slots when the price carries no `mode` metadata.

Expand Down
5 changes: 3 additions & 2 deletions documentation/lanes/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ Environment variables, secrets, CORS configuration, and API token permissions.
| `FAST_CLI_START` | Disables auto-update for all 6 AI tools when `'true'` (default); when `'false'`, update suppressors are removed and Pi runs `pi update` during startup | `'true'` | no | Worker -> DO | [REQ-AGENT-012](../../sdd/spec/agents.md#req-agent-012-fast-cli-start-configurable) |
| `PI_OFFLINE` | Disables Pi network checks when `1`; set by entrypoint when `FAST_CLI_START=true` | `1` (via entrypoint) | no | Dockerfile ENV / entrypoint | [REQ-AGENT-012](../../sdd/spec/agents.md#req-agent-012-fast-cli-start-configurable) |
| `PI_SKIP_VERSION_CHECK` | Suppresses Pi version check when `1`; set by entrypoint when `FAST_CLI_START=true` | `1` (via entrypoint) | no | Dockerfile ENV / entrypoint | [REQ-AGENT-012](../../sdd/spec/agents.md#req-agent-012-fast-cli-start-configurable) |
| `CONTEXT_MODE_BRIDGE_IDLE_MS` | Disables context-mode bridge-child idle reaping/noisy idle-release notices when `0`; set by entrypoint and reinforced by the preseeded Pi runtime extension | `0` (via entrypoint) | no | entrypoint / `context-mode-runtime.ts` | [REQ-AGENT-005](../../sdd/spec/agents.md#req-agent-005-pro-mode-includes-additional-skills-rules-agents-and-mcp-servers) AC5 |
| `CONTEXT_MODE_BRIDGE_IDLE_MS` | Disables context-mode bridge-child idle reaping/noisy idle-release notices when `0`; set by entrypoint and reinforced by the preseeded Pi runtime extension | `0` (via entrypoint) | no | entrypoint / `context-mode-runtime.ts` | [REQ-AGENT-076](../../sdd/spec/agents.md#req-agent-076-pi-context-mode-enablement-and-tool-extension-defaults) AC6 |
| `PI_NPM_PRESEED` | Path to image-local Pi extension npm seed cache | `/opt/codeflare/pi-agent/npm` | no | Dockerfile | [REQ-AGENT-001](../../sdd/spec/agents.md#req-agent-001-support-multiple-ai-coding-agents) |
| `PI_NPM_DIR` | Path to user-home Pi extension npm directory | `$USER_HOME/.pi/agent/npm` | no | entrypoint | [REQ-AGENT-001](../../sdd/spec/agents.md#req-agent-001-support-multiple-ai-coding-agents) |
| `CODEFLARE_OPENAI_API_KEY` | OpenAI API key for the consult-llm-mcp MCP server (optional). Injected under a `CODEFLARE_` namespace so coding agents (Pi, opencode, antigravity) cannot auto-detect it as their own credential; the entrypoint maps it back to the bare `OPENAI_API_KEY` ONLY inside the server's scoped `env`. Not injected in enterprise mode. | - | no | Worker -> DO (from KV `llm-keys:{bucket}`) | [REQ-AGENT-031](../../sdd/spec/agents.md#req-agent-031-consult-llm-key-isolation-subscription-backend-and-multi-agent-parity), [REQ-AGENT-009](../../sdd/spec/agents.md#req-agent-009-llm-api-key-storage-encrypted-in-kv) |
| `CODEFLARE_GEMINI_API_KEY` | Gemini API key for the consult-llm-mcp MCP server (optional). Namespaced like `CODEFLARE_OPENAI_API_KEY`; mapped back to the bare `GEMINI_API_KEY` ONLY inside the server's scoped `env`. Not injected in enterprise mode. | - | no | Worker -> DO (from KV `llm-keys:{bucket}`) | [REQ-AGENT-031](../../sdd/spec/agents.md#req-agent-031-consult-llm-key-isolation-subscription-backend-and-multi-agent-parity), [REQ-AGENT-009](../../sdd/spec/agents.md#req-agent-009-llm-api-key-storage-encrypted-in-kv) |
| `ENCRYPTION_KEY` | AES-256 key (base64) for rclone SSE-C. Appended to `rclone.conf` as `sse_customer_key_base64`. **Omitted in Governed Mode** (`R2_SSE_DISABLED`, [REQ-ENTERPRISE-018](../../sdd/spec/enterprise-mode.md#req-enterprise-018-governed-mode-r2-sse-c-disable-toggle--lossless-re-encrypt-migration)): SSE-C is off there so rclone never uses it, so this shared key is not placed in the container. Under strict egress + Governed Mode the container then holds no real secret but `CONTAINER_AUTH_TOKEN`. | - | no | Worker -> DO (from `env.ENCRYPTION_KEY`; not in Governed Mode) | [REQ-SEC-002](../../sdd/spec/security.md#req-sec-002-api-tokens-never-enter-containers), [REQ-SEC-005](../../sdd/spec/security.md#req-sec-005-r2-files-encrypted-at-rest-with-sse-c-when-operator-configures-an-encryption-key), [REQ-ENTERPRISE-018](../../sdd/spec/enterprise-mode.md#req-enterprise-018-governed-mode-r2-sse-c-disable-toggle--lossless-re-encrypt-migration) |
| `ENCRYPTION_KEY` | AES-256 key (base64) for rclone SSE-C. Appended to `rclone.conf` as `sse_customer_key_base64`. **Omitted in Governed Mode** (`R2_SSE_DISABLED`, [REQ-ENTERPRISE-018](../../sdd/spec/enterprise-mode.md#req-enterprise-018-governed-mode-toggle-and-configuration-surface)): SSE-C is off there so rclone never uses it, so this shared key is not placed in the container. Under strict egress + Governed Mode the container then holds no real secret but `CONTAINER_AUTH_TOKEN`. | - | no | Worker -> DO (from `env.ENCRYPTION_KEY`; not in Governed Mode) | [REQ-SEC-002](../../sdd/spec/security.md#req-sec-002-api-tokens-never-enter-containers), [REQ-SEC-005](../../sdd/spec/security.md#req-sec-005-r2-files-encrypted-at-rest-with-sse-c-when-operator-configures-an-encryption-key), [REQ-ENTERPRISE-018](../../sdd/spec/enterprise-mode.md#req-enterprise-018-governed-mode-toggle-and-configuration-surface) |
| `SESSION_MODE` | Session mode (`'default'` or `'advanced'`) - controls memory persistence and rclone filters | `'default'` | no | Worker -> DO via `setBucketName` | [REQ-MEM-011](../../sdd/spec/memory.md#req-mem-011-session-mode-storage-resolution-and-propagation), [REQ-AGENT-003](../../sdd/spec/agents.md#req-agent-003-agent-cli-auto-started-in-tab-1) |
| `NODE_COMPILE_CACHE` | V8 compile cache dir for faster Node.js CLI startup | `/root/.cache/node-compile-cache` | no | Dockerfile ENV | [REQ-AGENT-001](../../sdd/spec/agents.md#req-agent-001-support-multiple-ai-coding-agents) |
| `BROWSER` | Points to `open-url` shim that exits 1 | `/usr/local/bin/open-url` | no | Dockerfile ENV | [REQ-AGENT-013](../../sdd/spec/agents.md#req-agent-013-browser-shim-for-oauth-flows) |
Expand Down Expand Up @@ -369,6 +369,7 @@ You can adjust scopes anytime from your [GitHub token settings](https://github.c
## Specification Coverage

- [REQ-ENTERPRISE-001](../../sdd/spec/enterprise-mode.md#req-enterprise-001-enterprise_mode-forces-unlimited-tier-and-pro-mode) - ENTERPRISE_MODE forces unlimited tier and Pro mode
- [REQ-ENTERPRISE-018](../../sdd/spec/enterprise-mode.md#req-enterprise-018-governed-mode-toggle-and-configuration-surface) - Governed Mode toggle and configuration surface (setup:r2_sse_disabled; ENCRYPTION_KEY omitted when active)
- [REQ-ENTERPRISE-003](../../sdd/spec/enterprise-mode.md#req-enterprise-003-agent-allowlist-in-enterprise-mode) - Agent allowlist in Enterprise Mode
- [REQ-ENTERPRISE-004](../../sdd/spec/enterprise-mode.md#req-enterprise-004-outbound-interception-llm-routing-to-customer-ai-gateway) - Outbound-interception LLM routing to customer AI Gateway (AIG_GATEWAY_URL, AIG_TOKEN)
- [REQ-ENTERPRISE-006](../../sdd/spec/enterprise-mode.md#req-enterprise-006-deploy-time-aig-secrets-and-enterprise_mode-var) - Deploy-time AIG secrets and ENTERPRISE_MODE var (AIG_GATEWAY_URL, AIG_TOKEN; now an optional fallback)
Expand Down
2 changes: 1 addition & 1 deletion documentation/lanes/container.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ When enabled, `entrypoint.sh` disables auto-update checks for all AI tools, elim

**Codex dismissed_version hack:** Writes `{"dismissed_version":"999.0.0"}` to trick the Codex version checker into thinking a future version was already dismissed. The `~/.codex/` directory is excluded from rclone sync, so this file is safe to recreate on every container start.

**context-mode update notice (always disabled, not Fast-Start-gated):** context-mode is not a CLI agent but it polls `registry.npmjs.org/context-mode/latest` (MCP server on boot + hourly; CLI on each `ctx_stats`/`ctx_insight` render) and prints an "Update available ... ctx_upgrade" line into the agent chat. It exposes no env var or flag to suppress this, so the Dockerfile context-mode bundle patch (the same step that prepends the createRequire shim) repoints the probe URL at a refused local address; the version then resolves to `"unknown"`, the notice never renders, and no outbound npm traffic is generated. This disable is unconditional — a governed container is not a surface a user self-upgrades context-mode from — and is unaffected by the Fast Start toggle. See [REQ-AGENT-005](../../sdd/spec/agents.md#req-agent-005-pro-mode-includes-additional-skills-rules-agents-and-mcp-servers) AC8.
**context-mode update notice (always disabled, not Fast-Start-gated):** context-mode is not a CLI agent but it polls `registry.npmjs.org/context-mode/latest` (MCP server on boot + hourly; CLI on each `ctx_stats`/`ctx_insight` render) and prints an "Update available ... ctx_upgrade" line into the agent chat. It exposes no env var or flag to suppress this, so the Dockerfile context-mode bundle patch (the same step that prepends the createRequire shim) repoints the probe URL at a refused local address; the version then resolves to `"unknown"`, the notice never renders, and no outbound npm traffic is generated. This disable is unconditional — a governed container is not a surface a user self-upgrades context-mode from — and is unaffected by the Fast Start toggle. See [REQ-AGENT-076](../../sdd/spec/agents.md#req-agent-076-pi-context-mode-enablement-and-tool-extension-defaults) AC4.

When Fast Start is disabled (`FAST_CLI_START=false`), `entrypoint.sh` unsets the Dockerfile-level env vars (`DISABLE_AUTOUPDATER`, `DISABLE_INSTALLATION_CHECKS`) and the entrypoint-level update suppressors (`OPENCODE_DISABLE_AUTOUPDATE`, `PI_OFFLINE`, `PI_SKIP_VERSION_CHECK`), skips setting `COPILOT_AUTO_UPDATE`, removes Codeflare-managed Codex settings-file suppressors, and runs `pi update` so Pi and Pi packages reconcile before the session starts. Fast Start ON sets `PI_OFFLINE=1`, so Pi skips startup network checks and will not install restored user-added Pi packages that are absent from the image cache until Fast Start is turned off.

Expand Down
6 changes: 6 additions & 0 deletions documentation/lanes/mobile.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ The mobile terminal input system uses several techniques to work around browser/

### Root Cause

_(The fix-log analysis below was performed against xterm 6.0.0's exact source. `@xterm/xterm`
is currently pinned to `6.1.0-beta.288` as an unconfirmed Pi-flicker mitigation — see
[Troubleshooting: Pi Terminal Flicker](troubleshooting.md#pi-terminal-flicker-investigation-ongoing).
The beta's viewport-DOM-sync change does not appear to alter the mechanisms described
here, but this has not been independently re-verified against the beta.)_

xterm 6.0.0 replaced `.xterm-viewport` (native `overflow-y: scroll` with a scroll-area div) with VS Code's `SmoothScrollableElement` (JS-based scrolling via transforms). Despite this, the terminal would jump to the top of scrollback during burst output (git: Fix 8). Root cause was a vicious cycle between two performance hacks:

**`_syncTextArea` freeze + scroll guard vicious cycle:**
Expand Down
Loading