Skip to content

iOS simulators can live in Xcode's device set (drivers.ios.deviceSet) #968

Closed

Description

@V3RON

Part of #962.

Scope

An operator sets drivers.ios.deviceSet: "default" and restarts the daemon. Simlock then keeps its iOS simulators in Xcode's own device set, so xcodebuild, the React Native CLI, Detox and agent-device's XCTest runner target a leased simulator by its UDID. Simlock still claims only simulators whose mark names its own instance. A bad value, or a switch with simulators left from the other setting, turns iOS off with a reason doctor shows. Unset, everything is as today. The website gets a "Build and run your app" page, and simlock instructions names the build route for each setting. simlock doctor shows a refused driver's reason (today a refused driver makes doctor fail, F29). A stopped slow-lane run leaves no simulator in the maintainer's Xcode set.

One task, kept whole: every behaviour reads the one setting through the iOS driver, and the docs and instructions must change with it (documentation rule 9). About 12 Tests lines.

The "Build and run your app" page (using-devices/build-and-run.mdx) holds: under simlock, -DVTSimulatorSetLocation="$SIMLOCK_IOS_DEVICE_SET" on Xcode 27 or later, and on older Xcode or a tool that takes no extra xcodebuild arguments the generic build (-destination 'generic/platform=iOS Simulator') then simlock simctl install or agent-device install; under default, -destination "platform=iOS Simulator,id=<udid>" directly; on Android, ANDROID_ADB_SERVER_PORT from the grant and -s <serial> (or ANDROID_SERIAL); and a warning for default: xcrun simctl shutdown all stops leased simulators, Simlock reboots each under its lease and the holder loses running apps, and one erased while stopped ends its lease. How to switch: the key, a restart, and the device-set-changed steps. An operator who set drivers.ios.deviceRoot runs those steps with it still set, and removes it only when switching to "default"; the leftover check reads only the default own root, so a custom root's simulators are named by these steps, not by the check (decided in delivery, pending the maintainer).

In short

drivers.ios.deviceSet is "simlock" (default, today's behaviour) or "default" (Xcode's set, ~/Library/Developer/CoreSimulator/Devices). Under "default" no simctl call carries --set, the grant carries no SIMLOCK_IOS_DEVICE_SET, and a simulator is this Simlock's only when its durable mark names this instance's id. The check for simulators left from the other setting reads files only, at driver start: no simctl call is added to start-up.

flowchart LR
  C[config: drivers.ios.deviceSet] --> D["IosSimctlDriver.create (CHANGED)"]
  D -->|bad value / leftovers| R[iOS off: invalid-device-set / device-set-changed]
  D --> S["simctl argv: --set root, or none (CHANGED)"]
  D --> L["listManaged: all in set, or only this instance's marks (CHANGED)"]
  D --> E["grant env: SIMLOCK_IOS_DEVICE_SET, or none (CHANGED)"]
  E --> A[agent-device daemon: set, or Xcode's set]
Loading

Messages, word for word (<…> are the variable parts):

  • Bad value: Refusing the ios device set: drivers.ios.deviceSet must be "simlock" or "default", but it is <JSON of the value>
  • deviceRoot with "default": Refusing the ios device set: drivers.ios.deviceRoot names Simlock's own set, but drivers.ios.deviceSet is "default". Remove one of them.
  • Leftovers under "default": Refusing the ios device set: Simlock's own set at <root> still holds <n> simulator(s) (<udid>, <udid>, …). Set drivers.ios.deviceSet back to simlock, run `simlock nuke --delete-devices` and `simlock doctor --purge-orphans`, then switch again. Delete any that remain with `xcrun simctl --set <root> delete <udid>`.
  • Leftovers under "simlock": Refusing the ios device set: Xcode's device set still holds <n> of this Simlock's simulator(s) (<udid>, …). Set drivers.ios.deviceSet back to default, run `simlock nuke --delete-devices` and `simlock doctor --purge-orphans`, then switch again. Delete any that remain with `xcrun simctl delete <udid>`.
deviceSet deviceRoot Today After
not set not set own set own set
"simlock" /Volumes/sims own set at /Volumes/sims the same
"default" not set key ignored, own set Xcode's set
"default" /Volumes/sims key ignored iOS off, invalid-device-set
"Default", "", true, 1 not set key ignored iOS off, invalid-device-set

The operator's and agent's sessions are in #962, How it works for the user.

If this goes wrong, a user would notice Simlock wiping or deleting a simulator of their own or of another Simlock, or iOS staying off after they followed the printed steps.

Technical spec

Facts

At 3de46d1ff unless noted.

# Fact Source
F1 Every scoped simctl call is built by one method, ["simctl", "--set", this.#deviceRoot, ...args]; #invokeSimctl uses it src/drivers/ios/index.ts:1565-1571
F2 The passthrough builds its own argv ["simctl", "--set", this.#deviceRoot, ...args] with env: {} src/drivers/ios/index.ts:1337-1342
F3 runtime delete goes through #scopedSimctlArgv src/drivers/ios/index.ts:545-555
F4 Unscoped calls: findLegacy, destroyLegacy, and #listedImages' simctl list -j devices of the default set src/drivers/ios/index.ts:1084-1113, :634-637, :1573-1584
F5 listManaged lists every device in the scoped set and reads its marks, with no other filter src/drivers/ios/index.ts:1123-1140
F6 provision names a device simlock-<id> (cosmetic) and writes the mark (:741); reclaim writes a fresh mark (:1062) src/drivers/ios/index.ts:726-741, :1062
F7 #writeMark writes { token, udid, writtenAt }, erasable <dir>/data/simlock-mark.json first, then durable <dir>/simlock-mark.json; #readToken reads only token src/drivers/ios/index.ts:1449-1490
F8 The device folder is join(this.#deviceRoot, udid) src/drivers/ios/index.ts:1427-1429
F9 create calls ensureOwnedRoot on configuredDeviceRoot(options); revalidateRoot calls it again src/drivers/ios/index.ts:358-386
F10 A non-string or relative deviceRoot throws OwnedRootError(…, "not-absolute", …, "ios") src/drivers/ios/index.ts:1706-1724
F11 IosSimctlDriverOptions carries instanceId and coreSimulatorRoot; the daemon passes coreSimulatorRoot: ~/Library/Developer/CoreSimulator src/drivers/ios/index.ts:201, :207; src/daemon/main.ts:1368
F12 The daemon catches an iOS OwnedRootError, logs "Skipped iOS driver: device root rejected", and emits driver.root-rejected with { platform, reason, root }; Android starts on src/daemon/main.ts:1404-1409, :1490-1502
F13 RootRejectionReason is a closed union in core, listed in EVENTS.md; the bus payload reason is a string src/core/device-root.ts:10-24; src/bus/index.ts:415-419; docs/internal/EVENTS.md:153
F14 virtualLeaseEnvironment returns { SIMLOCK_IOS_DEVICE_SET: this.#deviceRoot }; a virtual leaseEnvironment returns the same src/drivers/ios/index.ts:1306-1313
F15 The screen capture gets SIMLOCK_IOS_DEVICE_SET: options.deviceSet for a simulator (deviceSet: deviceRoot); the capture program searches the default set when the variable is unset src/drivers/ios/screen-capture.ts:120-124; src/drivers/ios/index.ts:339; vendor/screen-capture/Sources/simlock-screen-capture/FrameCapture.swift:417-441
F16 The agent-device supervisor copies SIMLOCK_IOS_DEVICE_SET to AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET only when present, iOS on, role not phones; the env comes from every driver's virtualLeaseEnvironment src/agent-device/host/agent-device-supervisor.ts:576-581; src/daemon/main.ts:488-490
F17 agent-device with no set runs simctl without --set and xcodebuild with a plain -destination agent-device v0.21.28 packages/platform-apple/src/core/simctl.ts:28-29, packages/platform-apple/src/runner/runner-device-set.ts:24-26, packages/kernel/src/device.ts:346-348
F18 The agent-device front refuses a client --ios-simulator-device-set src/agent-device/front/request-rules.ts:145-151
F19 doctor --purge-orphans destroys devices listManaged reports that have no registry record, after revalidateRoot src/core/doctor.ts:264, :335-356, :393-410
F20 nuke --delete-devices destroys only registry virtual devices it can bring to shutdown src/core/nuke-service.ts:95-150
F21 foreignDevices in component.list counts devices outside Simlock using a runtime; iOS takes it from the default set's list -j devices per runtime src/contract/operations.ts:897-923; src/drivers/ios/index.ts:634-651, :1976-1989
F22 The passthrough refuses create, erase, delete, shutdown all, runtime delete, and any flag before the subcommand src/drivers/ios/index.ts:126-136, :1372-1426
F23 Driver config is opaque to core: drivers.<platform>.* is a string/number/boolean record the driver reads src/core/config.ts:266-269, :1238
F24 A second instance under one OS user is a second SIMLOCK_HOME with its own instanceId; the slow lane runs every daemon from a temp home src/core/AGENTS.md Known gaps; e2e/helpers/env.ts:177-202; scripts/slow-e2e.sh:22-25
F25 Xcode 27.0: xcodebuild build -destination "platform=iOS Simulator,id=<udid>" of a simulator in a custom set fails "Unable to find a device matching the provided destination specifier"; the same with -DVTSimulatorSetLocation=<set> prints ** BUILD SUCCEEDED ** command run on this Mac, 2026-10-23 (ADR 0048 Context)
F26 #147 (PR #960) adds IOS_BUILDS to src/instructions/index.ts ("Simlock's simulators live in a device set of their own…") with required phrases pinned in src/instructions/index.test.ts gh pr diff 960 lines 439-450, 560-564
F27 The slow-lane suite seeds one shared daemon with configOverrides e2e/slow-agent-device.test.ts:136-146
F28 iOS discovery catches only OwnedRootError; any other error from create is rethrown and stops the daemon start src/daemon/main.ts:1399-1402, :414
F29 Core's driver-unavailable doctor finding is not a kind in the wire doctorFindingSchema; doctor.run's handler returns core findings unchanged; a result that fails its output schema becomes INTERNAL src/core/doctor.ts:1137-1143; src/contract/schemas.ts:868-943; src/daemon/dispatcher.ts:812-823; src/daemon/dispatch.ts:191-193
F30 ScriptedProcessRunner throws Unexpected process invocation on a call it was not scripted for src/ports/process-runner.ts:688-695
F31 provision runs simctl create, then #writeMark, with no cleanup if the mark write throws src/drivers/ios/index.ts:731-741
F32 Doctor turns a registry-device-missing device that findLegacy finds into legacy-device, which --fix destroys; a lost durable mark is otherwise report-only durable-mark-missing src/core/doctor.ts:486-519, :830-840, :1115-1129
F33 The start-up write-leftovers sweep reads dirname(deviceRoot) and removes only staging entries named after the root's own basename src/core/write-leftovers.ts:9-34; src/daemon/main.ts:609, :1837-1842
F34 scripts/slow-e2e.sh clean/stop find a run's processes by /tmp/simlock-slow/ in their command line, then delete that folder scripts/slow-e2e.sh:59-95
F35 An instance's id lives in ${SIMLOCK_HOME}/instance.json src/core/instance-identity.ts:13
F36 The screen-capture env spreads the daemon's base environment and only overwrites SIMLOCK_IOS_DEVICE_SET src/drivers/ios/screen-capture.ts:120-124
F37 unusedDevices (the residue sentence after a runtime removal) counts never-booted default-set devices of that runtime src/drivers/ios/index.ts:653-658, :533-541
F38 The website says foreignDevices counts Xcode-set simulators booted at least once website/src/content/docs/docs/worker/runtimes-and-images.mdx:142
F39 The protocol range is { min: 60, max: 60 } src/contract/protocol.ts:13

Values sent elsewhere:

  • driver.root-rejected reason: invalid-device-set, device-set-changed. The bus types it as string (F13), so it passes; RootRejectionReason gains both.
  • root in that payload: for invalid-device-set, the configured deviceSet value as a string (JSON.stringify for a non-string); for device-set-changed, the path of the set that holds the leftovers.
  • The durable and erasable marks gain instanceId (F7, F11). A mark without it reads as no instance.

Modules touched

Searches: rg -n "deviceRoot|--set|SIMLOCK_IOS_DEVICE_SET|RootRejectionReason|#writeMark|#readMark|foreignDevices" src e2e website/src/content/docs docs/internal/EVENTS.md, and rg -n "device set" website/src/content/docs.

  • src/drivers/ios/index.ts: read deviceSet; create validates it and runs the leftover check (files only); under "default": no --set in F1/F2/F3, deviceRoot and the device folders are <coreSimulatorRoot>/Devices (the sweep then looks only for entries named after Devices, which Simlock never makes there, F33), no ensureOwnedRoot, revalidateRoot resolves, listManaged filters by this instance's durable mark, #listedImages counts the rest as foreign and unused, findLegacy answers undefined (so a lost mark stays report-only, F32), a failed mark write in provision deletes the new simulator before rethrowing, no SIMLOCK_IOS_DEVICE_SET in the lease environment. Under both: the marks carry instanceId.
  • src/drivers/ios/screen-capture.ts: when the driver passes no set, remove SIMLOCK_IOS_DEVICE_SET from the spread environment (F36).
  • src/contract/schemas.ts: a driver-unavailable arm (platform, reason, detail) in doctorFindingSchema; src/contract/protocol.ts: this PR bumps the protocol by one (min and max).
  • src/cli/commands/doctor.ts: writes Unavailable [<platform>] <reason>: <detail> to stderr for each driver-unavailable finding, beside the other finding lines; stdout unchanged.
  • scripts/slow-e2e.sh: clean (and stop, which calls it) also deletes, with xcrun simctl delete <udid>, each simulator in ~/Library/Developer/CoreSimulator/Devices whose durable mark names the instanceId of a home under the lane folder, before removing the folder (F34, F35).
  • src/core/device-root.ts: two new RootRejectionReasons.
  • src/drivers/ios/AGENTS.md, src/drivers/AGENTS.md: the --set rule and ownership rule per setting; the new key.
  • docs/internal/EVENTS.md: driver.root-rejected reasons.
  • src/instructions/index.ts, src/instructions/index.test.ts (from Add simlock instructions: the rules an agent must follow, printable and served over MCP #147): the "iOS builds" section for both settings.
  • src/agent-device/host/agent-device-supervisor.test.ts: the absent-key case (no code change, F16).
  • e2e/slow-agent-device.test.ts (and its helper as A standalone worker serves agent-device on localhost by default #957 leaves it): a "default" daemon case.
  • Website: reference/configuration.mdx (the key), worker/cleanup.mdx (roots, the two reasons, "never touches Xcode's set" per setting), using-devices/working-with-a-device.mdx (env table, simctl --set text, refusals, rules), introduction/how-it-works.mdx (Device), worker/runtimes-and-images.mdx (foreignDevices, F38), reference/cli.mdx (SIMLOCK_IOS_DEVICE_SET "iOS simulator under simlock"), new using-devices/build-and-run.mdx and its line in website/astro.config.mjs under "Using devices".
flowchart LR
  main[daemon/main.ts] --> ios["drivers/ios/index.ts (CHANGED)"]
  ios --> root["core/device-root.ts (CHANGED)"]
  ios --> cap["drivers/ios/screen-capture.ts (CHANGED)"]
  main --> sup[agent-device supervisor]
  ios -. lease env .-> sup
  instr["instructions/index.ts (CHANGED)"]
  disp[daemon/dispatcher.ts] --> doc[core doctor]
  disp --> schema["contract/schemas.ts (CHANGED)"]
Loading

Contract and event changes

doctorFindingSchema gains the driver-unavailable arm core already produces (F29): platform (a platform), reason (a string, at most 64 characters), detail (a string). This PR bumps the protocol by one. driver.root-rejected itself is not a contract shape (rg "root-rejected" src/contract finds nothing; the bus payload reason is a string, F13). driver.root-rejected gains reasons invalid-device-set and device-set-changed: docs/internal/EVENTS.md:153 lists them.

New config field drivers.ios.deviceSet: a string, exactly "simlock" or "default" (case-sensitive); absent means "simlock". Anything else gets invalid-device-set. New mark field instanceId: the instance's id string as written; read as absent when missing or not a non-empty string.

Other code on the same state

Searches: the set path (rg -n "deviceRoot|--set" src, 41 hits), the marks (rg -n "simlock-mark|readMark|provenanceDrift" src, 14 hits), the default set (rg -n "legacySimctl|CoreSimulator" src, 9 hits).

  • Lease health monitor (src/leasing/lease-health-monitor.ts:176, :386-404): reads listManaged and the marks. Under "default" it sees only this instance's devices; drift reads as today, since durable/erasable tokens are unchanged.
  • Doctor (src/core/doctor.ts:264, :1115-1124): orphans and provenance from listManaged; under "default" only this instance's devices, so another instance's or the user's never become orphans.
  • Startup read (src/core/startup-read.ts:64): one listManaged per driver; same filter.
  • findLegacy / destroyLegacy (F4): unscoped already; under "default" the same set. Only registry records reach them.
  • Another Simlock instance under "default" in the same Xcode set: each lists only its own marks, so neither sees the other's devices. Its simctl writes touch only UDIDs its own registry names.
  • device.exec fills in the lease's device and refuses another #958 (device.exec fill-in): changes the same passthrough method. T1 builds on it: the argv rule here applies to the argv device.exec fills in the lease's device and refuses another #958 builds.

Failure modes

Call Outcome What happens Limit, counted from
leftover check under "default": read Simlock's own root folder UUID-named entries device-set-changed, iOS off none (file reads)
same none, or no folder iOS starts same
same unreadable (not ENOENT) OwnedRootError reason unreadable, iOS off; never a daemon-fatal error (F28) same
leftover check under "simlock": read <coreSimulatorRoot>/Devices/*/simlock-mark.json (skipped when no coreSimulatorRoot is given, as in the test helper) a mark naming this instance device-set-changed, iOS off same
same no folder; only unmarked or other-instance marks; a mark file unreadable or corrupt (skipped) iOS starts same
same the folder unreadable (not ENOENT) OwnedRootError reason unreadable, iOS off same
#writeMark in provision under "default" throws simctl delete <udid> (best effort), then the error is rethrown 30 s for the delete, from spawn
mark read under "default" listManaged unreadable, corrupt device not listed (no instance proven) none (file read)

State: the marks gain a field, written atomically as today. A restart between simctl create and the durable mark under "default" leaves one unlisted simlock-<id> simulator in Xcode's set; it is rare, no test, and ios/AGENTS.md Known gaps names it with its fix (xcrun simctl delete <udid>). No new shared state.

Rules in play

  • ADR 0048 §1–5: the key, ownership by instance mark, refusal on a change, no set in any env, refusals kept.
  • ADR 0001 §6, "Orphans are reported, never automatically destroyed": kept; only the orphan rule's input is filtered.
  • Safety: "Simlock destroys only what its registry owns" (docs/internal/ARCHITECTURE.md:112-113): listManaged never offers a device this instance did not mark.
  • Drivers rule 1, "A refusal (OwnedRootError) skips that platform only": both new refusals are OwnedRootErrors.
  • Drivers rule 3, "drivers.<platform>.* are carried unread": core does not validate the key (F23).
  • Documentation rule 9: every page above changes in this PR.
  • Contract manual, "Every change to a contract shape bumps it by one in the same PR": the driver-unavailable arm bumps the protocol by one.

Tests

Seam: IosSimctlDriver (src/drivers/ios/index.test.ts, with ScriptedProcessRunner and MemoryFilesystem), plus agent-device-supervisor.test.ts, src/instructions/index.test.ts and the slow lane. Model on "refuses the platform, not the daemon, when the configured device root is not a path" (index.test.ts:1537) and "reports every device in its set, whatever the device is named" (:1335). Unset key = today: the leftover check reads only files, which the existing tests' MemoryFilesystem does not hold, so no existing test gets a new process call (F30), and the existing suite proves it unchanged.

  • The driver given deviceSet runs every simctl call with or without --set: cases key unset and "simlock" (--set <root> on create, boot, erase, delete, list, runtime delete); "default" (none of them carries --set).
  • An operator with a bad value or a conflicting deviceRoot gets OwnedRootError reason invalid-device-set with the message above: cases "Default", "", true, "default" with deviceRoot set.
  • An operator who switches with leftovers gets device-set-changed: cases "default" with two devices in Simlock's set (refused, message names both UDIDs and xcrun simctl --set <root> delete <udid>); "default" with the set empty, and with no root folder (starts); "simlock" with a device in Xcode's set marked by this instance (refused, xcrun simctl delete <udid>); "simlock" with only unmarked and other-instance devices there (starts); an unreadable folder (unreadable); no case runs a process.
  • A new or reclaimed simulator's marks name this instance: cases "simlock", "default"; both mark files carry instanceId. Under "default", a mark write that fails in provision runs simctl delete <udid> and rethrows.
  • Under "default", listManaged reports only devices whose durable mark names this instance: cases this instance's mark (listed); erasable mark gone (listed, erasable undefined); no mark; a mark with no instanceId; another instance's mark; unmarked named simlock-1 (none of these four listed); findLegacy of a registered UDID answers undefined under "default".
  • Under "default", listComponents foreignDevices and the removal's unused count take only devices this instance's mark does not name: three used devices on one runtime (this instance's, unmarked, another instance's) → foreignDevices 2; three never-used ones → unused count 2.
  • A lease holder and the screen capture get the set only under "simlock": cases "simlock" ({ SIMLOCK_IOS_DEVICE_SET: <root> }, capture env has it); "default" ({}, capture env lacks it, also when the daemon's own environment had it); a physical device under both (SIMLOCK_DEVICE_UDID only).
  • simlock simctl under "default" runs plain xcrun simctl and keeps its refusals: cases install <udid> app.app (argv ["simctl","install",…], no --set); erase <udid>, shutdown all, --set /tmp list (refused as today).
  • The agent-device simulator daemon gets no AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET when the lease env lacks SIMLOCK_IOS_DEVICE_SET and iOS is on (extends "passes every key and value of the drivers' environment unchanged", agent-device-supervisor.test.ts:627).
  • simlock instructions' "iOS builds" section names the route per grant: required phrases SIMLOCK_IOS_DEVICE_SET, -DVTSimulatorSetLocation, Xcode 27, generic/platform=iOS Simulator, xcodebuild -destination id=<udid>.
  • An operator running simlock doctor while iOS is refused gets a driver-unavailable finding with its reason and detail, not INTERNAL (src/daemon/dispatcher.test.ts, extends "doctor.run forwards purgeOrphans…" at :915): cases invalid-device-set, device-set-changed; and simlock doctor writes Unavailable [ios] <reason>: <detail> on stderr with stdout unchanged (src/cli/index.test.ts, modelled on :2364).
  • Slow lane, e2e/slow-agent-device.test.ts: under a daemon with drivers.ios.deviceSet: "default", an agent opens an iOS device, plain xcrun simctl list devices (no --set) lists its UDID, and snapshot answers; teardown runs simlock nuke --delete-devices --yes so no simulator is left in Xcode's set.
  • The "Build and run your app" page's switch steps tell an operator with a custom drivers.ios.deviceRoot to keep it set while running simlock nuke --delete-devices and simlock doctor --purge-orphans, and to remove it only when switching to "default" (checked by the Done when docs review; decided in delivery, pending the maintainer).

Done when

  • pnpm test:changed passes, with the Tests lines above.
  • pnpm --dir website install && pnpm --dir website build && node website/scripts/check-openapi.mjs passes.
  • In each page listed under Modules touched, every iOS hit of rg -n "simctl --set|device set|deviceRoot|SIMLOCK_IOS_DEVICE_SET|foreignDevices" website/src/content/docs says which setting it holds for; website/src/content/docs/docs/using-devices/build-and-run.mdx exists and is in the sidebar under "Using devices".
  • docs/internal/EVENTS.md lists invalid-device-set and device-set-changed.
  • Slow lane (real simulator): scripts/slow-e2e.sh e2e/slow-agent-device.test.ts passes the "default" case.
  • Slow lane: start that case, run scripts/slow-e2e.sh stop while it runs, then xcrun simctl list devices shows no simulator whose durable mark names a lane instance.

Out of scope

Depends on

Written by an agent.

Activity

  1. added
    task:draftScope written; technical spec or its spec check missing.
    on Oct 23, 2026
  2. added
    task:readySpec checked. An agent may implement it once its Depends on allow.
    and removed
    task:draftScope written; technical spec or its spec check missing.
    on Oct 24, 2026
  3. self-assigned this
    on Oct 24, 2026
  4. 20 remaining items

  5. removed their assignment
    on Oct 24, 2026
  6. V3RON commented on Oct 25, 2026

    @V3RON
    ContributorAuthor

    Decision

    Maintainer accepted the deviceRoot switch behaviour in PR #976: the old custom root stays in the set until simlock nuke --delete-devices or doctor --purge-orphans runs, then it is removed, with no registry check. Before the merge, reword safety.md:112 so it does not read as forbidding default. Still parked on the slow lane (disk).

    Written by an agent.

  7. added
    task:readySpec checked. An agent may implement it once its Depends on allow.
    and removed
    task:blockedAgent stopped on a blocker in its handoff. Maintainer re-adds the label it came from.
    on Oct 26, 2026
  8. self-assigned this
    on Oct 26, 2026
  9. added
    task:draftScope written; technical spec or its spec check missing.
    and removed
    task:readySpec checked. An agent may implement it once its Depends on allow.
    on Oct 26, 2026
  10. github-actions commented on Oct 26, 2026

    @github-actions

    Back to task:draft: .agents/scripts/spec-lint.mjs found blocking lines. Fix them in the body, then set task:ready again.

    B 968 Facts: no `Commit <sha>.` line, so no path:line can be checked; add the commit read
    B 968 Done when: "Slow lane: start that case, run `scripts/slow-e2e.sh stop` w…" needs the slow lane but names no `e2e/slow-*.test.ts`; name it
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

task:draftScope written; technical spec or its spec check missing.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions