Skip to content

C7: provider-state root as a live_deploy EnsuredHostDirectory member - #11676

Merged
gunbai-bot[bot] merged 3 commits into
mainfrom
session/bright-swift-259
Sep 21, 2026
Merged

gunbai-bot[bot] merged 3 commits into
mainfrom
session/bright-swift-259

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

CONVERGENCE-ONE C7, replacement half (operator ruling 2026-09-19: live_deploy owns provider-state creation as an EnsuredHostDirectory member). Nothing is deleted here. The launcher deletion comes after this lands. There are no wet effects.

What changes

  • gunbc.live_deploy.spec: new EnsuredDependencyKind::ProviderStateRootDirectory.
    • deployment_provider_state_step(instance) builds the member. Its path comes from gunbc.roadmap_dashboard_instance dashboard_instance_provider_state_root and its owner from gunbc_service_user, the same principal readback compares against. No call-site literals.
    • deployment_steps_apply_order appends it per instance. It is not a host-level target.ensured_directories row, because the path is an instance fact.
    • deployment_provider_state_standing classifies a spec as Carried, Absent, Duplicated, WrongOwner or NotADirectory.
  • gunbc.live_deploy.emit:
    • live_deploy_apply_script_for refuses before emitting anything unless the standing is Carried. That function is the production route: deployment_spec_srv1, then host_effect_realize.
    • identity_member_of_step maps the member to a DirectoryRoot, so the release plan gates it (CreateRoot or Keep).
  • gunbc.live_deploy.member_observe: root_members_of_step puts the member in the read-back roster, and presence and owner are read like any root's. It stays Ensured, so retract never tears it down.
  • gunbc.roadmap.roadmap_dashboard_instance: the provision-plan annotation now records the ruled arm and points to the census.

Disposition census: who creates the provider-state root after this change

instance creator
srv1_live this live_deploy member, on the production route and read back. DashboardEnsureProviderStateRoot is now redundant for this instance and goes with the launcher deletion.
srv1_lab provision plan DashboardEnsureProviderStateRoot (sole creator; its spec carries the member but no production caller applies that spec)
srv2_lab provision plan (sole creator)
srv2_deploy provision plan (sole creator; its spec carries the member but has no production caller)
macbook_local provision plan (sole creator)

There are no blank rows. The provision op may be deleted for an instance only once a production caller applies that instance's spec.

Witnesses (test.claim.live_deploy.provider_state_member_witness_test)

  • Presence: the production step dispatch (apply_step_effects via the shared projection) over deployment_spec_srv1 emits the owned install -d for the model's path and owner.
  • Readback: the member roster contains DirectoryRoot{provider root}. Retract's owned identities do not.
  • Control: the production spec's standing is Carried at the model path.
  • Refusal: live_deploy_apply_script_for on the same spec with the member filtered out returns the refusal marker (standing=absent), not a script. A duplicated member is classified as Duplicated.

Stated divergence

The directory uses the ensured-directory arm's shared mode (0755), the same mode the provision mkdir produces. A tighter credential-root mode would be a ManagedDirectory derivation, which would change what EnsuredHostDirectory means for every kind, so it is out of scope here.

🤖 Generated with Claude Code

@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 19, 2026 02:51
@gunbai-bot
gunbai-bot Bot force-pushed the session/bright-swift-259 branch from e727927 to bf7b89b Compare September 20, 2026 01:22
@gunbai-bot

gunbai-bot Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

The failing check is not from this PR, and the passing check does not cover it either.

heal-generated-artifacts failure — pre-existing on main. The error is:

dag/gunbc/fleet/fleet_converge_workflow.dag:321: error: non-exhaustive match: missing variant(s) ApprovalKeyringConverge, MtCollins1Boot
(surfaced as: resolve failed for dag/gunbc/instruments/generated_artifact_gate.dag)

fleet_converge_workflow.dag is byte-identical to origin/main on this branch (git diff --quiet origin/main -- on that path is clean), and this PR touches five files, none of them that one. The cause is a pair of individually-green PRs: #11736 added fleet_converge_mode_fleet_ssh_key_demand, a total match over FleetConvergeWorkflowMode, and #11484 then added the ApprovalKeyringConverge and MtCollins1Boot modes without arms in it. The repair is one arm each, but the value (FleetSshKeyConsumed vs FleetSshKeyNotConsumed) decides whether a credential is materialized, so it belongs to that lane rather than to a guess from here. Reported to the parent session.

What the green witnesses check does and does not establish. Since #11742 the required check builds the compiler and runs no claims, so it is not evidence that this PR's witnesses pass. I therefore ran them directly against this head (bf7b89bd29), with a locally built claim_batch:

PASS the_production_apply_emits_the_provider_state_root_install   eval_steps=1913189
PASS the_provider_state_root_is_a_read_back_directory_member      eval_steps=924
PASS retract_never_owns_the_provider_state_root                   eval_steps=991
PASS the_production_spec_carries_one_provider_state_member        eval_steps=834
PASS an_apply_without_the_provider_state_member_is_refused        eval_steps=1196
PASS a_duplicated_provider_state_member_is_refused                eval_steps=962

All six executed and passed. They also ran and passed on the floor at the earlier head 882efba8 (run 35416906178), before #11742 removed that lane.

— sent from bright-swift-259

@gunbai-bot

gunbai-bot Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

Review 68784: both findings taken, and the fix is the construction arm rather than a patch to the check. Pushed as f25cb8a662.

Finding 1 — validation standing where construction was available. Agreed, and my own doc-comment stated the root cause, which is the tell. The constraint was decidable and fully modelled, so it is now carried by the model:

  • DeploymentServiceConfig gains provider_state_root, beside the instance-projected paths it already carries (serve_binary, instance_root, repo_root). deployment_service_config populates it from dashboard_instance_provider_state_root.
  • deployment_provider_state_step(spec) is a function of the spec: path from that field, owner from the same config's service_user.
  • The emitted ensure rides the apply preamble derived from that function (provider_state_ensure_steps), not a row in spec.steps. The read-back member derives from the same function.

Absent, Duplicated, WrongOwner and NotADirectory therefore have no constructor. Deleted: the five-armed ProviderStateMemberStanding, provider_state_dependencies, provider_state_single_standing, deployment_provider_state_standing, the poison string and the refusal branch. No next-rung trigger is owed because the class is at the ceiling, not below it.

Finding 2 — two arms with no discriminating red. Resolved by the same change: those arms no longer exist.

What happened to the two refusal witnesses, stated plainly because it departs from my brief. My brief asked for a witness proving absence is refused rather than silently skipped. Under construction that state has no constructor, so such a claim is permanently green and would stand as false coverage — DESIGN §4b: ask whether the RED is authorable before writing the check. I deleted them instead of keeping them for the tally. The replacement reds are structural: deleting the ensure from the preamble, or the member from the roster, reds the claims below. Added two that did not exist before — the spec's derived path equals the instance's own projection (the join that would catch the deploy creating a directory the preflight does not read), and the production preamble carries the ensure (the route, not only the command text). If the operator prefers the brief's literal wording, say so and I will restore the refusal arm.

Executed evidence at f25cb8a662 (locally built claim_batch; the required CI check runs no claims since #11742):

PASS the_spec_derives_the_instance_provider_state_path
PASS the_provider_state_ensure_emits_the_owned_install
PASS the_production_apply_preamble_carries_the_provider_state_ensure
PASS the_provider_state_root_is_a_read_back_directory_member
PASS retract_never_owns_the_provider_state_root

Neighbours re-run green: live_deploy/emit_test (5 claims incl. owned-vs-ensured and teardown-disposition) and all 34 of live_deploy_unit_emission_oracle_witness_test.

One neighbour legitimately went red first and was not quietly renumbered: the_preamble_ensures_the_publication_principal_as_a_nologin_system_account asserts count(preamble) == 2, and the preamble genuinely gained a third step. I moved it to 3 and recorded why, keeping it an exact count rather than relaxing to >= 2 — the conjunct exists to notice steps creeping into the preamble, and a bound admitting any number would stop noticing. That claim's own subject is unchanged.

Still blocked on a defect that is not this PR's: heal-generated-artifacts fails on main's non-exhaustive match in fleet_converge_workflow.dag (#11736 + #11484), reported separately.

— sent from bright-swift-259

@gunbai-bot

gunbai-bot Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

The one failing check is still the pre-existing main defect, not this PR.

heal-generated-artifacts at f25cb8a662 fails with the same cause as at the previous head:

error: resolve failed for dag/gunbc/instruments/generated_artifact_gate.dag
  cause: dag/gunbc/fleet/fleet_converge_workflow.dag:321:3: error: non-exhaustive match: missing variant(s) ApprovalKeyringConverge, MtCollins1Boot

It is still unfixed on the newest main (66d683bc86): the two arms are absent from fleet_converge_mode_fleet_ssh_key_demand there, so the gate cannot resolve for any PR. The repair is already in flight as #11777, so I am not duplicating it. Once that lands I will bring this branch up to date and re-check.

The other check, witnesses, passes — though since #11742 it only builds the compiler, so the executed evidence for this PR is the local run reported in the previous comment.

— sent from bright-swift-259

@gunbai-bot

gunbai-bot Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

Review 68824: both findings verified against the head and fixed in b1650862ad.

1. The false refusal clause in roadmap_dashboard_instance.dag. Correct, and it was mine twice: I wrote the sentence for the original validation design and then did not re-read it when the construction rework deleted the refusal out from under it. That is the §4b(1) failure exactly as described — prose reporting a wall one rung above what holds, on the one carrier a reader consults before deleting DashboardEnsureProviderStateRoot, contradicting the two authorities that state it correctly. It now reads:

The member is read back as a DirectoryRoot, and no spec can lack it: the member is derived from the spec rather than authored into its step list, so the state a refusal would have caught has no constructor.

2. Unused ProviderStateRootDirectory import in emit.dag. Confirmed — git grep showed the kind referenced only at emit.dag:73 (the import), spec.dag:110 (the variant) and spec.dag:962 (its one construction). Residue of the deleted refusal arm, removed. The emitter only calls deployment_provider_state_step.

Re-ran the five witnesses at this head after touching a file they resolve through — all pass:

PASS the_spec_derives_the_instance_provider_state_path
PASS the_provider_state_ensure_emits_the_owned_install
PASS the_production_apply_preamble_carries_the_provider_state_ensure
PASS the_provider_state_root_is_a_read_back_directory_member
PASS retract_never_owns_the_provider_state_root

Still blocked on main, not on this PR: heal-generated-artifacts fails on the non-exhaustive match in fleet_converge_workflow.dag, unfixed on main as of 66d683bc86, with the repair in flight as #11777.

— sent from bright-swift-259

@gunbai-bot
gunbai-bot Bot force-pushed the session/bright-swift-259 branch from b165086 to 31977e2 Compare September 20, 2026 03:10
… the spec

live_deploy now creates and reads back the provider-state root, so the dashboard
launcher can be deleted without losing that creation silently.

DeploymentServiceConfig carries provider_state_root, projected from
dashboard_instance_provider_state_root beside the other instance paths it already
holds. deployment_provider_state_step is a function of the spec: the emitted
ensure rides the apply preamble derived from it, and the read-back DirectoryRoot
member derives from the same function, so the created path and the observed path
cannot diverge. Absent, duplicated, wrong-owner and not-a-directory have no
constructor, so nothing validates them.

Nothing is deleted here. The census on deployment_provider_state_step records who
creates the root for each instance: srv1_live from this member, the other four
still only from the provision plan's DashboardEnsureProviderStateRoot, which stays
until a production caller applies their specs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot force-pushed the session/bright-swift-259 branch from f61b663 to c153cfa Compare September 20, 2026 07:48
briansrls pushed a commit that referenced this pull request Sep 20, 2026
Main moved 27 commits and edited five of its seven files, so the resolve is
content work, not a projection drop. Its only consumer is C8, which is held, so a
rebuild would deliver a member nothing consumes at the cost of a full review and
CI cycle, and would rot again on the next live_deploy edit. Left open rather than
closed so the review history survives for whoever resumes C8.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Brian Searls and others added 2 commits September 21, 2026 00:25
# Conflicts:
#	dag/gunbc/live_deploy/spec.dag
#	dag/test/claim/live_deploy_unit_emission_oracle_witness_test.dag
…oot too

main added approval_broker_service_config, a second DeploymentServiceConfig literal,
while this branch added the provider_state_root field; the merge resolved textually
and the floor caught the missing field at spec.dag. The broker is a second unit on an
instance rather than a sixth instance, so its root is that instance's root from the
same projection, and the census records why.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 21, 2026
Merged via the queue into main with commit 572364e Sep 21, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/bright-swift-259 branch September 21, 2026 01:50
@briansrls
briansrls restored the session/bright-swift-259 branch September 21, 2026 01:54
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.

0 participants