Skip to content

Restore the wordpress-source section's purpose; close the wp-admin/wp-config/mu-plugins gaps - #321

Merged
chubes4 merged 2 commits into
mainfrom
fix/320-generic-managed-prose
Aug 3, 2026
Merged

Restore the wordpress-source section's purpose; close the wp-admin/wp-config/mu-plugins gaps#321
chubes4 merged 2 commits into
mainfrom
fix/320-generic-managed-prose

Conversation

@chubes4

@chubes4 chubes4 commented Aug 3, 2026

Copy link
Copy Markdown
Member

Closes #322. Supersedes #320 — that fixed false claims inside a shape that was itself wrong, so it is folded in here.

The section had lost its purpose

It exists so the agent is an expert on its own runtime by reading the WordPress installed underneath it. That is what lets a small free model be competent about WordPress with no skills and no fine-tuning. Direct Reference was the point; Read-Only was the qualifier.

The managed variant from #315 inverted it into an editable list, a read-only list, a justification, a production contract and a "not source" appendix — with "verify core APIs, hooks, conventions, and runtime behavior" surviving as one clause in the middle.

That restriction half was redundant. lib/source-policy.sh makes the runtime enforce it; prose enforces nothing. Restating the deny list bought no safety while crowding out the one thing prose is uniquely good at.

Both variants now lead with what the source is for. The managed section is about half its previous length.

Core was half-defined — in both directions

wp-admin/ and wp-includes/ are siblings, not nested. The root set was:

wp-content/plugins   wp-content/themes   wp-includes

As policy: every install ever created could edit wp-admin/** and every root PHP file — including wp-config.php, which holds the DB credentials, the salts, and the constants gating AGENTS.md composition. An agent able to rewrite it can switch off its own governance. Confirmed live on h44lacrosse.com.

As reference: the same omission pointed the agent away from list tables, get_plugins(), media handling and the upgrade routines — undercutting the section's actual purpose.

One definition of core fixes both.

wp-content/mu-plugins/ is denied too: it is agent governance, not a site extension — wp-coding-agents installs the mu-plugin that generates AGENTS.md there. wp-content/uploads/ stays open, because the agent's memory lives under it.

Declared exceptions, not a blanket deny

wp-config.php has legitimate uses (WP_DEBUG, memory limits), so --managed-writable re-opens a denied path.

It deliberately does not reuse --managed-source. That flag means editable and captured, which is what makes the "your work is recorded" promise true. wp-config.php is not captured by a component harvest. Conflating them would have AGENTS.md assert a safety property that does not hold — #318 again. Separate category, separate prose: "nothing captures them — a rebuild or migration will not carry the change."

The limitation that was backwards

We were strict about editing core (correct — an update overwrites it anyway) and accidentally strict about reading the one thing needed to recover from a fatal.

/var/log/nginx/ and /var/log/php8.5-fpm.log sit outside the site root. OpenCode gates those behind external_directory, which defaults to ask — and an autonomous Discord agent has nobody to ask. So the most important recovery capability in the whole design sat behind a prompt that could never be answered.

--log-path grants read via external_directory and explicitly denies edit, so logs are diagnostic input rather than something to rewrite.

Glob trap worth knowing

Root files are exact literals, never globs. OpenCode's matcher turns * into .*, which spans slashes, so wp-*.php would also match wp-content/plugins/acme/wp-thing.php and over-deny inside a site's own component. source_policy_edit_rules now emits a dir/file kind so each runtime formats correctly.

Tests

tests/posture.sh (79 assertions) pins:

tests/opencode-local-plugin-path.sh and tests/repair-opencode-json.sh had frozen copies of the old three-rule map; they now assert the properties that matter and leave the canonical list to posture.sh.

Full suite: no new failures (same 7 pre-existing environment failures as main, none in shell.yml). bash -n clean.

Follow-up

h44lacrosse.com needs a re-run after release, with --managed-writable/--log-path decided by the operator. Not part of this PR.

chubes4 added 2 commits August 3, 2026 12:37
The managed wordpress-source section is generated into the AGENTS.md of every
managed install, but it described h44lacrosse.com's stack as if it were
universal:

- "including commerce and payment code" and "the site's ability to take money"
  — there may be no store and no gateway
- "the runtime that gives you memory and tools" — that is Data Machine, this
  install's happenstance, not a property of wp-content/plugins
- a specific never-captured list (vendor, node_modules, composer.lock,
  package-lock.json, package.json) — one operator's harvest excludes copied
  verbatim, from a config this tool does not own and cannot read
- "exactly what the operator's capture records" — the intended invariant of the
  posture, which the tool has no way to verify

This is the #314/#318 failure in a third form. Those were prose claiming things
the enforced policy could not back; this is prose claiming things about the
environment that the tool never inspected. An agent told that editing a plugin
breaks the site's ability to take money, on a site with no commerce plugin, has
been handed a false model of its own install by the file that is supposed to be
its most reliable source of truth. Presenting a guessed exclude list is worse
than silence, because the agent will trust it.

Now describes the category and the reason and leaves the specifics to the
operator: plugins this site did not author, including whatever this agent
depends on; an update overwrites the change and nothing captures it, both true
regardless of what any plugin does; installed and generated files are not
authored source, so ask the operator which paths this site actually captures
rather than assume.

tests/posture.sh gains a guard asserting the rendered prose names none of
WooCommerce, Stripe, commerce, payment, money, composer.lock, package-lock,
node_modules, Data Machine, homeboy, harvest.yml, or wp-admin. Verified
non-vacuous: reintroducing a single product name fails the suite.

The two rules this file must follow are now recorded at the top of it.
…e gaps

Closes #322. Supersedes #320, which fixed false claims inside a shape that was
itself wrong.

PURPOSE. The section exists so the agent is an expert on its own runtime by
reading the WordPress installed underneath it — that is what lets a small model
be competent about WordPress with no skills and no fine-tuning. Direct
Reference was the point; Read-Only was a qualifier. The managed variant added
in #315 inverted that into an editable list, a read-only list, a justification,
a production contract, and a "not source" appendix, with the reference clause
buried in the middle.

The restriction half was also redundant. lib/source-policy.sh makes the runtime
enforce it; prose enforces nothing. Restating the deny list bought no safety
while crowding out the one thing prose is uniquely good at. Both variants now
lead with what the source is FOR and name the boundary only so the agent is not
misinformed about it. The managed section is roughly half its previous length.

CORE WAS HALF-DEFINED. wp-admin and wp-includes are siblings, not nested. The
root set was wp-content/plugins, wp-content/themes, wp-includes — so on every
install ever created the agent could edit wp-admin and every root PHP file,
including wp-config.php, which holds the database credentials and the constants
that gate AGENTS.md composition. As reference the same omission pointed the
agent away from list tables, media, and the upgrade routines. Both halves fixed
by defining core once.

wp-content/mu-plugins is now denied too. It is agent governance, not a site
extension: wp-coding-agents installs the mu-plugin that GENERATES AGENTS.md
there. wp-content/uploads stays open because the agent's memory lives under it.

DECLARED EXCEPTIONS. wp-config.php has real uses (WP_DEBUG, memory limits), so
--managed-writable re-opens a denied path. It cannot reuse --managed-source:
that flag means editable AND captured, which is what makes the "your work is
recorded" promise true, and wp-config.php is not captured by a component
harvest. Conflating them would assert a safety property that does not hold —
the #318 failure. Separate category, separate prose.

LOGS. The limitation was backwards. We were strict about editing core (correct;
an update overwrites it anyway) and accidentally strict about READING the one
thing needed to recover from a fatal. OpenCode gates paths outside the site
root behind external_directory, which defaults to ask, and an autonomous agent
has nobody to ask — so the most important recovery capability in the design sat
behind an unanswerable prompt. --log-path grants read and explicitly denies
edit.

GLOB TRAP. Root files are exact literals, not globs. OpenCode's matcher turns *
into .* which spans slashes, so wp-*.php would also match
wp-content/plugins/acme/wp-thing.php and over-deny inside a site's own
component. source_policy_edit_rules now emits a dir/file kind so each runtime
can format correctly.

tests/posture.sh pins the purpose (reference framing present in both variants),
the enumerate-never-generalise rule, the writable-is-not-captured distinction,
log paths readable but not writable, uploads untouched, ordering, and the #320
guard against naming one install's stack.
@chubes4 chubes4 changed the title Stop asserting one install's stack in managed guidance Restore the wordpress-source section's purpose; close the wp-admin/wp-config/mu-plugins gaps Aug 3, 2026
@chubes4
chubes4 merged commit 7a3bb85 into main Aug 3, 2026
18 checks passed
@chubes4
chubes4 deleted the fix/320-generic-managed-prose branch August 3, 2026 13:04
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.

wordpress-source section lost its purpose, and wp-admin/wp-config.php are neither referenced nor denied

1 participant