README's proxy-mode section still promises a keychain trust step no attach performs - #933
README's proxy-mode section still promises a keychain trust step no attach performs#933philcunliffe wants to merge 3 commits into
Conversation
…ttach performs (#923) LLP 0262 moved Claude Code off proxy capture and took the last production caller of `installCaTrust` with it: nothing in the tree installs the interception CA into a trust store any more. The README's "Proxy mode" section was outside that change's diff and still described the removed step in the present tense, including the claim that a detach keeps the keychain trust "so re-attaching does not ask again". That last sentence is the one that costs the reader something. It reads the keychain trust an older release left on their account as a convenience being held for them, when it is a leftover nothing re-creates and only `hyp detach <client> --purge` or `hyp daemon uninstall` clears. The section now says trust is file-scoped to the proxied client's own settings, puts the keychain grant in the past tense as something earlier releases did, and tells a reader who ran one of those that the trust setting is still on their account until they remove it. `test/core/readme-proxy-trust-claims.test.js` is the gate: it pairs the fact that no production module outside `src/core/tls/darwin_trust.js` names `installCaTrust` with the claims the README may not make while that holds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…es (#933 review) The fix for #923 corrected the CA-trust bullet and left the bullet under it making the same stale promise: "On macOS, a proxy attach also leaves a login-session variable behind." `installLaunchdEnv` has no production caller, so no attach runs `launchctl setenv NODE_USE_SYSTEM_CA 1` or writes the login agent. The bullet's own body had already drifted to past tense, so it contradicted its own lead. A reader turning proxy mode on for codex or claude-desktop was told to expect a session-wide variable and a login item that are never created. Also: "nothing installs it into a system trust store" understated the change, since the system keychain was never touched either way. What stopped is the login-keychain install, so the sentence now names it. The guard test only banned the three sentences this branch rewrote, so a paragraph re-documented from scratch could re-assert every one of them in fresh words and stay green. It now carries both halves: the banned claims, and the sentences the README has to keep saying instead. Its tree-fact assertion covers both trust writers, since the keychain root and the launchd variable that made the root count are one grant in two halves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Neutral review recordReviewed: The premise of the change checks out. 1. MEDIUM (fixed) - the next bullet still promises the launchd variable no attach writes
That is the same class of falsehood the PR exists to remove, in the same section. The user-visible cost: someone turning on Fixed: the bullet now leads "an earlier proxy attach also left...", and states "No attach writes either one today" before describing what a pre-0262 machine still carries. The removal sentences ( 2. LOW (fixed) - the guard test was a verbatim denylist, so it caught a revert but not a rewrite
- left the test green. The test's stated purpose ("so the prose cannot drift back without the fact drifting back too") did not hold for any rewrite that reused none of the original wording, which is the likely shape of drift when someone re-documents the feature from scratch. Fixed by giving the gate a second half: a Also hardened 3. LOW (fixed) - "a system trust store" understates what changed
4. LOW (reported, left) - the same claim still ships in
|
The proxy-mode rewrite told README readers that no attach installs the interception CA into an OS trust store, and left `docs/PRIVACY.md` and `hyp detach --help` asserting the opposite in the present tense. The privacy document is where a reader checks what touched their machine and the help text is read at the moment of deciding, so those two were the worse copies to defer. - docs/PRIVACY.md: the keychain install, the password dialog, and the `launchctl setenv` step move to the past tense, and the lifetime paragraph stops selling a plain detach as holding the grant open for a re-attach that never asks again. - src/core/cli/core_commands.js: `hyp detach --help` says the kept trust is a leftover no attach re-creates, not a spared dialog. - README.md: `hyp detach <client>` does not unconditionally clear the launchd variable and its login agent. `releaseProxyModeLaunchdEnv` returns early unless the marker still records a proxy attach, so on a machine migrated to another attach mode (the machine the bullet is about) a plain detach is a no-op for the leftover. Only `--purge` and `hyp daemon uninstall` run the release unconditionally. The gate grows to match. Its claim lists are now per document, because the three say the same thing in three registers and the README's sentences read as non-sequiturs in a terminal help string; the old shared `REQUIRED_TRUTHS` was applied as a cross-product over `SCANNED`, so the widening the file invited would have demanded the README's verbatim prose of every document that joined. The installer scan is word-bounded so a future `installCaTrustForHost` is not read as this one, and its failure message says a module *names* a writer rather than accusing it of installing trust, which is all a text scan can prove. Renamed off `readme-` now that it covers three files.
Neutral review:
|
Neutral triage:
|
…es (#933 review) The fix for #923 corrected the CA-trust bullet and left the bullet under it making the same stale promise: "On macOS, a proxy attach also leaves a login-session variable behind." `installLaunchdEnv` has no production caller, so no attach runs `launchctl setenv NODE_USE_SYSTEM_CA 1` or writes the login agent. The bullet's own body had already drifted to past tense, so it contradicted its own lead. A reader turning proxy mode on for codex or claude-desktop was told to expect a session-wide variable and a login item that are never created. Also: "nothing installs it into a system trust store" understated the change, since the system keychain was never touched either way. What stopped is the login-keychain install, so the sentence now names it. The guard test only banned the three sentences this branch rewrote, so a paragraph re-documented from scratch could re-assert every one of them in fresh words and stay green. It now carries both halves: the banned claims, and the sentences the README has to keep saying instead. Its tree-fact assertion covers both trust writers, since the keychain root and the launchd variable that made the root count are one grant in two halves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The proxy-mode rewrite told README readers that no attach installs the interception CA into an OS trust store, and left `docs/PRIVACY.md` and `hyp detach --help` asserting the opposite in the present tense. The privacy document is where a reader checks what touched their machine and the help text is read at the moment of deciding, so those two were the worse copies to defer. - docs/PRIVACY.md: the keychain install, the password dialog, and the `launchctl setenv` step move to the past tense, and the lifetime paragraph stops selling a plain detach as holding the grant open for a re-attach that never asks again. - src/core/cli/core_commands.js: `hyp detach --help` says the kept trust is a leftover no attach re-creates, not a spared dialog. - README.md: `hyp detach <client>` does not unconditionally clear the launchd variable and its login agent. `releaseProxyModeLaunchdEnv` returns early unless the marker still records a proxy attach, so on a machine migrated to another attach mode (the machine the bullet is about) a plain detach is a no-op for the leftover. Only `--purge` and `hyp daemon uninstall` run the release unconditionally. The gate grows to match. Its claim lists are now per document, because the three say the same thing in three registers and the README's sentences read as non-sequiturs in a terminal help string; the old shared `REQUIRED_TRUTHS` was applied as a cross-product over `SCANNED`, so the widening the file invited would have demanded the README's verbatim prose of every document that joined. The installer scan is word-bounded so a future `installCaTrustForHost` is not read as this one, and its failure message says a module *names* a writer rather than accusing it of installing trust, which is all a text scan can prove. Renamed off `readme-` now that it covers three files.
…h cannot perform (#902) * Stop offering a proxy migration and a CA repair the otel Claude attach cannot perform (#885) Two user-facing instructions left over from LLP 0262, where the `claude` client's attach became otel-only: one settings write, no repointed base URL, no CA, no keychain, no launchd env. 1. `hyp attach claude` on an install whose gateway config lacks `proxy_mode` offered the LLP 0244 migration, because `@hypaware/claude`'s picker row still declared `compose.gateway_proxy_mode`. Every clause of the question was false: the otel attach repoints no base URL, and a yes wrote `proxy_mode`, restarted the daemon, and blocked on a CA mint the following attach never consults. The scripted shapes carried the matching one-line pointer at a migration that does not exist. LLP 0243's own `Extended-by` line already settled the fix: the claude row stops declaring the flag, while the composition rule itself is unchanged. The `hyp init claude` preset, which writes literally what the fold composes, stops writing `proxy_mode: true` for the same reason: a claude-only install would mint a CA it never presents and then trip the gateway's own stale-CA warning. 2. `hyp status`'s proxy-trust block told a macOS host with a leftover CA that an untrusted keychain breaks Remote Control inbound and that `hyp attach claude` retries the trust, and that the same command sets `NODE_USE_SYSTEM_CA`. Nothing installs either any more (`installCaTrust` / `installLaunchdEnv` have no production callers since the otel switch), and Remote Control no longer rests on the trust at all, since the base URL is never repointed (LLP 0262 R6). Both lines now state the fact, and the block names the one command that acts on what it reports: `hyp detach claude --purge`. The migration machinery stays generic for any client still captured by the proxy, and keeps its coverage: the tests drive it through a staged installed plugin whose picker row declares the flag, instead of through `claude`. docs/PRIVACY.md carried the same stale claim ("attach installs the CA into your login keychain") and now describes it as residue of an earlier release. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review fixes: the proxy-trust note must not tell a live proxy_mode install to purge its CA Review of e1ea1a2 found the new `hyp status` proxy-trust note is unconditional, while `proxy_mode: true` still has the gateway mint and present that CA on every start (ai-gateway/src/source.js prepareInterception). On such an install the note read "only proxy_mode capture uses this CA, and the claude attach no longer does" and told the user to run `hyp detach claude --purge`, which deletes the key the running interception terminates TLS with; the next start mints a different one and nothing in the product restores the keychain trust. - ProxyTrustReport carries `proxyModeConfigured`, read off the effective gateway entry, because neither probe can tell a live CA from residue. - The note branches on it: residue keeps the purge, a live proxy_mode gateway is told what still depends on the CA and given nothing to run. `--json` gains `proxy_mode_configured` alongside. - The migration question no longer promises "macOS will then ask to trust the HypAware Local CA": `installCaTrust` has had no production caller since the attach went otel-only, so a yes mints the CA and stops there. - The preset comment claimed writing `proxy_mode: true` would leave the gateway logging its stale-CA warning; that warning only fires on the `!proxyMode` branch. Restated to what the key would actually cost. - PRIVACY.md and `hyp detach --help` no longer say a detach keeps the trust "so a later re-attach does not ask for your password again", which contradicts the same section's "nothing installs this CA into a system trust store any more". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Review fixes: the proxy-trust note must not guess a client, hide the detach, or read an unreadable config as proxy_mode off * README's proxy-mode section still promises a keychain trust step no attach performs (#923) LLP 0262 moved Claude Code off proxy capture and took the last production caller of `installCaTrust` with it: nothing in the tree installs the interception CA into a trust store any more. The README's "Proxy mode" section was outside that change's diff and still described the removed step in the present tense, including the claim that a detach keeps the keychain trust "so re-attaching does not ask again". That last sentence is the one that costs the reader something. It reads the keychain trust an older release left on their account as a convenience being held for them, when it is a leftover nothing re-creates and only `hyp detach <client> --purge` or `hyp daemon uninstall` clears. The section now says trust is file-scoped to the proxied client's own settings, puts the keychain grant in the past tense as something earlier releases did, and tells a reader who ran one of those that the trust setting is still on their account until they remove it. `test/core/readme-proxy-trust-claims.test.js` is the gate: it pairs the fact that no production module outside `src/core/tls/darwin_trust.js` names `installCaTrust` with the claims the README may not make while that holds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Proxy-mode section still promises the launchd variable no attach writes (#933 review) The fix for #923 corrected the CA-trust bullet and left the bullet under it making the same stale promise: "On macOS, a proxy attach also leaves a login-session variable behind." `installLaunchdEnv` has no production caller, so no attach runs `launchctl setenv NODE_USE_SYSTEM_CA 1` or writes the login agent. The bullet's own body had already drifted to past tense, so it contradicted its own lead. A reader turning proxy mode on for codex or claude-desktop was told to expect a session-wide variable and a login item that are never created. Also: "nothing installs it into a system trust store" understated the change, since the system keychain was never touched either way. What stopped is the login-keychain install, so the sentence now names it. The guard test only banned the three sentences this branch rewrote, so a paragraph re-documented from scratch could re-assert every one of them in fresh words and stay green. It now carries both halves: the banned claims, and the sentences the README has to keep saying instead. Its tree-fact assertion covers both trust writers, since the keychain root and the launchd variable that made the root count are one grant in two halves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The trust-leftover correction stopped at the README (#933 review) The proxy-mode rewrite told README readers that no attach installs the interception CA into an OS trust store, and left `docs/PRIVACY.md` and `hyp detach --help` asserting the opposite in the present tense. The privacy document is where a reader checks what touched their machine and the help text is read at the moment of deciding, so those two were the worse copies to defer. - docs/PRIVACY.md: the keychain install, the password dialog, and the `launchctl setenv` step move to the past tense, and the lifetime paragraph stops selling a plain detach as holding the grant open for a re-attach that never asks again. - src/core/cli/core_commands.js: `hyp detach --help` says the kept trust is a leftover no attach re-creates, not a spared dialog. - README.md: `hyp detach <client>` does not unconditionally clear the launchd variable and its login agent. `releaseProxyModeLaunchdEnv` returns early unless the marker still records a proxy attach, so on a machine migrated to another attach mode (the machine the bullet is about) a plain detach is a no-op for the leftover. Only `--purge` and `hyp daemon uninstall` run the release unconditionally. The gate grows to match. Its claim lists are now per document, because the three say the same thing in three registers and the README's sentences read as non-sequiturs in a terminal help string; the old shared `REQUIRED_TRUTHS` was applied as a cross-product over `SCANNED`, so the widening the file invited would have demanded the README's verbatim prose of every document that joined. The installer scan is word-bounded so a future `installCaTrustForHost` is not read as this one, and its failure message says a module *names* a writer rather than accusing it of installing trust, which is all a text scan can prove. Renamed off `readme-` now that it covers three files. * Align proxy migration checks with current CLI --------- Co-authored-by: test <test@example.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: test <test@test.com> Co-authored-by: neutral <neutral@example.com> Co-authored-by: neutral <neutral@hyperparam.app> Co-authored-by: Phillip Cunliffe <filco@Macmini.localdomain>
What was wrong
Issue #923 collects three deferred findings from the review rounds on PR #902. Only one of them is a defect in
master, and this PR is that one: finding 3, the README's "Proxy mode" section.LLP 0262 moved Claude Code off proxy capture. With it went the last production caller of
installCaTrust: onmaster,installCaTrustis named nowhere outside its own module,src/core/tls/darwin_trust.js. Nothing HypAware runs installs the interception CA into a trust store any more.The README's proxy-mode bullet was outside that change's diff and still described the removed step in the present tense:
hyp detach <client>keeps the CA and the trust, so re-attaching does not ask again"Review round 1 on PR #902 corrected the same sentence in
docs/PRIVACY.mdand in thehyp detachhelp text, and noted the README still carried it.Root cause
The third claim is the one that costs the reader something, and it is the root of why this is worth a change rather than a copy-edit. It frames the keychain trust an older release left on the user's account as a convenience being held for them. It is the opposite: nothing re-creates that grant, so it is a leftover that only
hyp detach <client> --purgeorhyp daemon uninstallclears. A reader who believes the README leaves a user-domain trusted root on their macOS account indefinitely, on purpose.Fix
The bullet now says trust is file-scoped to the proxied client's own settings and that nothing installs it into a system trust store; puts the keychain grant in the past tense as something earlier releases did; and tells a reader who ran one of those that the trust setting is still on their account until they remove it. It follows the framing round 1 settled for
docs/PRIVACY.md.README.mdis the whole diff.docs/PRIVACY.mdandsrc/core/cli/core_commands.jscarry the same sentence and are corrected in PR #902, so they are deliberately untouched here and the two changes do not overlap.Regression test
test/core/readme-proxy-trust-claims.test.js, testthe README promises no CA trust step that no attach performs.It is a lint in the shape of
test/core/house-style-em-dash.test.js, and it is code-anchored rather than pure prose-grepping: it first asserts the fact (no production.jsoutsidesrc/core/tls/darwin_trust.jsnamesinstallCaTrust) and then asserts the claims the README may not make while that fact holds. If an attach path ever installs trust again, the first assertion fails and says so, which is the signal that the gate needs rewriting rather than the docs.Before, on
origin/master(1215492):After:
# pass 1 # fail 0.Full suite:
npm test4529 pass / 0 fail / 1 skipped.npm run typecheckclean.The other two findings, and why they are not here
Finding 1 (
hyp init --forcedropsproxy_mode) cannot be reproduced onmasterand is settled design. The scenario needs the claude picker row to have stopped declaringcompose.gateway_proxy_mode, which is PR #902's change and is not merged:hypaware-core/plugins-workspace/claude/hypaware.plugin.json:58still declares it here. The issue itself records this as accepted-by-design in review round 1, and the fold documents the behaviour as deliberate atsrc/core/cli/walkthrough.js:963-968under LLP 0243/0244, which are Accepted. The follow-up the issue floats, having the 0262 migration guarantee a re-attach alongside a forced re-init, is a design change to an accepted decision, so it wants a request LLP once PR #902 lands, not a patch onmasternow.Finding 2 is a PR body inaccuracy, not a repo artifact.
proxy_trust.proxy_mode_configuredis added by PR #902; the wording to correct lives in that PR's description, not in this tree.Fixes #923
opy outright
rather than keeping a stale one, so there is nothing to reproduce here and no
fix that could land ahead of #893. It is also architectural by the issue's own
description - closing it changes what a client-scoped run is - so per neutral's
escalate-don't-force rule it is not forced into this PR. It is carried forward
as the open question in LLP 0278 #open-questions so the record exists on
master, and it stays recorded on #893's branch at LLP 0266#open-kept-not-refreshed.
Fixes #921