mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-10-25 21:20:25 +00:00
7a6682ed3f
* fix: pull the next commit on a manual Git-managed Blueprint A claimed manual source had no operator fetch: polling skips it, and stack Pull now stays refused. Pull source stages a candidate and leaves acceptance to Accept source, except an automatic policy, which accepts the same way a poll does. * test: supply a node list to the GitOps sheet mocks The authority row reads the default node from the node context. These mocks omitted nodes, so the sheet threw before it rendered. * test: type the Git source permission mock without unused parameters The default can implementation always returns false. Naming the permission arguments made lint fail. * fix: send the Blueprint id and report what Pull source did The claimed sheet posted the internal application id, so the pull never reached the Blueprint. An automatic pull could accept and start a rollout while the result only said the commit was fetched. * fix: report a continuing automatic pull instead of a failed one Acceptance can commit before preparation and rollout finish. Answer once that wait reaches its deadline, keep the source locked until the work finishes, and do not describe the deadline as a failed pull. * fix: report why an automatic pull cannot prepare a commit A completed preparation reason was replaced by the generic unresolved-artifact skip. Keep that reason, and describe the claimed sheet by the source actions it still offers. * fix: refuse a pull that would replace an interrupted apply's candidate Apply recovery stays eligible only while the interrupted generation is still the current candidate. Pull source waits in that case. An interrupted fetch still pulls, and a pull stays available once the candidate has moved on. * refactor: share the bounded follow-up after a Git-managed acceptance Accept source and an operator pull each had their own copy of the deadline, the continuation notes, and the slot hold. One follow-up now answers both. * fix: declare the post-accept deadline timer as const The deadline id is assigned once. A later assignment made the lint fail. * fix: confirm Accept source before it can start a rollout Accept source recorded the fetched commit immediately, including when stored rollout authorization can deploy it, and those actions were not on the sheet Overview. The confirmation names the commit, the approved targets, and whether a rollout can start, and confirm posts the generation that was on screen. * fix: read placement approval only on a Blueprint projection The accept preview read approvals on every projection, and the one with nothing to show has no approvals. The Blueprint check comes first so the build can read the placement ref. * fix: name the approved rollout scope and report settled failures Two confirmations could describe a destination the action would not use, and one result reported work as starting when it had already failed. Accept source named every observed target row as approved placement. Those rows are where an application runs, not where a rollout goes, and they disagree whenever placement moved since the last rollout ran: an approved node has no row until the rollout that places one, and a withdrawn node keeps one. A projection now carries the scope the placement approval froze, read from the rollout candidate and accepted only once the approval resolves for that set, which is the evidence the dispatch boundary already uses. Both confirmations read it through one reader and name the approved nodes, or say the scope cannot be read rather than naming a set they did not. The bounded follow-up used its continuing-work answer for a deadline and for a rejection alike, so a dispatch that had already failed was reported as starting, with nothing pending. The three outcomes are now distinct: only a deadline holds work still running, and a rejection reports the rollout as held with the failure named. * fix: bind a source confirmation to the request that carries it Pull source and Accept source asked the operator to confirm a destination and then sent nothing that named it. Fetch posted an empty body and acceptance posted only a generation, so execution read whatever the placement and the rollout policy happened to say at the moment it dispatched. An operator could confirm a placement for one node and deploy to another, and a dialog promising a waiting rollout could start one after another session armed the policy. Both bodies now carry what the dialog read: the placement approval the scope was resolved from, and whether the confirmation said a rollout could start. The description and the claim are frozen together when the overlay opens, so the words the operator agreed to and the state the server checks are one read of one projection. The claim is checked at every consequential boundary rather than only at the route, because each one is preceded by asynchronous work: at the route and at the controller entry, again before an automatic acceptance after the reconcile, and again in the handoff after preparation. A refusal that lands after the acceptance committed is held with the reason instead of answered, since the reconciler re-drives any accepted generation with nothing to check it against and a refusal that recorded nothing would be undone by the next tick. The hold carries an operator origin, so only a person clears it, and the recovery is the existing one: review the placement, then resume the rollout. The destination is compared exactly, because the dialog named specific nodes. The rollout promise is compared one way: a confirmation that allowed a rollout and finds the policy waiting for an operator does less than it said, and the dispatch gate already reports that, while the reverse would start something the operator was told would wait. A manual or review pull only fetches, so it asks for nothing, and the poll and resume paths send no confirmation at all because a cadence is configured rather than confirmed. * fix: keep the confirmation hold inside the mode that can clear it Three ways the refusal did not survive contact with the rest of the model. The hold was recorded below the rollout authorization policy gate, so a manual source paused the rollout over a confirmation the handoff could never have acted on. A manual policy never dispatches from here, and its Authorize is already the operator's own decision against the placement as it stands, so all that bought was an extra resume step before an authorize the pause also blocks. The gate is back first and the confirmation is checked under it, so only an automatic policy, the one that would have dispatched on its own, is held. The hold outlived the Blueprint. Every resume route resolves a Git-managed Blueprint and answers NOT_GIT_MANAGED for the row afterwards, so a pause carried through Retire or Detach read as a paused rollout nothing could clear. Both demotion paths now clear it, which is what the Blueprint demotion already does with every other column it invalidates. And the module claimed the check ran at every consequential boundary, which is only true of the boundaries an operator action reaches. A cadence carries no claim to check, so the poll and the reconciler's re-drive are not among them, and the hold is what keeps them from undoing a refusal. Each correction is covered by a test that fails without it: a manual-policy acceptance whose placement moves during preparation is not held, an operator hold survives a later acceptance on the policy's own behalf, and retiring a Blueprint releases a held rollout. * fix: make a confirmed acceptance keep its placement past the request A confirmation carried only in a request body stops existing when the request answers, and two paths outlive it while both still dispatch. Preparation can run past its deadline and hand the handoff to the reconciler, and a restart re-drives any accepted generation with no request in the picture. The guard therefore protected the fast path and nothing else, which is worse than none: the operator was told to review a change that then deployed on its own. The acceptance now records the precondition on its own approval row, in the column that already existed there and was unused for this kind. A null recording is a real answer rather than missing evidence: an acceptance made by the poll records none, because a cadence is configured rather than confirmed. It is enforced in ensureRolloutAuthorization, the single funnel every mint passes and the only place an unattended dispatch reaches, so it covers the reconciler's re-drive and the startup preflight backfill as well as the request that carried the claim. Only a policy mint is bound: an operator mint is the decision the confirmation deferred, taken against the placement as it stands. A stale precondition holds rather than merely refuses, because a refusal with nothing behind it is re-attempted every reconcile and leaves a rollout queued with no reason attached. The acceptance itself stands, so the content is recorded and only its destination waits for a person. An application-scoped resume releases the recording; a target-scoped one does not. The same function now re-resolves ingredients after the registry preflight await and refuses when the placement approval or the frozen node set moved. The mint re-reads ingredients inside its write transaction, so a placement re-approved mid-preflight produced a rollout naming the replacement nodes with readiness evidence that described the old ones. That gap predates this work, but a request-local guard cannot see past an await, and a rollout generation is immutable once written. * fix: compare the whole ingredient record, and let an operator mint decide Two gaps in the durable guard, both found by reading it against the paths that reach it. The post-await comparison watched the placement approval and the frozen node set and nothing else. A source acceptance landing during the same preflight window changes the generation, the artifact set and the acceptance without moving either of those, so the check passed and the mint named the new generation with readiness evidence evaluated for the old one, which is the same defect the comparison was added to close. Every field the mint copies onto an immutable rollout generation is compared now. An operator mint is exempt from the guard, because asking to authorize the rollout is the decision the confirmation deferred. Nothing moved the recording on that path, so once the authorization lapsed the automatic policy held a rollout asking the operator to resume a placement they had deliberately authorized. An operator mint now re-points the recording at what was decided, inside the mint's own transaction, which also keeps the guard working for the next replacement. * fix: keep the whole source confirmation after the request ends A stored placement pointer let a later re-drive start a rollout the operator was told would wait, or deploy to a destination the confirmation never named. The acceptance now stores both facts, and unattended authorization reads that record rather than the request that already finished. * fix: show source confirmations and start a ready automatic resume Operators were asked to confirm a sentence they could not read, and Resume reported that an automatic policy would start a rollout it never dispatched.