Skip to content

feat(runtime): replace family snapshots with session-owned settings in session metadata - #46

Merged
osovv merged 7 commits into
mainfrom
factory/session-owned-settings-zamenit-family-snapshots
Nov 8, 2026
Merged

osovv merged 7 commits into
mainfrom
factory/session-owned-settings-zamenit-family-snapshots

Conversation

@osovv

@osovv osovv commented Nov 8, 2026

Copy link
Copy Markdown
Owner

Why the change

The snapshot-plus-guard mechanism kept freezing configuration into a side store and then proving every request against that copy, which produced recurring runtime incidents, so families now simply live with their own settings recorded in native session metadata.

Special things to note

  • Behavioral change (intended): a family root session no longer switches its own model or gains family-qualified model variants — roles apply only to newly created children at creation time (agent definitions plus a one-shot child reconciliation), and existing sessions keep whatever native model they have.
  • One-time migration: the first start of the new version converts existing family bindings into root-session metadata, then deletes the legacy bindings/, snapshots/, and rebind/ directories; a failed write keeps them and retries on the next start. The old snapshot store is never read afterwards.
  • The e2e host pin now targets the newest verified host (2.2.5, src/hosts.json) with the published binary's sha256; fresh live evidence for 2.2.6 was not obtainable in this environment, so the verified list is unchanged and the pin is override-driven (VVOC_E2E_V2_HOST_SHA256 / VVOC_E2E_V2_SOURCE_COMMIT, the source commit is no longer claimed by default because the published binary carries no verifiable commit metadata).

Change outline

Settings live under one metadata key of the family root; every write is a read-modify-write so foreign metadata survives the native replace-semantics write:

// metadata["vvoc:settings"] on the family ROOT (children carry none)
{ "version": 1, "preset?": "vv-zai",
  "roles": { "smart": "prov/m2#high", "...": "..." },
  "profile": "orchestrated",
  "plugins": { "secrets-redaction": true } }
resolve(session):  lineage to root (parentID / forkSessionID, cycle+depth guarded)
                   → decode(root.metadata["vvoc:settings"]) ?? live vvoc.json
birth(root):       first resolution → read fresh metadata → merge only the
                   settings key → session.update (serialized per family)
explicit change:   `vvoc session set --session <id>` / TUI `/vv-settings`
                   (preset | profile | role | plugin | pull-defaults) →
                   lineage to root → single RMW of that family only

The guard machinery is deleted outright — snapshot-store.ts, snapshots.ts, the rebind marker store, /vv-rebind, and the --force flags are gone, so the bind/admission error class can no longer occur:

- runtime.snapshots.configFor(session) → accept(...)   // bind + guard
- bindFor / guardResolvedModel / firstWorkPending / explicitSelections
- SnapshotAdmissionError | SnapshotUnboundError | SnapshotStoreError
+ runtime.settings.configFor(session)                   // resolve, fail-soft
+ migrateFamilyBindings(...)                            // one-shot migration

All plugin consumers (workflow, model-roles, system-context-injection, guardian, and the rest) resolve the projected family config through the one settings service; credentials keep coming from the live configuration and are never persisted in metadata. The real-host e2e harness asserts birth stability, config-change isolation, restart persistence, and lineage instead of snapshot ids.

osovv added 7 commits November 7, 2026 23:40
Replace the snapshot store and bind/guard machinery with a session-owned
settings service: the resolved roles, orchestration profile, and plugin
toggles of the effective configuration are recorded under one metadata key
of the family root on first resolution, resolved through host-verified
lineage for every member, and merged back through read-modify-write so
foreign metadata survives the native replace-semantics write. Birth reads
the effective configuration fresh because vvoc.json edits emit no host
config event. Legacy bindings migrate once into root metadata and the old
directories are pruned only after a fully successful pass.
Every native plugin consumer (workflow, model-roles, system-context-
injection, guardian, hashline-edit, spec-guard, analytics, tool-history-
compaction, peak-hours, web-tools, secrets-redaction) reads its family
policy from the shared settings service instead of the removed snapshot
configFor/accept pair; the workflow runtime surface narrows to the settings
service and the integration suites cover birth stability, family-scoped
changes, and creation-level role application.
Add `vvoc session set --session <id>` (preset, profile, role, plugin
toggle, or pull-defaults) and the native TUI /vv-settings command sharing
the same action parser; both resolve lineage to the family root and perform
a single metadata read-modify-write, so only the named family changes.
Drop the --force/--session rebind flags from preset, role, and plugin
commands together with the rebind marker store and /vv-rebind.
The fixture control plane forwards to the family-settings service
(/settings, /family) instead of the removed admission and snapshot
endpoints; cases assert lazy metadata birth, config-change isolation,
lineage, restart persistence, and role payloads without qualified snapshot
variants or per-request session attribution; the restart-replay case proves
the persisted record survives a real host restart byte-identically. The
host pin targets the newest verified host (2.2.5) with the published
binary's sha256, and the source commit is no longer claimed by default
because the published binary carries no verifiable commit metadata.
Rewrite the binding/rebind/--force contract paragraphs, the plugin table
row, and the startup-snapshot note around session-owned settings and the
new explicit change commands; the GRACE graph and verification entries
describe the settings service, the deleted machinery, the new command
surfaces, and the rewritten scenarios.
…rift notes

The guard error class no longer exists; the distinct-context smoke now
asserts the absence of family-binding admission failures in the host log
without naming the deleted class.
@osovv
osovv merged commit 400cfd9 into main Nov 8, 2026
1 check 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