feat: derive the owned source set from site state - #340
Merged
Conversation
Declaring what a site owns was an operator action: --owned-source per
component, over SSH, repeated in the capture configuration. A non-technical
owner asking for a new plugin therefore had to file a support ticket, which
is the thing managed hosting exists to remove.
Ownership is not a judgement call. It is a fact already on the box:
owned = installed − known to wp.org − installed by wp-coding-agents
− explicitly excluded
Measured against h44lacrosse.com, that produces exactly the three
components previously declared by hand, plus one vendor plugin the
exclusion list covers. A plugin the agent creates is now editable and
captured with no operator step and no agent self-declaration.
THE FAILURE MODE THIS IS BUILT AROUND
The wp.org signal is a transient. On a fresh install, after a cache flush,
or when wp.org is unreachable it is absent — and if absence were read as
"no plugin is known to wp.org", every plugin would classify as the site's.
On h44lacrosse.com that hands a coding agent write access to WooCommerce
and a Stripe payment gateway, produced by automation whose entire purpose
is to be safer than an operator doing it by hand.
So ownership is inferred only from the PRESENCE of evidence. A missing,
empty, or stale signal produces no derivation and the caller keeps the last
recorded set. Verified against the live site: forcing the freshness gate to
zero makes it refuse with empty output rather than derive.
The Update URI header (WP 5.8+) would have generalised this past wp.org to
premium and vendor plugins, and is unusable: measured across every plugin
on that box, including WooCommerce, the Stripe gateway and Akismet, not one
sets it. Hence --not-owned, which is also what keeps licensed vendor code
out of the operator's repository.
Precedence is explicit flags > derived > recorded. Derivation must beat the
recorded set or a newly created plugin would never become editable and this
would change nothing; it must lose to explicit flags, which are the
operator deciding deliberately.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the declaration half of #336, without making declaration an action.
The idea
Declaring what a site owns was an operator action —
--owned-sourceper component, over SSH, repeated in the capture config. A non-technical owner asking for a new plugin had to file a support ticket, which is the thing managed hosting exists to remove.But ownership isn't a judgement call. It's a fact already on the box:
Verified against h44lacrosse.com's live state:
Exactly the hand-declared set, plus one vendor plugin. With
--not-owned data-machine-businessthe two are identical.The failure mode this is built around
The wp.org signal is a transient. Fresh install, cache flush, wp.org unreachable — it's absent. Read absence as "nothing belongs to wp.org" and every plugin classifies as the site's, handing the agent write access to WooCommerce and a Stripe payment gateway. Automation whose whole purpose is to be safer than a human would be the thing that opened the payment plugin.
So ownership is inferred only from the presence of evidence. Missing, empty, or stale (>2d) produces no derivation and the caller keeps the last recorded set.
Verified live by forcing the freshness gate to zero:
Why not
Update URIWP 5.8+ defines exactly the right header — a plugin declaring an external update source is by definition not the site's, and it would generalise past wp.org to premium plugins. It's unusable: measured across every plugin on that box, including WooCommerce, the Stripe gateway and Akismet, not one sets it.
Hence
--not-owned <slug>, which also keeps licensed vendor code out of the operator's repository.Precedence
explicit flags > derived > recorded. Derivation must beat the recorded set or a newly created plugin never becomes editable and this changes nothing; it must lose to explicit flags, which are the operator deciding deliberately. Pinned by a test that strips comments before checking call order — my comments name the functions in a different order than the code calls them.Coverage
tests/owned-source-discovery.sh, wired into CI. Every "missing evidence" case asserted separately, plus the catastrophe asserted directly rather than implied: a missing signal cannot open WooCommerce.One test bug worth noting: my first version used substring matching and couldn't distinguish
plugins/data-machinefromplugins/data-machine-business— the exact pair this file exists to tell apart. Slug assertions are now exact-line.