Skip to content

Fix a published install command that fails (retired desktop console) - #99

Merged
wshallwshall merged 1 commit into
mainfrom
claude/stale-desktop-console-refs
Aug 1, 2026
Merged

Fix a published install command that fails (retired desktop console)#99
wshallwshall merged 1 commit into
mainfrom
claude/stale-desktop-console-refs

Conversation

@wshallwshall

Copy link
Copy Markdown
Owner

The site publishes a command that fails

getting-started.html told readers to run:

pip install "messagefoundry[console]"
python -m messagefoundry.console --url http://127.0.0.1:8765

Neither exists. The engine's pyproject.toml declares no console extra (only harness), and
messagefoundry/console/ was deleted when BACKLOG #103 retired the desktop admin console in
favour of the browser console (shipped 2026-07-13). A reader following the quickstart gets a pip
error in their terminal.

Four places, one root cause

File Was Now
getting-started.html:205-206 broken pip install + python -m messagefoundry.console pip install messagefoundry-webconsole, browse to /ui
getting-started.html:51 HowTo JSON-LD: "Install the console extra and attach the desktop admin console" browser console at /ui
tools.html:208 python -m messagefoundry.console open http://127.0.0.1:8765/ui
overview.html:123,130 "A desktop console…" + "Read-only by design" browser console; "Never touches the database"

The JSON-LD one matters beyond the visible page — the stale claim was being served to search and
answer engines as structured data.

overview.html:130 was also internally contradictory: "Read-only by design" sat directly
beneath "One-click replay", and the console now has a config write path
(POST /ui/connections/{name}/flag). What is actually true is that it never touches the database —
which is how console.html:176 already phrases it, so this aligns the two.

console.html already documented the browser console correctly, with a real screenshot. The site
was disagreeing with itself.

Wording

Taken from the canonical in-repo instruction at assets/docs/_md/Install-Guide.md:255 rather than
invented: install messagefoundry-webconsole alongside the engine, restart, browse to /ui; it is
on by default. Left unpinned to match how every other install command on the site is written
(the site publishes no version numbers — see PR #65).

Deliberately not mentioned: the [api].serve_ui config key. ADR 0118 relocated it to
[security].serve_web_console, and the old spelling is now rejected at config load.

Verification

Served locally and checked in the browser:

  • All three pages render; no console errors.
  • JSON-LD still parses on every edited page (2 blocks on getting-started, 1 each on the others).
  • Post-change sweep: no messagefoundry[console], no messagefoundry.console, and no "desktop"
    reference anywhere in the site's HTML except comparison.html, where it correctly describes
    competitors' version-locked desktop clients.

Known, deliberately not fixed here

tools.html also advertises python -m harness. The harness/ package is a top-level sibling of
messagefoundry/
, and both wheel and sdist are package-only
([tool.hatch.build.targets.sdist] only-include = ["messagefoundry", …]), so python -m harness
also fails for a PyPI user — messagefoundry[harness] installs PySide6 but not the harness itself.

That one is left alone on purpose: the correct fix may be to ship the package from the engine rather
than to change the website copy, and that is an engine packaging decision. Flagged, not guessed at.

🤖 Generated with Claude Code

…onsole framing

getting-started.html told readers to run:

    pip install "messagefoundry[console]"
    python -m messagefoundry.console --url http://127.0.0.1:8765

Neither exists. The engine declares no `console` extra (pyproject.toml has only
`harness`), and `messagefoundry/console/` was deleted when BACKLOG #103 retired
the desktop admin console in favour of the browser console. A reader following
the quickstart hits a pip error.

The same retired desktop framing appeared in three more places:

- getting-started.html HowTo JSON-LD — "Install the console extra and attach the
  desktop admin console", i.e. the stale claim was also being served to search
  and answer engines as structured data.
- tools.html — `python -m messagefoundry.console` as the console's command.
- overview.html — "A desktop console…", plus a "Read-only by design" bullet
  sitting directly beneath "One-click replay", which contradicted it. The console
  has a config write path now; what is actually true is that it never touches the
  database, which is how console.html already describes it.

console.html already documented the browser console correctly, so the site
disagreed with itself.

Replacement wording follows the canonical instruction in
assets/docs/_md/Install-Guide.md:255 — install `messagefoundry-webconsole`
alongside the engine and browse to /ui, on by default. Left unpinned to match how
every other install command on the site is written.

Verified in the browser: all three pages render, no console errors, JSON-LD still
parses, and no `messagefoundry[console]` / `messagefoundry.console` / "desktop"
reference survives outside comparison.html (where it describes competitors).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
wshallwshall added a commit that referenced this pull request Jul 31, 2026
…ound

The agent audit's precision held but its recall did not. A deterministic sweep —
extract every [section].key reference in all 20 published sources, validate each
against the engine's live pydantic models — found four more of the same class
that the audit missed entirely.

docs/secure-development-standards.md (3 relocated keys, ADR 0118):
  :331  [api].serve_ui      -> the console is on by default; [security].serve_web_console
  :378  [auth].require_mfa  -> [security].require_mfa
  :449  [auth].require_mfa  -> [security].require_mfa

assets/docs/_md/Configuration.md (1 silently-ignored key):
  :1252 [inbound].source_ip_allowlist — [inbound] has exactly three fields
        (ack_after, bind_host, stream_inflight_budget_bytes). source_ip_allowlist
        is a per-connection attribute in connections.toml. Because sections are
        extra="ignore", putting it under [inbound] is silently accepted and
        ignored — an operator believes MLLP peers are restricted when they are
        not, which is the security-relevant version of the [delivery] buildup bug.

Also corrected in the same file, same defect class as #98/#99 (retired desktop
console): the A.1 technology stack still listed "PySide6 (desktop UI)", and the
A.2 surfaces bullet described a "PySide6 desktop client, plus an opt-in
read-only web ops dashboard ... off by default" — wrong on four counts (the
desktop client was deleted, the console is on by default at a loopback bind, and
it carries write actions, not read-only).

DELIBERATELY NOT TOUCHED, pending the owner's ASVS ruling:
  :339  the V3 "Web Frontend Security" exclusion row
  :355  the chapter roll-up that moves with it
Verified still present in the rendered PDF.

Sweep now reports zero real defects across all 20 sources. The 19 remaining hits
are verified false positives: Configuration.md's own documented moved-keys list,
`forward_*` / `allowed_*` wildcards written in prose, the deliberate
accepted-but-ignored key list at :19, and regex artifacts (`pip install -e`,
`python -m sigstore`).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
wshallwshall added a commit that referenced this pull request Aug 1, 2026
…ound

The agent audit's precision held but its recall did not. A deterministic sweep —
extract every [section].key reference in all 20 published sources, validate each
against the engine's live pydantic models — found four more of the same class
that the audit missed entirely.

docs/secure-development-standards.md (3 relocated keys, ADR 0118):
  :331  [api].serve_ui      -> the console is on by default; [security].serve_web_console
  :378  [auth].require_mfa  -> [security].require_mfa
  :449  [auth].require_mfa  -> [security].require_mfa

assets/docs/_md/Configuration.md (1 silently-ignored key):
  :1252 [inbound].source_ip_allowlist — [inbound] has exactly three fields
        (ack_after, bind_host, stream_inflight_budget_bytes). source_ip_allowlist
        is a per-connection attribute in connections.toml. Because sections are
        extra="ignore", putting it under [inbound] is silently accepted and
        ignored — an operator believes MLLP peers are restricted when they are
        not, which is the security-relevant version of the [delivery] buildup bug.

Also corrected in the same file, same defect class as #98/#99 (retired desktop
console): the A.1 technology stack still listed "PySide6 (desktop UI)", and the
A.2 surfaces bullet described a "PySide6 desktop client, plus an opt-in
read-only web ops dashboard ... off by default" — wrong on four counts (the
desktop client was deleted, the console is on by default at a loopback bind, and
it carries write actions, not read-only).

DELIBERATELY NOT TOUCHED, pending the owner's ASVS ruling:
  :339  the V3 "Web Frontend Security" exclusion row
  :355  the chapter roll-up that moves with it
Verified still present in the rendered PDF.

Sweep now reports zero real defects across all 20 sources. The 19 remaining hits
are verified false positives: Configuration.md's own documented moved-keys list,
`forward_*` / `allowed_*` wildcards written in prose, the deliberate
accepted-but-ignored key list at :19, and regex artifacts (`pip install -e`,
`python -m sigstore`).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
wshallwshall added a commit that referenced this pull request Aug 1, 2026
)

* Docs: fix 23 instructions that produce an engine which won't start

An adversarially-verified audit of all 20 published documents found 61 defects.
These are the 23 that break on use — config a reader copies out of the docs that
the engine now refuses, and commands that error in their terminal.

The dominant cause is ADR 0118, which relocated the posture switches into
[security] and made every old spelling a hard ValueError at config load
(_reject_relocated_keys, settings.py:3863). A document still teaching
[api].serve_ui, [auth].require_mfa, [api].host or [ai].data_class does not
merely mislead — following it yields an instance that will not boot.

Corrected, with the engine as the source of truth:

- Relocated keys, 11 sites across 7 files → their [security] homes. Note
  [ai].data_class was a "synthetic"|"phi" string; its replacement
  [security].handles_real_patient_data is a boolean, so this is not a rename.
- Refuse-vs-warn, 4 sites in Configuration.md. The split is
  [security].enforcement, NOT the deployment tier: `enforce` is the shipped
  default on dev and staging as much as prod, and all three built-in env names
  derive PHI. Docs promising a warning on staging were promising exit 2.
- Remote-Console-Customer-Guide's central recipe. Swapping [api].host alone
  produces a *different* dead engine: an off-loopback in-process-TLS bind is
  refused until MEFOR_TLS_REVOCATION_ATTESTED=1, which is an environment
  variable with no TOML equivalent. Adopted the engine's full recipe.
- `--allow-insecure-bind` is clamped inert on the shipped posture; it was
  offered as the escape from a refusal it cannot lift.
- install-service.ps1 needs -Environment (it throws without it), and already
  defaults to a per-service virtual account — the guide had LocalSystem as the
  default and the virtual account as the opt-in, which is backwards.
- `python -m harness` needs the separate messagefoundry-harness distribution;
  messagefoundry[harness] installs PySide6 but not harness/, which is
  deliberately not in the engine wheel.
- [delivery] buildup keys are buildup_max_*; the unprefixed names are the
  per-outbound object's fields, and since sections are extra="ignore" they were
  silently discarded — the operator believed a threshold was set.
- Store encryption refuses on ANY PHI instance, not just production.
- OIDC oidc_require_mfa_claim=false now fails closed (0.3.1 breaking change);
  it no longer degrades to the AD posture.
- Architecture's "Roadmap (not yet enforced)" listed three shipped controls.

Verification, against the live engine models rather than by reading:
  - all 19 introduced keys exist as real fields; every documented default
    matches (require_mfa=True, require_mfa_scope=every_local_account,
    serve_web_console=True, buildup_max_oldest_seconds=300.0)
  - every old spelling the docs taught is rejected by _reject_relocated_keys
  - the new config validates through SecuritySettings/DeliverySettings intact
  - no live instruction to use a relocated key survives; the lines that remain
    document the rejection, which is correct and deliberate
  - 9 PDFs re-rendered, all carrying v0.3.2 / July 2026, zero mojibake

The other 38 findings are reported, not applied.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Docs: close the recall gap — 4 more dead keys a deterministic sweep found

The agent audit's precision held but its recall did not. A deterministic sweep —
extract every [section].key reference in all 20 published sources, validate each
against the engine's live pydantic models — found four more of the same class
that the audit missed entirely.

docs/secure-development-standards.md (3 relocated keys, ADR 0118):
  :331  [api].serve_ui      -> the console is on by default; [security].serve_web_console
  :378  [auth].require_mfa  -> [security].require_mfa
  :449  [auth].require_mfa  -> [security].require_mfa

assets/docs/_md/Configuration.md (1 silently-ignored key):
  :1252 [inbound].source_ip_allowlist — [inbound] has exactly three fields
        (ack_after, bind_host, stream_inflight_budget_bytes). source_ip_allowlist
        is a per-connection attribute in connections.toml. Because sections are
        extra="ignore", putting it under [inbound] is silently accepted and
        ignored — an operator believes MLLP peers are restricted when they are
        not, which is the security-relevant version of the [delivery] buildup bug.

Also corrected in the same file, same defect class as #98/#99 (retired desktop
console): the A.1 technology stack still listed "PySide6 (desktop UI)", and the
A.2 surfaces bullet described a "PySide6 desktop client, plus an opt-in
read-only web ops dashboard ... off by default" — wrong on four counts (the
desktop client was deleted, the console is on by default at a loopback bind, and
it carries write actions, not read-only).

DELIBERATELY NOT TOUCHED, pending the owner's ASVS ruling:
  :339  the V3 "Web Frontend Security" exclusion row
  :355  the chapter roll-up that moves with it
Verified still present in the rendered PDF.

Sweep now reports zero real defects across all 20 sources. The 19 remaining hits
are verified false positives: Configuration.md's own documented moved-keys list,
`forward_*` / `allowed_*` wildcards written in prose, the deliberate
accepted-but-ignored key list at :19, and regex artifacts (`pip install -e`,
`python -m sigstore`).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@wshallwshall
wshallwshall merged commit 819d7db into main Aug 1, 2026
@wshallwshall
wshallwshall deleted the claude/stale-desktop-console-refs branch August 1, 2026 03:19
wshallwshall added a commit that referenced this pull request Aug 1, 2026
)

The toolkit page lists six tools under "What's in the box", each with a
command and no indication of where it comes from. Two of them do not come
from the engine wheel, and the page's framing implies they do.

- **Test harness** (`python -m harness`) ships as its own distribution,
  `messagefoundry-harness`, released in lockstep with the engine. The engine
  wheel is `only-include = ["messagefoundry", ...]`, so `harness/` is not in
  it; the harness distribution force-includes it. The card now says so. This
  is the item deferred in #99, where the fix might have been engine packaging
  rather than site copy — it wasn't; the packaging is deliberate.

- **Tee relay** (`python -m tee`) is worse and was not previously flagged:
  `tee/` is a repo-root directory, is not inside `messagefoundry/`, is not
  force-included by ANY distribution, and has no entry point. There is no
  `packaging/messagefoundry-tee`. So it is reachable only from a source
  checkout — no published package provides it. The card now says that too.

Neither command was wrong; both worked once you had the right thing installed.
The defect was that the page never told you what that was, while presenting
them alongside tools that do ship with `pip install messagefoundry`.

Verified against the engine: `pyproject.toml:21` (wheel contents),
`packaging/` (only messagefoundry-harness and messagefoundry-webconsole),
`[project.scripts]` / `[project.gui-scripts]` (no tee entry point). The doc
sources already state the harness packaging correctly after #100/#101, so this
brings the HTML into line with the PDFs rather than inventing a new claim.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant