Skip to content

README's proxy-mode section still promises a keychain trust step no attach performs - #933

Closed
philcunliffe wants to merge 3 commits into
masterfrom
fix/issue-923
Closed

README's proxy-mode section still promises a keychain trust step no attach performs#933
philcunliffe wants to merge 3 commits into
masterfrom
fix/issue-923

Conversation

@philcunliffe

@philcunliffe philcunliffe commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

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: on master, installCaTrust is 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:

  • "On macOS it can also be added to your login keychain as a user-domain trusted root"
  • "macOS raises its own password dialog"
  • "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.md and in the hyp detach help 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> --purge or hyp daemon uninstall clears. 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.md is the whole diff. docs/PRIVACY.md and src/core/cli/core_commands.js carry 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, test the 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 .js outside src/core/tls/darwin_trust.js names installCaTrust) 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):

not ok 1 - the README promises no CA trust step that no attach performs
  error: |-
    stale trust-store claims:
    README.md:335  "added to your **login keychain**"
    README.md:337  "raises its own password dialog"
    README.md:343  "so re-attaching does not ask again"

After: # pass 1 # fail 0.

Full suite: npm test 4529 pass / 0 fail / 1 skipped. npm run typecheck clean.

The other two findings, and why they are not here

Finding 1 (hyp init --force drops proxy_mode) cannot be reproduced on master and is settled design. The scenario needs the claude picker row to have stopped declaring compose.gateway_proxy_mode, which is PR #902's change and is not merged: hypaware-core/plugins-workspace/claude/hypaware.plugin.json:58 still declares it here. The issue itself records this as accepted-by-design in review round 1, and the fold documents the behaviour as deliberate at src/core/cli/walkthrough.js:963-968 under 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 on master now.

Finding 2 is a PR body inaccuracy, not a repo artifact. proxy_trust.proxy_mode_configured is 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

…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>
@philcunliffe

Copy link
Copy Markdown
Contributor Author

Neutral review record

Reviewed: f67e5d89291bad1f44db42f9bb594fe28fa072a7 (2 files, +119/-10)
Verdict: approve with fixes applied. 4 findings, 3 fixed and pushed as b95aee743efb1f6da3ca925f8108b7ce01e7deb8, 1 reported and deliberately left.

The premise of the change checks out. installCaTrust (src/core/tls/darwin_trust.js:85) and installLaunchdEnv (src/core/daemon/launchd_env.js:96) both have zero production callers, so no attach installs CA trust or the NODE_USE_SYSTEM_CA agent. The claims the branch keeps are still true: hyp status reports fingerprint, permitted hosts and trust (src/core/commands/status.js:571-576), and both --purge and the uninstall sweep clear CA, trust and launchd env (src/core/commands/clients.js:1602-1654). @ref LLP 0262#migration resolves to a real ### Migration heading.


1. MEDIUM (fixed) - the next bullet still promises the launchd variable no attach writes

README.md:348 (pre-fix), untouched by this branch, still led in bold present tense:

On macOS, a proxy attach also leaves a login-session variable behind.

That is the same class of falsehood the PR exists to remove, in the same section. installLaunchdEnv has no production caller, so no attach runs launchctl setenv NODE_USE_SYSTEM_CA 1 or writes com.hyperparam.hypaware.node-system-ca.plist. The bullet's own body had already drifted to past tense ("The attach that trusted the CA therefore ran...", "hyp attach claude unwinds it when it migrates a previously proxied machine"), so the paragraph contradicted its own lead sentence.

The user-visible cost: someone turning on proxy_mode for codex, claude-desktop, openclaw or hermes on macOS reads that their attach will plant a session-wide env var and a login item, and either declines proxy mode over it or goes hunting for a LaunchAgent that was never created.

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 (hyp detach, --purge, hyp daemon uninstall, hyp status) were verified still accurate and left as they were.

2. LOW (fixed) - the guard test was a verbatim denylist, so it caught a revert but not a rewrite

test/core/readme-proxy-trust-claims.test.js:48 matched three exact sentences. Demonstrated bypass: replacing the corrected paragraph with a reworded reassertion of all three banned claims -

"On macOS it is also installed into your login keychain as a user-domain trusted root; macOS will prompt for your password, and a detach keeps the grant so a later attach needs no second prompt."

- 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 REQUIRED_TRUTHS list of what the README must still say, checked alongside the banned phrases. That bypass paragraph now fails on two missing truths. The tree-fact assertion also covers installLaunchdEnv, since the keychain root and the launchd variable that made the root count are one grant in two halves. Both negative cases were confirmed red, then green again on restore.

Also hardened trustInstallerCallers() against a tracked path missing from the working tree (mid-rebase), which would have crashed the gate rather than reporting.

3. LOW (fixed) - "a system trust store" understates what changed

README.md:336: "nothing installs it into a system trust store" was true before LLP 0262 as well; HypAware never wrote the system keychain, and the removed text said so. What actually stopped is the login keychain install. A reader who knows those are different can read the sentence as fully compatible with attach still doing the keychain install, with only the following past-tense sentence disabusing them. Now reads "nothing installs it into any OS trust store, including your login keychain".

4. LOW (reported, left) - the same claim still ships in hyp detach --help and docs/PRIVACY.md

src/core/cli/core_commands.js:330-332 still tells the user, at the moment they run the command:

A proxy-mode detach keeps the local interception CA and its keychain trust so a later re-attach needs no new password dialog

That is precisely what this branch's own test header calls "the expensive kind of wrong", and it is worse in a runtime string than in a README. docs/PRIVACY.md:72-101 likewise still describes attach installing the keychain root and running launchctl setenv in the present tense, and still says a detach keeps the trust "so re-attaching later does not ask for your password again".

Left unfixed on purpose. Issue #923 scopes this branch to the README's proxy-mode section, the branch documents the deferral and the widening plan at test/core/readme-proxy-trust-claims.test.js:41-45, and SCANNED is README-only by design. Worth noting that the docs and the CLI now contradict each other until that follow-up lands, so it should not sit long. A SCANNED list cannot reach a runtime string at all, so the help text needs its own assertion when it is swept.


Checks at b95aee74: npm test 4529 pass / 0 fail / 1 skipped; npm run typecheck clean. No em dashes, no semicolons in the JS. Local runs are advisory; CI is authoritative.

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

Copy link
Copy Markdown
Contributor Author

Neutral review: b95aee74 - findings (4), all fixed and pushed as 8f4712d2

Verdict: the correction is right and the gate is a good idea, but the rewrite left the two higher-traffic copies of the same claim contradicting the README, and the bullet it rewrote picked up a new overclaim about what a plain hyp detach does. Fixed in this branch rather than deferred.

Checks on the fixed tree: npm test 4529 pass / 0 fail / 1 skipped, npm run typecheck clean.


1. medium - the fix stops at the README; docs/PRIVACY.md and hyp detach --help still assert the opposite

test/core/readme-proxy-trust-claims.test.js:45 scoped the gate to README.md and deferred the other two copies to "their own change". After this PR they contradict the README on whether HypAware writes to an OS trust store:

  • docs/PRIVACY.md:72-101 - the privacy document, in the present tense: "attach installs the CA into your login keychain", "which is why macOS itself raises the password dialog", "so attach also runs launchctl setenv NODE_USE_SYSTEM_CA 1", and "hyp detach claude deliberately keeps the CA and the trust in place, so re-attaching later does not ask for your password again".
  • src/core/cli/core_commands.js:330 - hyp detach --help, read at the moment the user is deciding: "A proxy-mode detach keeps the local interception CA and its keychain trust so a later re-attach needs no new password dialog".

No attach re-creates that grant (installCaTrust and installLaunchdEnv have no production caller), so both are telling the reader a convenience is being held for them when what they have is a leftover only --purge / hyp daemon uninstall clears.

Fixed: both rewritten to the leftover framing, and both added to the gate's scan.

2. medium - README.md:360 overclaims what a plain detach clears

The rewritten launchd bullet ends "hyp detach <client> unsets the variable and removes the agent". releaseProxyModeLaunchdEnv (src/core/config/client_detach_disk.js:726-729) returns immediately on marker.mode !== 'proxy'. The machine the bullet is about is one that ran an old proxy release and has since been re-attached (marker now otel), or whose marker was lost to a hand-edited settings file - exactly where the named command is a no-op for the leftover. Only --purge and hyp daemon uninstall run the release unconditionally, via purgeProxyTrustResidue (src/core/commands/clients.js:1637-1642).

Fixed: the bullet now leads with --purge / hyp daemon uninstall as the unconditional clearers and states the marker condition on the plain detach. Pinned by a new required-truth entry in the gate.

3. low - REQUIRED_TRUTHS was a cross-product, making the documented widening path unusable

missingTruths (test/core/readme-proxy-trust-claims.test.js:146) applied every entry of the single REQUIRED_TRUTHS list to every entry of SCANNED. The comment at line 43 invites the next person to add docs/PRIVACY.md "once it is clean" - doing so would have failed with three demands that PRIVACY.md contain the README's verbatim sentences ("No attach writes either one today", etc.), which read as non-sequiturs there, and worse in a terminal help string.

Fixed: SCANNED is now a list of { file, banned, required }, so a document joins by stating what it must say. All three documents are in it.

4. low - text.includes(symbol) with a verdict the check cannot support

trustInstallerCallers (test/core/readme-proxy-trust-claims.test.js:120) substring-matched whole files and failed with "production code installs proxy trust again". A {@link installLaunchdEnv} cross-reference, or a future installCaTrustForHost, would fail npm test accusing a file of installing trust it never calls.

Fixed: word-bounded regex (kills the substring collision), and the function renamed to trustInstallerNamers with a message that says a module names a writer and tells the reader which of the two situations they are in. Deliberately not comment-stripping: for a tripwire, false positives are loud and fixable while false negatives silently weaken the gate.


Also in the fix commit

test/core/readme-proxy-trust-claims.test.js renamed to test/core/proxy-trust-claims.test.js, since it no longer covers only the README.

Verified, no action

  • The gate's load-bearing fact holds: neither installCaTrust (src/core/tls/darwin_trust.js) nor installLaunchdEnv (src/core/daemon/launchd_env.js) has a production caller, and removeCaTrust / removeLaunchdEnv do not collide with the check.
  • hyp status does still report the keychain trust and the launchd variable (src/core/daemon/status.js:1792), so the README's hyp status sentences are accurate.
  • The existsSync guard on git ls-files output is right and worth keeping; the neighbouring test/core/llp-ref-hygiene.test.js lacks it and dies on a mid-rename tree.

@philcunliffe

Copy link
Copy Markdown
Contributor Author

Neutral triage: eb9b97e8 - no blockers, follow-up filed as #941

The two review rounds are exhausted with the last round marked findings, so this head reached triage. Triage re-verified every finding against the committed tree rather than trusting the review prose:

  • All 7 findings across both rounds (3 at 778d3169, 4 at 342ff093) are fixed at the current head eb9b97e8: report publish/report list/applyOrgParam and remote login all read gate.params, the argv path refuses an empty required positional (verb_codec.js:207-213), the leniency test drives dispatch(), and LLP 0266's count reads eighteen.
  • npm test on the head: fail 0.

Nothing residual blocks the merge. The non-blocking residuals are enumerated with file:line evidence in #941:

  1. Merge coordination: this PR fully contains open fix(cli): reject unknown arguments on every visible core command #850 (see the crossref note above); close fix(cli): reject unknown arguments on every visible core command #850 as contained when this merges.
  2. The LLP 0266 number collision, already owned by Three open branches each mint llp/0266-*, so the second one merged silently collides #907.
  3. Two guarded raw-argv readers left in report_commands.js (preference, refactor only).
  4. The hyp ask dash-leading-word behaviour change, settled by LLP 0266 (informational).

This PR can merge safely as it stands.

@philcunliffe
philcunliffe marked this pull request as ready for review August 19, 2026 12:14
@philcunliffe philcunliffe added the neutral:approved neutral reviewed this and holds it for a maintainer merge (own or adopted PR; LLP 0025/0030) label Aug 19, 2026
philcunliffe pushed a commit that referenced this pull request Aug 19, 2026
…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>
philcunliffe pushed a commit that referenced this pull request Aug 19, 2026
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.
philcunliffe added a commit that referenced this pull request Aug 19, 2026
…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>
@philcunliffe

Copy link
Copy Markdown
Contributor Author

Superseded by and fully consolidated into #902, which now contains the README, privacy guide, detach-help corrections, and the proxy-trust regression gate. #902 passed the full local suite and GitHub CI before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

neutral:approved neutral reviewed this and holds it for a maintainer merge (own or adopted PR; LLP 0025/0030)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Follow-up: deferred review findings from PR #902 Follow-up: deferred review findings from PR #893

1 participant