Skip to content

Enable topology response profiles for curtailment automation - #978

Merged
negarn merged 4 commits into
mainfrom
negar/gh-909-enable-topology-profile-automation
Aug 29, 2026
Merged

Enable topology response profiles for curtailment automation#978
negarn merged 4 commits into
mainfrom
negar/gh-909-enable-topology-profile-automation

Conversation

@negarn

@negarn negarn commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Reviewable diff: +377/-146 across 11 files (excludes generated, test, and story files).

Summary

Topology-scoped response profiles can now be bound to and executed by MQTT curtailment automation. Building, rack, and group selectors remain logical scopes, so each trigger resolves current membership while every automation scope fails closed if the selector, source principal, permissions, or required admin role changed. This is the automation-enablement slice of #909; the remaining picker/UI and E2E work stays tracked there.

How it works

When a rule is created, updated, enabled, or triggered, the response profile service strictly resolves its persisted topology selector. A new automation event enters the existing SQL execution transaction, which locks the rule, profile revision, MQTT source, current topology, effective permission assignments, and primary role before persisting any event or target reservation. If an OFF signal reasserts demand while an event is restoring, the re-curtail transaction applies the same rule, source-principal, permission, admin-role, profile, and event-ownership checks before it reclaims targets. The authorization-envelope evaluator is shared with the reconciler's pre-dispatch fence, keeping admission, re-curtail, and physical dispatch aligned.

flowchart LR
    A["MQTT OFF signal"] --> B["Load bound response profile"]
    B --> C{"Existing event is restoring?"}
    C -->|"No"| D["Resolve current building, rack, or group scope"]
    D --> E["Build curtailment plan"]
    E --> F["Transactional start fence"]
    C -->|"Yes"| G["Transactional re-curtail fence"]
    F --> H{"Binding and authorization still valid?"}
    G --> H
    H -->|"Yes"| I["Persist event or reclaim targets"]
    H -->|"No"| J["Reject without changing ownership"]
    I --> K["Reconciler revalidates before Curtail dispatch"]
Loading

Areas of the code involved

Area / package / file What changed Why it matters for review
client/ curtailment profile types Marks every recognized terminal scope as automation-ready Building, rack, and group profiles are selectable without treating unknown scopes as valid
server/internal/domain/curtailment Removes topology staging gates, adds strict live selector validation, and carries the automation execution fence through re-curtail Binding and trigger paths preserve logical selectors and re-curtail cannot bypass current rule ownership
Authorization envelope Extracts the shared current-permission coverage check Start, re-curtail, and dispatch use the same site/org-wide authorization semantics for every scope
server/internal/domain/stores/sqlstores Adds transactional source-principal, permission, role, topology, profile, rule, and event-ownership fences Unauthorized automation cannot reserve or reclaim miners before dispatch
server/sqlc/queries/ Locks and verifies the current MQTT source user and primary role Concurrent source edits or role demotions serialize with event creation
server/generated/sqlc/ Regenerated SQL bindings — skip Generated from the reviewed query sources

Key technical decisions & trade-offs

  • Keep topology selectors logical and resolve them live instead of snapshotting miner IDs into the automation rule.
  • Recheck authorization inside start and re-curtail transactions instead of relying only on the later dispatch fence, preventing unauthorized reservations from being persisted or reclaimed.
  • Apply permission and admin-role checks to every automation scope, including site, whole-org, and explicit-miner profiles.
  • Preserve idempotent replay recovery even when a profile later changes; strict current-profile validation applies only before creating or re-curtailing an event.
  • Keep profile reads tolerant of stale topology for settings/history, while execution-capable paths opt into strict resolution.

Testing & validation

  • go test ./internal/domain/curtailment/... ./internal/handlers/curtailment
  • go test ./internal/domain/stores/sqlstores -run '^$'
  • go build ./... from server/
  • just _lint-server
  • go test ./cmd/fleetnode -run '^TestRunCmd_RefreshFailureCannotExtendControlStreamPastExpiry$' -count=10
  • npx vitest run for the response-profile hook, automation settings, and curtailment settings suites (89 tests)
  • npx tsc --noEmit
  • npm run build:protoFleet
  • just _lint-client
  • Added SQL integration coverage for deleted selectors; topology and site permission revocation; admin demotion; changed MQTT source principals; and successful or rejected transactional re-curtail. The local integration database could not authenticate the configured fleet user, so those cases are compiled locally and will execute in CI.

Refs #909

@negarn
negarn requested a review from a team as a code owner August 28, 2026 13:38
Copilot AI lite review requested due to automatic review settings August 28, 2026 13:38
@github-actions github-actions Bot added javascript Pull requests that update javascript code client server labels Aug 28, 2026
@github-actions github-actions Bot added the review-policy: needs-review Managed by the Review Policy workflow. label Aug 28, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 35b55208c9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread server/internal/domain/stores/sqlstores/curtailment.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Enables building/rack/group (topology-scoped) response profiles to be bound to and executed by MQTT curtailment automation, by adding stricter live selector validation and strengthening the SQL-side execution fence (rule/profile/source/permissions/role) so automation fails closed when bindings or authorization drift.

Changes:

  • Allow topology-scoped response profiles to be used by automation, with strict live selector validation on bind/execute paths.
  • Add transactional locking/verification for MQTT source principal and role/permission rechecks during automation event insertion.
  • Update ProtoFleet client “automation-ready” classification and associated unit tests to include topology scopes (while keeping unknown scopes read-only / not automation-ready).

Reviewed changes

Copilot reviewed 16 out of 21 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
server/sqlc/queries/user_organization.sql Adds a locking query to fetch a user’s org role name for admin-role revalidation inside execution transactions.
server/sqlc/queries/curtailment_automation.sql Extends the rule execution lock to also lock/verify the MQTT source row and its service user.
server/internal/domain/stores/sqlstores/response_profile_revision_integration_test.go Adds integration coverage for topology automation execution failing closed on permission/role/source drift.
server/internal/domain/stores/sqlstores/response_profile_automation_scope_integration_test.go Updates integration test expectations: topology-scoped profiles can be automated; deleted selectors fail closed.
server/internal/domain/stores/sqlstores/curtailment.go Removes topology automation gating; adds topology selector locking/validation and new automation execution authorization fence.
server/internal/domain/curtailment/service.go Removes the prior “topology Start not available for automation” gate.
server/internal/domain/curtailment/response_profile.go Introduces ValidateAutomationScope for strict live validation in execution-capable paths.
server/internal/domain/curtailment/response_profile_test.go Updates unit test to reflect that topology scopes are allowed even when automation rules exist.
server/internal/domain/curtailment/reconciler/dispatch_authorization.go Refactors dispatch authorization to use the shared AuthorizationEnvelopeAllows helper.
server/internal/domain/curtailment/automation.go Switches binding/execution checks to use ValidateAutomationScope and current-bound-profile validation.
server/internal/domain/curtailment/automation_test.go Updates automation unit tests to allow topology binding/execution and to fail closed on unavailable selectors.
server/internal/domain/curtailment/authorization_envelope.go Adds shared AuthorizationEnvelopeAllows helper for consistent admission/dispatch permission coverage checks.
server/generated/sqlc/user_organization.sql.go Generated sqlc bindings for GetUserRoleNameForUpdate (generated — skip).
server/generated/sqlc/retrying_querier.gen.go Generated retrying querier method for new query (generated — skip).
server/generated/sqlc/querier.go Generated querier interface update (generated — skip).
server/generated/sqlc/db.go Generated prepared-statement wiring for new query (generated — skip).
server/generated/sqlc/curtailment_automation.sql.go Generated sqlc bindings for updated execution lock query (generated — skip).
client/src/protoFleet/features/settings/components/Curtailment/types.ts Marks any recognized terminal scope type as automation-ready (no longer excluding topology scopes).
client/src/protoFleet/features/settings/components/Curtailment/CurtailmentSettingsPage.test.tsx Updates settings page test to expect topology profiles to be automation-ready.
client/src/protoFleet/features/settings/components/Curtailment/CurtailmentAutomations.test.tsx Updates automation UI tests to include topology-scoped profiles and keep unsupported scopes blocked.
client/src/protoFleet/api/useCurtailmentResponseProfiles.test.tsx Updates hook tests for automation-ready classification (topology true; unknown false).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread server/internal/domain/stores/sqlstores/curtailment.go Outdated
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Note: This is an automated security-focused code review generated by Codex.
It should be used as a supplementary check alongside human review.
False positives are possible - use your judgment.

Scope summary

  • Reviewed pull request diff only (414e010e477e59c4b3b40d04ed3b67378f9f9df9...163281872d5137bf588e3ce2a8c6414d86c8cb75, exact PR three-dot diff)
  • Model: gpt-5.6-sol

💡 Click "edited" above to see previous reviews for this PR.


Review Summary

Overall Risk: HIGH

Findings

[HIGH] Automated review incomplete

  • Category: Other
  • Description: The automated review produced no usable result for 414e010e477e59c4b3b40d04ed3b67378f9f9df9...163281872d5137bf588e3ce2a8c6414d86c8cb75 (workflow run 33251268784; reason: codex-job-timeout, elapsed: unknown, budget: 9 minutes).
  • Impact: The pull request has not received complete automated security, correctness, and reliability analysis.
  • Recommendation: Require human review before merging. Do not treat this result as approval-free or low risk.

Notes

Human review is required because the bounded automated review was incomplete.


Generated by Codex Security Review |
Triggered by: @negarn |
Review workflow run

Comment thread server/internal/domain/curtailment/automation.go
Comment thread server/internal/domain/stores/sqlstores/curtailment.go Outdated
Comment thread server/internal/domain/curtailment/automation.go
Comment thread server/internal/domain/stores/sqlstores/curtailment.go Outdated
Comment thread server/internal/domain/curtailment/automation.go
@github-actions github-actions Bot added review-policy: human-approved Managed by the Review Policy workflow. and removed review-policy: needs-review Managed by the Review Policy workflow. labels Aug 28, 2026
@github-actions github-actions Bot added review-policy: needs-review Managed by the Review Policy workflow. and removed review-policy: human-approved Managed by the Review Policy workflow. labels Aug 29, 2026
@negarn
negarn merged commit 72dba79 into main Aug 29, 2026
71 of 74 checks passed
@negarn
negarn deleted the negar/gh-909-enable-topology-profile-automation branch August 29, 2026 14:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client javascript Pull requests that update javascript code review-policy: needs-review Managed by the Review Policy workflow. server

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants