Repository navigation
Hosted context is never taken for a workstation when it cannot be read (#83) - #89
Conversation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
#83) The hosted operator discovery now tells three kinds apart: positively absent (not Linux, no handover, another account), hosted (the declared operator's Folder) and unreadable (unsafe custody, a permission error, malformed or off-schema handover, inconsistent operator fields, an operator record that cannot be resolved). `hostedEnvironmentPreset` rejects with `HostedEnvironmentUnreadable` when that context, or the declared Folder, its state or preferences, cannot be read. gh's curated login, key linking and sign-out stop before gh runs as failed / environment-unreadable; a running session re-reads the context through one sticky reader per command before each later effect, so a lost or no-longer-found hosted Folder stops key creation, registration and known_hosts. Nothing is signed out or removed. Commands that only look up a Folder keep taking none from an unreadable context; doctor names it as machine-binding warn handover-unreadable. The handover reader takes its root and custodian as a parameter only, so a consumer proof reads real handover and Folder files in a private temporary root. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
agentrozjedemeai
left a comment
There was a problem hiding this comment.
@immakermatty APPROVED on exact head b8fd319; do not treat this as a merge instruction.
#87 contract is intact: git diff e6fa282 -- tests/tools-team-github.test.ts tests/qualify-evidence.test.ts is empty; all 12 ordinary regression assertions pass. Real-file discovery covers absent, single-operator, Team, unreadable/unsafe/malformed handover, missing Folder/state/preferences and malformed preferences; unreadable never becomes workstation for gh. The typed errors, sticky lost-context reader, initial and running-session refusals and credential-preserving logout refusal check out. Independently reproduced the issue #83 empty Folder and throwing resolver: both refuse login, --ssh-key and logout before gh is invoked. Test-only source is not exposed by production CLI or environment, whose Linux default remains / with UID 0 custody. I traced the hosted discovery callers: curated gh fails closed; install/prompt and composio/wacli are unaffected; update, organization/module, chat link and recover act on no guessed Folder; doctor warns. No concrete customer/Organization/host or private operational detail introduced in this public diff (fixture names are placeholders).
Local pinned Bun 1.4.2: 999 pass, 4 platform skips, 0 fail; lint, typecheck, public guard (385 files), build:proof, smoke:proof and diff --check pass. Exact-head CI: ubuntu-24.04 and macos-14 both pass; zero unresolved threads at review.
Open questions: (1) Keep another-account behavior unchanged for #83; decide separately whether the Team rule should prohibit non-operator accounts, with an explicit account-scope contract and tests, rather than infer operator authority. (2) Prefer distinct environment-unreadable diagnostics in organization/module and read-only surfaces as a follow-up for operator clarity; current no-guessed-Folder refusal is safe. (3) Accept the parameter-only source for real-file tests while preserving unoverrideable production defaults and custody checks.
Why
On a hosted Machine,
lazurio tools login ghand--ssh-keydecide the Team rule of #66 from the preset of the declared operator's Folder. Until now, every failure on that path — an unreadable or malformed handover, a missing declared Folder, missing or malformed Folder preferences, a resolver error — collapsed into "no hosted context", so the CLI behaved as on a workstation and allowed a personal gh sign-in and SSH-key linking on a Team Environment (#83). A context that is there but cannot be read is not evidence of a workstation.What changes
discoverHostedOperator(src/machine/operator.ts) returnsabsent(not Linux, no handover at all, a valid handover whose operator is another account or root),hosted(the declared operator's Folder) orunreadable(unsafe custody, a permission error, malformed JSON, a schema mismatch, operator fields that disagree with each other, an operator record that cannot be resolved).hostedOperatorFolderkeeps thehostedFolderseam shape: it resolves the Folder, resolvesundefinedonly when there positively is none, and rejects with the typedMachineContextErrorwhen the context is unreadable.hostedEnvironmentPreset(src/tools/github-gate.ts) rejects withHostedEnvironmentUnreadablewhen the seam rejects or the declared Folder, its state or its preferences cannot be read (a lock that stays busy counts too). One reader per command (hostedEnvironmentReader) is sticky: once a hosted Folder was found, a later read that finds none isunreadable(lost), not a workstation.tools login gh,tools login gh --ssh-keyandtools logout ghon an unreadable Environment return the existing{ kind: "failed", tool: "gh", reason: "environment-unreadable" }with the existing JSON envelope and exit 1, before gh starts. A running session already ended asenvironment-unreadablewhen its re-check threw; the re-check now throws on an unreadable or lost context, so key creation, registration andknown_hostsdo not follow. A pending key-scope refresh keeps the existing key and the signed-in account. Nothing is signed out or removed; an already approved device flow is not undone.readMachineContext(source)takes the platform, filesystem root and custodian. Production stays Linux,/and root. No CLI flag or environment variable reaches it. This lets the consumer proof read real files.machine-bindingiswarn/handover-unreadableand no longerskipped/no-folder.docs/environment-tools.mdanddocs/decisions.md(F19 "How the kind of Environment is known", with an addendum for Curated gh login fails open when the hosted Environment context cannot be read #83). The known limit that the CLI treats an unreadable Folder as a workstation is removed. No base-instructions template text described this behaviour, so the template is unchanged.Every caller of the hosted discovery and its decision
lazurio tools login gh/--ssh-key(src/cli.ts→runToolsCommand→runLogin)environment-unreadablebefore gh runs, and again before every later effect of a running session (sticky reader).lazurio tools logout ghenvironment-unreadable, nothing signed out. This matches the Launchpad, which already fails when its preset cannot be read.lazurio tools login composio/waclilazurio tools installlazurio tools prompt ghlazurio update,update status(standardFolder)lazurio organization …,lazurio module …(operatorFolder)blocked/folder-unknown. They never act on a guessed Folder, which is already fail-closed for effects. Proven on real files in the new suite.lazurio chat link(operatorFolder)lazurio doctormachine-bindingwarnhandover-unreadable.lazurio recover/ Recovery source.catch, now commented). Its own handover readout already showsnull.folderPreset), not this discoveryoperation-failed,environment-unreadablefor sessions).lazurio machine inspect / folder-init / folder-refreshreadMachineContextdirectly, typed errorsWhat does not change
team-environment(Team Environment: gh works through Lazurio for GitHub — personal sign-in refused in CLI and routes, the broker's identity shown, sign-out of a leftover personal account #66), as before.hostedFolderseam signature and every existing test injection.git diff e6fa282 -- tests/tools-team-github.test.ts tests/qualify-evidence.test.tsis empty.Verification (macOS, pinned Bun 1.4.2)
tests/tools-team-github.test.ts37 pass, 0 fail.tests/hosted-context-discovery.test.ts, 15 pass, 0 skip. It uses a reallazurio.machine.jsonbuilt from the repository's P3 fixtures and a real Folder in a private temporary root, the realdiscoverHostedOperator→hostedOperatorFolder→hostedEnvironmentPreset, and the reallazurio toolsCLI with fake gh and a temporary HOME. Cases:team-environment;environment-unreadablefor login,--ssh-keyand logout, gh is never called,gh.stateis kept and no.sshis created;organization liston an unreadable handover:folder-unknown.bun run lint,bun run typecheck,bun run check:public,bun run build:proofandbun run smoke:proofpass.Open questions
absent, which means gh login is allowed for that account, as before. Should a non-operator account on a Team Machine also be refused?update,organization,moduleandchat linkkeep "no Folder" on an unreadable context. They do not refuse with a distinctenvironment-unreadablereason. Should they say so explicitly, beyond doctor?readMachineContext. The handover reader gained a parameter-only source (root, custodian, platform) for the consumer proof, because production had no path override (by design, none via CLI or environment). Confirm that this seam is acceptable.Refs #83 (implements it; closing the issue is left to the Principal)
Contains the test contract of #87 (commits efc74da, e6fa282) unchanged.
🤖 Generated with Claude Code
Note
Fail GitHub tool operations closed when hosted context is unreadable
MachineContextErrorinstead of collapsing into a workstation result.ghlogin, install, and logout now carry explicit none/hosted/unreadable environment state via github-gate.ts and curated-cli.ts. Unreadable context fails with exit 1 before anyghcall, and credentials and SSH keys are never removed. A previously found hosted Folder that disappears mid-command is reported as lost, not absent.standardFolderin update/cli.ts treats a rejected hosted lookup as no Folder, so Folder-independent update paths keep running.hostedOperatorFoldernow get a rejection for unreadable context where they previously receivedundefined; GitHub login/logout on unreadable hosted context now exit 1 without invokinggh, replacing the old workstation fallback.Macroscope summarized b8fd319.