Skip to content

fix(bindings): served bindings keep owner write; failed sync fails loudly and skips reconcile - #113

Merged
arcaven merged 1 commit into
mainfrom
fix/binding-write-mode-108
Aug 1, 2026
Merged

fix(bindings): served bindings keep owner write; failed sync fails loudly and skips reconcile#113
arcaven merged 1 commit into
mainfrom
fix/binding-write-mode-108

Conversation

@arcaven

@arcaven arcaven commented Aug 1, 2026

Copy link
Copy Markdown
Member

Fixes #108 (P1 from the aae-orc#154 consumer round): since the store freeze (#106), served bindings inherited the frozen source's 0444 mode, so the next sync could not overwrite its own output. Every other version flip removed all 119 artifacts, synced zero, and exited 0, leaving a user with no bmad content behind one warning line.

Two composing fixes, matching the diagnosis in the issue:

  • writeWithSourceMode keeps the owner write bit (exec bit still carries; served bindings are sideshow-owned regenerable output, not store content) and unlocks a pre-fix read-only target in place, so machines that already synced from a frozen store self-heal on the next sync. Verified live: this machine's served bindings sat at 0444 and two consecutive syncs with the fixed binary both wrote 120 artifacts.
  • runSync counts failed bindings, skips the stale reconcile when any failed, and returns an error. The reconcile skip is what stops the wipe: a failed binding's artifacts are absent from the ownership set, so reconciling would remove content it still owns. And a sync that writes 0 of N now exits nonzero (the issue's secondary point).

Tests: frozen-source mode carry, exec-bit preservation, pre-fix target self-heal, failure-skips-reconcile with a planted prior manifest (the served artifact survives), clean path still reconciles.

…udly and skips reconcile

Two composing fixes for sideshow#108 (found in the aae-orc#154
consumer round): since the store freeze (#106), writeWithSourceMode
carried the frozen source's 0444 onto served bindings, so the next
sync could not overwrite its own output. Every other version flip
removed all artifacts, synced zero, and exited 0; the flip after
succeeded only because the previous one had deleted everything.

writeWithSourceMode now keeps the owner write bit (served bindings
are sideshow-owned regenerable output, not store content; the exec
bit still carries), and unlocks a pre-fix read-only target in place,
so machines that synced from a frozen store self-heal on the next
sync. Verified live on this machine: served bindings sat at 0444,
and two consecutive syncs with the fixed binary both wrote 120
artifacts and restored owner write.

runSync now counts failed bindings, skips the stale reconcile when
any failed (an incomplete ownership set would remove artifacts a
failed binding still owns), and returns an error so use and commands
sync exit nonzero. A sync that writes 0 of N no longer exits 0.

Closes #108
@arcaven
arcaven merged commit 6b5b01f into main Aug 1, 2026
@arcaven
arcaven deleted the fix/binding-write-mode-108 branch August 1, 2026 22:49
arcaven added a commit that referenced this pull request Aug 8, 2026
…bstitution (#117)

The rewrite substituted every {project-root}/_bmad/ reference with the
absolute user-install path, assuming everything under the shim dir is pack
content. It is not. Pack content is what the installer put in the store;
everything else under _bmad/ is project state that upstream creates and
writes at runtime. Blind substitution redirected that state into immutable
shared storage, inside instructions an agent then follows.

Controlled traversal of the synced surface (2,205 files, 173 skill dirs)
found 30 distinct pack references, 14 of them absent from the store,
carried by 32 files. All 14 originate as {project-root}/_bmad/... in the
pack source, so the rewrite created every one. They include the config
write targets already filed, and two classes not previously recorded:
runtime state (the agent-builder memory/{skillName} sanctum, planning
output) and the custom/ surface bmad-customize exists to write.

The store is installed read-only (FreezeTree, aae-orc-dihj), so a path
absent from it can never come into being there. That collapses the
read-versus-write question into an existence test, with none of the
write-verb, flag-name, or redirect heuristics the audit measured as
unreliable. A reference is rewritten only if it exists in the store;
otherwise it stays literal and the fallback footer resolves it
cwd-relative, which is correct for project state.

Existence cannot decide one case: {project-root}/_bmad/custom/ exists in
the store but pack.yaml custom_bridge declares it repo-writable territory.
That is settled by reading the declaration, so the bridge path is
preserved alongside _bmad-custom/ and _bmad-output/.

verify() is the post-condition, run independently of the rewrite so a
reference that arrived absolute in the pack source is caught too. It is
structural, so it gates: a violation fails the binding and skips stale
reconcile, per the loud-failure path from #108/#113.

End-to-end sync of bmad 6.10.0 into a sandboxed HOME: 119 artifacts, zero
dangling references, down from 14 across 32 files, with the 16 legitimate
reads still resolving to the store.

Closes aae-orc-c8v8
Refs aae-orc-dihj, aae-orc-mkpo, aae-orc-3mci
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.

use: version flip fails to write bindings and exits 0 — freeze mode 0444 propagates into served artifacts

1 participant