P1-FieldRequired |
TestFormalReplaceLabelP1_FieldRequired |
label_to_remove/label_to_add required, non-empty (RL-004, RL-005) |
P2-FieldMaxLength |
TestFormalReplaceLabelP2_FieldMaxLength |
128-char label limits, 256-char repo limit (RL-004..RL-006) |
P3-DefaultMaxFive |
TestFormalReplaceLabelP3_DefaultMaxFive |
ValidationConfig DefaultMax = 5 (RL-012) |
P3-ValidationConfig |
TestFormalReplaceLabelP3_ValidationConfigFields |
Field rules (Required, Type, MaxLength, Sanitize) match spec §4.2.1 |
P4-AllowlistEnforcement |
TestFormalReplaceLabelP4_AllowlistEnforcement |
label_to_add accepted/rejected by allowed-add globs (RL-020..RL-022) |
P5-BlocklistPriority |
TestFormalReplaceLabelP5_BlocklistPriority |
blocked rejects label even when matching allowed-add (RL-003) |
P6-RemoveAllowlist |
TestFormalReplaceLabelP6_RemoveAllowlist |
label_to_remove accepted/rejected by allowed-remove (RL-021, RL-025) |
P7-RequiredLabelsGate |
TestFormalReplaceLabelP7_RequiredLabelsGate |
ALL required-labels present → proceed; missing → skipped:true (RL-024, RL-026) |
P8-TitlePrefixGate |
TestFormalReplaceLabelP8_TitlePrefixGate |
Title must begin with prefix; else skipped:true (RL-025, RL-026) |
P9-StagedFlag |
TestFormalReplaceLabelP9_StagedFlagOnConfig |
staged=true stored as TemplatableBool on config (RL-027) |
P9-StagedResult |
TestFormalReplaceLabelP9_StagedHandlerResult |
Staged returns {success:true, staged:true} (RL-028) |
P10-LabelSetComputation |
TestFormalReplaceLabelP10_LabelSetComputation |
new = (current − rm) ∪ {add}, deduplicated (RL-029) |
P11-IdempotentMissingRemove |
TestFormalReplaceLabelP11_IdempotentMissingRemove |
rm absent → add-only, labelRemoved=null, success:true (RL-034, RL-039) |
P12-LabelToAddAlwaysPresent |
TestFormalReplaceLabelP12_LabelToAddAlwaysPresent |
label_to_add exactly once in result (RL-041, RL-042) |
P13-HardVsSoftErrors |
TestFormalReplaceLabelP13_HardVsSoftErrors |
Gate → skipped:true; REST failure → hard error (RL-026, RL-044, RL-046) |
P14-CrossRepoRestriction |
TestFormalReplaceLabelP14_CrossRepoRestriction |
repo ∉ allowed-repos rejected (RL-015, RL-050) |
P15-TargetModeEnforcement |
TestFormalReplaceLabelP15_TargetModeEnforcement |
"triggering" → triggering item only; "*" → any (RL-018, RL-020) |
Edge-IdenticalLabels |
TestFormalReplaceLabelEdge_BothLabelsIdentical |
label_to_remove == label_to_add → deduplicated to one occurrence |
Edge-HTTP422 |
TestFormalReplaceLabelEdge_NonExistentLabelHTTP422 |
Missing label_to_add → hard error, not soft skip (RL-052) |
Edge-AliasFields |
TestFormalReplaceLabelEdge_ItemNumberAliasFields |
item_number typed IssueNumberOrTemporaryID for alias resolution (RL-016) |
Edge-ConfigStruct |
TestFormalReplaceLabelEdge_ReplaceLabelConfigStructFieldsPresent |
All §4.1.1 config fields present on ReplaceLabelConfig |
Summary
Formal verification model and Go testify unit-test suite for
specs/replace-label-spec.md— the W3C-style spec for thereplace-labelsafe-output type. This spec defines atomic label transitions on GitHub issues/PRs via a single RESTPUT /issues/{n}/labelscall. Fifteen predicates were extracted from 56 normative requirements (RL-001..RL-056) and mapped to 21 Go test functions covering schema validation, allowlist/blocklist enforcement, gate checks, staged mode, label-set computation, idempotency, and cross-repo restrictions.Specification
specs/replace-label-spec.mdreplace-labelsafe-output type — atomic label replacement via single REST callFormal Model
Predicates and invariants (illustrative notation)
Behavioral Coverage Map
P1-FieldRequiredTestFormalReplaceLabelP1_FieldRequiredP2-FieldMaxLengthTestFormalReplaceLabelP2_FieldMaxLengthP3-DefaultMaxFiveTestFormalReplaceLabelP3_DefaultMaxFiveP3-ValidationConfigTestFormalReplaceLabelP3_ValidationConfigFieldsP4-AllowlistEnforcementTestFormalReplaceLabelP4_AllowlistEnforcementP5-BlocklistPriorityTestFormalReplaceLabelP5_BlocklistPriorityP6-RemoveAllowlistTestFormalReplaceLabelP6_RemoveAllowlistP7-RequiredLabelsGateTestFormalReplaceLabelP7_RequiredLabelsGateP8-TitlePrefixGateTestFormalReplaceLabelP8_TitlePrefixGateP9-StagedFlagTestFormalReplaceLabelP9_StagedFlagOnConfigP9-StagedResultTestFormalReplaceLabelP9_StagedHandlerResultP10-LabelSetComputationTestFormalReplaceLabelP10_LabelSetComputationP11-IdempotentMissingRemoveTestFormalReplaceLabelP11_IdempotentMissingRemoveP12-LabelToAddAlwaysPresentTestFormalReplaceLabelP12_LabelToAddAlwaysPresentP13-HardVsSoftErrorsTestFormalReplaceLabelP13_HardVsSoftErrorsP14-CrossRepoRestrictionTestFormalReplaceLabelP14_CrossRepoRestrictionP15-TargetModeEnforcementTestFormalReplaceLabelP15_TargetModeEnforcementEdge-IdenticalLabelsTestFormalReplaceLabelEdge_BothLabelsIdenticalEdge-HTTP422TestFormalReplaceLabelEdge_NonExistentLabelHTTP422Edge-AliasFieldsTestFormalReplaceLabelEdge_ItemNumberAliasFieldsEdge-ConfigStructTestFormalReplaceLabelEdge_ReplaceLabelConfigStructFieldsPresentGenerated Test Suite
📄 `pkg/workflow/replace_label_formal_test.go` (1,043 lines, committed to repo)
Full file:
pkg/workflow/replace_label_formal_test.goUsage
pkg/workflow/replace_label_formal_test.gois present (committed this run).// stubhelpers with realgobwas/globand handler implementations.go test ./pkg/workflow/... -run FormalReplaceLabelContext
specs/replace-label-spec.mdWarning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
proxy.golang.orgSee Network Configuration for more information.