Skip to content

fix: reconcile the manifest and migrate the sibling option keys - #339

Merged
chubes4 merged 1 commit into
mainfrom
manifest-reconcile
Aug 5, 2026
Merged

fix: reconcile the manifest and migrate the sibling option keys#339
chubes4 merged 1 commit into
mainfrom
manifest-reconcile

Conversation

@chubes4

@chubes4 chubes4 commented Aug 5, 2026

Copy link
Copy Markdown
Member

Found by verifying the v1.13.0 upgrade on h44lacrosse.com rather than trusting it.

What the live check showed

wp_coding_agents_source_mode      owned          <- migrated
wp_coding_agents_owned_sources    (empty)        <- NOT migrated
/var/lib/wp-coding-agents/.../owned-sources      <- NOT WRITTEN

The manifest was the entire point of the release, and it did not appear.

Cause

source_policy_record_owned_sources compared through the legacy-aware reader, which on a pre-rename install returns exactly the paths about to be written. So it returned early, never wrote the new key, and never reached the manifest call sitting after it.

This is the same defect source_policy_record_mode already carries a comment about:

Compare against the NEW key only. Comparing through the legacy-aware reader would see a pre-rename install as already correct […] and leave it recorded under the old key forever, so the migration would never actually happen.

I wrote that, fixed it in one place, and didn't apply it to the siblings. record_writable_paths and record_log_paths had it too.

The manifest now reconciles before any no-change return. It's a projection of the declaration, not a record of a change to it — an install whose sources never change would otherwise never get one, and a manifest deleted by hand would never come back.

Second bug: dry runs lie

wp_cmd routes through run_cmd, which echoes its arguments instead of executing them under DRY_RUN. So every recorded_* reader returned echoed command text and the resolver fell through to defaults.

The mode reader papered over this with its own DRY_RUN short-circuit returning the not-yet-resolved variable. Net effect on h44:

./upgrade.sh --dry-run
  --source-mode workspace
  edit_permission_expected: { wp-content/plugins/**: deny, wp-content/themes/**: deny, ... }
  external_directory_expected: { /var/lib/datamachine/workspace/**: allow }

For a site recorded as owned. The dry run advertised exactly the destructive outcome an operator runs a dry run to rule out — I nearly aborted a correct upgrade over it.

Reads are side-effect free and should happen during a dry run, not be simulated. Only writes belong behind run_cmd.

Coverage

Four new assertions in tests/source-mode.sh: a legacy install migrates onto the new sources key; the manifest is written for one; a manifest deleted by hand is restored even when the option needs no write; and a dry run reports the mode the install actually has.

Found by verifying the v1.13.0 upgrade on h44lacrosse.com rather than
trusting it: the mode migrated to the new key, the sources did not, and no
manifest was written at all — the one thing the release existed to do.

source_policy_record_owned_sources compared through the legacy-aware
reader, which on a pre-rename install returns exactly the paths about to be
written. So it returned early, never wrote the new key, and never reached
the manifest call sitting after it. This is the same defect the mode
recorder already carries a comment about; I fixed it there and did not
apply it to the siblings, which is precisely the failure that comment
warns about. The writable and log recorders had it too.

The manifest now reconciles BEFORE any no-change return. It is a projection
of the declaration, not a record of a change to it: an install whose
sources never change would otherwise never get one, and a manifest deleted
by hand would never come back.

Also fixes reads under --dry-run. wp_cmd routes through run_cmd, which
ECHOES its arguments instead of executing them when DRY_RUN is set, so
every recorded_* reader returned the echoed command text and the resolver
fell through to defaults. The mode reader papered over this with its own
DRY_RUN short-circuit that returned the not-yet-resolved variable, so
`./upgrade.sh --dry-run` on h44 reported `--source-mode workspace` and a
full deny set for a site recorded as owned — advertising exactly the
destructive outcome an operator runs a dry run to rule out. I nearly
aborted a correct upgrade because of it.

Reads are side-effect free and should happen during a dry run rather than
be simulated; only writes belong behind run_cmd.
@chubes4
chubes4 merged commit 42cc1c0 into main Aug 5, 2026
42 checks passed
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