docs(comments): strip internal task/milestone/bundle bookkeeping from code comments
Remove project bookkeeping citations from shipped code comments across the solution: hyphenated task IDs (WP-14, StoreAndForward-025), milestone/task/ issue refs (M3, Task 4, Audit Log #23, #21), Bundle X task-bundle labels, and C/D/K/S/T phase labels. Comment text only — no code logic, string/log literals, or XML-doc structure changed. Genuine descriptions are preserved (only the citation is stripped), and technical lookalikes are retained (UTF-8, SHA-256, T00:00:00, M365, UTC-5, pre-C4/pre-C5 schema versions). Flagged by the new CommentChecker TaskReferenceInComment / TrackingReferenceInComment checks plus targeted grep passes; full solution builds clean, append-only guard tests pass.
This commit is contained in:
@@ -82,8 +82,8 @@ public static class CollisionDetector
|
||||
/// chain, and they are ALSO re-added — under the parent's name — by
|
||||
/// <see cref="CollectInheritedMembers"/>. Counting both yielded two distinct
|
||||
/// origins for the same canonical name and a spurious collision, which blocked
|
||||
/// every attempt to add an attribute/composition to a derived template
|
||||
/// (follow-up #3). Pass <c>false</c> only for the composed-module walk, where
|
||||
/// every attempt to add an attribute/composition to a derived template.
|
||||
/// Pass <c>false</c> only for the composed-module walk, where
|
||||
/// placeholder rows are the sole representation of a derived module's inherited
|
||||
/// members (that walk does not climb the composed template's parent chain).
|
||||
/// </param>
|
||||
|
||||
@@ -42,7 +42,7 @@ public class DiffService
|
||||
s => s.CanonicalName,
|
||||
ScriptsEqual);
|
||||
|
||||
// TemplateEngine-018: surface standalone connection endpoint/protocol/
|
||||
// Surface standalone connection endpoint/protocol/
|
||||
// failover drift. Per-attribute binding changes already show up under
|
||||
// AttributeChanges, but a connection's own ConfigurationJson /
|
||||
// BackupConfigurationJson / Protocol / FailoverRetryCount edits do not —
|
||||
@@ -119,7 +119,7 @@ public class DiffService
|
||||
a.CanonicalName == b.CanonicalName &&
|
||||
a.Value == b.Value &&
|
||||
a.DataType == b.DataType &&
|
||||
// #290: ElementDataType is part of the revision hash, so the diff must
|
||||
// ElementDataType is part of the revision hash, so the diff must
|
||||
// treat a List element-type change (e.g. Int32 → Double) with identical
|
||||
// JSON-encoded values as a Changed attribute — keeping the structured
|
||||
// diff in parity with the staleness hash.
|
||||
@@ -170,7 +170,7 @@ public class DiffService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TemplateEngine-018: produces a per-connection diff between two flattened
|
||||
/// Produces a per-connection diff between two flattened
|
||||
/// configurations, emitting Added / Removed / Changed entries keyed by the
|
||||
/// connection name. Mirrors the existing <see cref="ComputeEntityDiff{T}"/>
|
||||
/// shape used for attributes / alarms / scripts. Called by
|
||||
|
||||
@@ -831,7 +831,7 @@ public class FlatteningService
|
||||
ParameterDefinitions = script.ParameterDefinitions,
|
||||
ReturnDefinition = script.ReturnDefinition,
|
||||
MinTimeBetweenRuns = script.MinTimeBetweenRuns,
|
||||
// M2.5 (#9): per-script timeout rides along on the winning row.
|
||||
// Per-script timeout rides along on the winning row.
|
||||
// Scripts inherit/override at whole-row granularity (no per-field
|
||||
// merge), so this follows the same rule as the script body/MinTime.
|
||||
ExecutionTimeoutSeconds = script.ExecutionTimeoutSeconds,
|
||||
|
||||
@@ -85,7 +85,7 @@ public class RevisionHashService
|
||||
ParameterDefinitions = s.ParameterDefinitions,
|
||||
ReturnDefinition = s.ReturnDefinition,
|
||||
MinTimeBetweenRunsTicks = s.MinTimeBetweenRuns?.Ticks,
|
||||
// M2.5 (#9): include the per-script timeout so a change to it
|
||||
// Include the per-script timeout so a change to it
|
||||
// is detected as a configuration change (staleness/redeploy).
|
||||
ExecutionTimeoutSeconds = s.ExecutionTimeoutSeconds
|
||||
})
|
||||
@@ -176,7 +176,7 @@ public class RevisionHashService
|
||||
public string? Description { get; init; }
|
||||
/// <summary>
|
||||
/// For List attributes: the element scalar type name; null otherwise.
|
||||
/// Folded into the hash (#290) so a List element-type change (e.g.
|
||||
/// Folded into the hash so a List element-type change (e.g.
|
||||
/// Int32 → Double) with identical JSON-encoded values is detected as a
|
||||
/// staleness/revision change. Null for scalar attributes — and because
|
||||
/// the serializer ignores null properties
|
||||
@@ -258,7 +258,7 @@ public class RevisionHashService
|
||||
/// </summary>
|
||||
public string Code { get; init; } = string.Empty;
|
||||
/// <summary>
|
||||
/// M2.5 (#9): the per-script execution timeout in seconds (null = global).
|
||||
/// The per-script execution timeout in seconds (null = global).
|
||||
/// </summary>
|
||||
public int? ExecutionTimeoutSeconds { get; init; }
|
||||
/// <summary>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace ZB.MOM.WW.ScadaBridge.TemplateEngine;
|
||||
/// nor <see cref="TemplateAttribute.LockedInDerived"/> may be cleared after it has
|
||||
/// been set. The same one-way ratchet applies to alarms and scripts. This pins
|
||||
/// the design intent so a base template cannot retroactively re-allow derived
|
||||
/// overrides that were previously blocked (TemplateEngine-022).
|
||||
/// overrides that were previously blocked.
|
||||
///
|
||||
/// Override granularity:
|
||||
/// - Attributes: Value and Description overridable; DataType, ElementDataType and DataSourceReference fixed.
|
||||
@@ -135,7 +135,7 @@ public static class LockEnforcer
|
||||
/// flag change is legal. <c>LockedInDerived</c> follows the same one-way ratchet
|
||||
/// as <c>IsLocked</c> — once set on a base template, it cannot be cleared,
|
||||
/// otherwise derived templates that were previously blocked from overriding the
|
||||
/// field would become retroactively allowed (TemplateEngine-022).
|
||||
/// field would become retroactively allowed.
|
||||
/// </summary>
|
||||
/// <param name="originalLockedInDerived">Current <c>LockedInDerived</c> state.</param>
|
||||
/// <param name="proposedLockedInDerived">Proposed <c>LockedInDerived</c> state.</param>
|
||||
|
||||
@@ -5,7 +5,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
||||
namespace ZB.MOM.WW.ScadaBridge.TemplateEngine.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Enforces template deletion constraints (WP-25).
|
||||
/// Enforces template deletion constraints.
|
||||
/// Template deletion is blocked when:
|
||||
/// - Instances reference the template
|
||||
/// - Child templates reference it (as parent)
|
||||
@@ -78,10 +78,10 @@ public class TemplateDeletionService
|
||||
errors.Add($"Cannot delete template '{template.Name}': it is the base of {derivatives.Count} derived template(s) used in {details}{(derivatives.Count > 10 ? "..." : "")}. Remove those compositions first.");
|
||||
}
|
||||
|
||||
// Check 3: Other templates compose it directly (e.g., pre-Phase-3 data).
|
||||
// Check 3: Other templates compose it directly.
|
||||
// Read the Compositions navigation already loaded by GetAllTemplatesAsync
|
||||
// rather than issuing one GetCompositionsByTemplateIdAsync round-trip per
|
||||
// template (TemplateEngine-009) — this is the same source TemplateService
|
||||
// template — this is the same source TemplateService
|
||||
// .DeleteTemplateAsync uses for the equivalent check.
|
||||
var composingTemplates = allTemplates
|
||||
.SelectMany(t => t.Compositions
|
||||
|
||||
@@ -6,7 +6,7 @@ using ZB.MOM.WW.ScadaBridge.Commons.Types;
|
||||
namespace ZB.MOM.WW.ScadaBridge.TemplateEngine;
|
||||
|
||||
/// <summary>
|
||||
/// WP-5: Shared Script CRUD.
|
||||
/// Shared Script CRUD.
|
||||
/// System-wide scripts not associated with templates.
|
||||
/// Same parameter/return definition structure as template scripts.
|
||||
/// Includes syntax/structural validation (basic C# compilation check).
|
||||
@@ -67,7 +67,7 @@ public class SharedScriptService
|
||||
ReturnDefinition = returnDefinition
|
||||
};
|
||||
|
||||
// TemplateEngine-020: save the entity first so EF Core populates the
|
||||
// Save the entity first so EF Core populates the
|
||||
// auto-generated key, then write the audit row with the real
|
||||
// script.Id, then save the audit row. The pre-fix order logged
|
||||
// EntityId = "0" because the audit row was queued before
|
||||
|
||||
@@ -6,7 +6,7 @@ using ZB.MOM.WW.ScadaBridge.TemplateEngine.Flattening;
|
||||
namespace ZB.MOM.WW.ScadaBridge.TemplateEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Read-only AUTHORING resolver (M9/T26a). Given a template id and the full
|
||||
/// Read-only AUTHORING resolver. Given a template id and the full
|
||||
/// template lookup, computes the EFFECTIVE inherited member set fresh from the
|
||||
/// whole inheritance chain (root -> leaf, arbitrary depth, cycle-guarded via
|
||||
/// <see cref="TemplateResolver.BuildInheritanceChain"/>), annotated per member
|
||||
|
||||
@@ -104,11 +104,11 @@ public static class TemplateResolver
|
||||
/// Gets the inheritance chain from root ancestor to the specified template.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TemplateEngine-019: the parent walk uses the <see cref="int?"/>
|
||||
/// The parent walk uses the <see cref="int?"/>
|
||||
/// <see cref="Template.ParentTemplateId"/> directly — only a missing
|
||||
/// (<c>null</c>) value means "no parent". The legacy <c>0</c>-as-no-parent
|
||||
/// sentinel that was removed from <c>CycleDetector</c> in the
|
||||
/// TemplateEngine-013 fix had silently truncated chains whenever a real
|
||||
/// fix had silently truncated chains whenever a real
|
||||
/// template id of 0 appeared (e.g. import-staging / not-yet-saved rows);
|
||||
/// the duplicate-tolerant <c>BuildLookup</c> upstream means an Id of 0 is
|
||||
/// a valid node here and must walk the chain like any other.
|
||||
|
||||
@@ -29,7 +29,7 @@ public class TemplateService
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// WP-1: Template CRUD with Inheritance
|
||||
// Template CRUD with Inheritance
|
||||
// ========================================================================
|
||||
|
||||
/// <summary>
|
||||
@@ -75,7 +75,7 @@ public class TemplateService
|
||||
// collisions are enforced on every member-mutating call (AddAttribute,
|
||||
// AddAlarm, AddScript, AddComposition) and on rename in UpdateTemplate.
|
||||
|
||||
// TemplateEngine-020: save the entity first so EF Core populates the
|
||||
// Save the entity first so EF Core populates the
|
||||
// auto-generated key, then write the audit row with the real
|
||||
// template.Id, then save the audit row. The pre-fix order logged
|
||||
// EntityId = "0" because the audit row was queued before
|
||||
@@ -91,7 +91,7 @@ public class TemplateService
|
||||
|
||||
/// <summary>
|
||||
/// Updates a template's name and (optionally) description. Optional fields use
|
||||
/// leave-unchanged semantics so an omitted field is not silently wiped (followup #5):
|
||||
/// leave-unchanged semantics so an omitted field is not silently wiped:
|
||||
/// a <c>null</c> <paramref name="description"/> leaves the stored description as-is —
|
||||
/// pass an empty string to explicitly clear it. Parent template is immutable after
|
||||
/// creation; a <c>null</c> <paramref name="parentTemplateId"/> leaves it unchanged,
|
||||
@@ -165,8 +165,8 @@ public class TemplateService
|
||||
|
||||
// Deletion-constraint logic (instances / child / derived / composing
|
||||
// templates) lives in exactly one place — TemplateDeletionService — so a
|
||||
// future rule change cannot drift between two implementations
|
||||
// (TemplateEngine-014). TemplateService owns only the audit-logging side
|
||||
// future rule change cannot drift between two implementations.
|
||||
// TemplateService owns only the audit-logging side
|
||||
// effect, which the deletion service is unaware of.
|
||||
var deletionService = new Services.TemplateDeletionService(_repository);
|
||||
var deleteResult = await deletionService.DeleteTemplateAsync(templateId, cancellationToken);
|
||||
@@ -210,7 +210,7 @@ public class TemplateService
|
||||
// folder cannot collide with itself).
|
||||
if (template.FolderId != newFolderId)
|
||||
{
|
||||
// Sibling-name uniqueness at the destination (TemplateEngine-021),
|
||||
// Sibling-name uniqueness at the destination,
|
||||
// mirroring TemplateFolderService.MoveFolderAsync. A template move
|
||||
// changes only FolderId, so there is no inheritance- or
|
||||
// composition-graph cycle to detect (templates have no folder-
|
||||
@@ -261,7 +261,7 @@ public class TemplateService
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// WP-2: Attribute Definitions with Lock Flags
|
||||
// Attribute Definitions with Lock Flags
|
||||
// ========================================================================
|
||||
|
||||
/// <summary>
|
||||
@@ -278,7 +278,7 @@ public class TemplateService
|
||||
string user,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Defense-in-depth (#92): hoist the (DataType, ElementDataType, Value)
|
||||
// Defense-in-depth: hoist the (DataType, ElementDataType, Value)
|
||||
// guard — previously only enforced on the CLI/API path in
|
||||
// ManagementActor.ValidateAttributeTypes — into the service so the
|
||||
// Central UI's direct TemplateService write path shares one server-side
|
||||
@@ -306,14 +306,14 @@ public class TemplateService
|
||||
if (collisions.Count > 0)
|
||||
return Result<TemplateAttribute>.Failure(string.Join(" ", collisions));
|
||||
|
||||
// TemplateEngine-020: save-then-audit so the audit row carries the
|
||||
// Save-then-audit so the audit row carries the
|
||||
// real attribute Id rather than a literal "0".
|
||||
await _repository.AddTemplateAttributeAsync(attribute, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
await _auditService.LogAsync(user, "Create", "TemplateAttribute", attribute.Id.ToString(), attribute.Name, attribute, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Propagate the new member to derived descendants (#1/#2).
|
||||
// Propagate the new member to derived descendants.
|
||||
await ReconcileDescendantsAsync(templateId, user, cancellationToken);
|
||||
|
||||
return Result<TemplateAttribute>.Success(attribute);
|
||||
@@ -337,7 +337,7 @@ public class TemplateService
|
||||
if (existing == null)
|
||||
return Result<TemplateAttribute>.Failure($"Attribute with ID {attributeId} not found.");
|
||||
|
||||
// Defense-in-depth (#92): hoist the (DataType, ElementDataType, Value)
|
||||
// Defense-in-depth: hoist the (DataType, ElementDataType, Value)
|
||||
// guard out of ManagementActor.ValidateAttributeTypes so the Central UI's
|
||||
// direct TemplateService write path shares one server-side check. DataType
|
||||
// and ElementDataType are fixed by the defining level (not copied from the
|
||||
@@ -378,7 +378,7 @@ public class TemplateService
|
||||
// LockedInDerived is a one-way ratchet on base templates: once a base
|
||||
// marks an attribute LockedInDerived it cannot be cleared, otherwise
|
||||
// derived overrides that were previously blocked would become
|
||||
// retroactively legal (TemplateEngine-022). Only meaningful on base
|
||||
// retroactively legal. Only meaningful on base
|
||||
// templates — derived rows never carry an authoritative LockedInDerived.
|
||||
if (template?.IsDerived != true)
|
||||
{
|
||||
@@ -410,7 +410,7 @@ public class TemplateService
|
||||
await _auditService.LogAsync(user, "Update", "TemplateAttribute", attributeId.ToString(), existing.Name, existing, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Propagate the changed effective value to derived descendants (#1/#2).
|
||||
// Propagate the changed effective value to derived descendants.
|
||||
await ReconcileDescendantsAsync(existing.TemplateId, user, cancellationToken);
|
||||
|
||||
return Result<TemplateAttribute>.Success(existing);
|
||||
@@ -448,7 +448,7 @@ public class TemplateService
|
||||
await _auditService.LogAsync(user, "Delete", "TemplateAttribute", attributeId.ToString(), attribute.Name, null, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Remove the now-orphaned inherited placeholder from derived descendants (#1/#2).
|
||||
// Remove the now-orphaned inherited placeholder from derived descendants.
|
||||
await ReconcileDescendantsAsync(attribute.TemplateId, user, cancellationToken);
|
||||
|
||||
return Result<bool>.Success(true);
|
||||
@@ -459,7 +459,7 @@ public class TemplateService
|
||||
/// Returns a human-readable failure message (for <c>Result.Failure</c>), or
|
||||
/// <c>null</c> when the triple is valid. Mirrors the CLI/API-path guard in
|
||||
/// <c>ManagementActor.ValidateAttributeTypes</c> so both server write paths
|
||||
/// share one server-side check (#92), reusing <see cref="AttributeValueCodec"/>
|
||||
/// share one server-side check, reusing <see cref="AttributeValueCodec"/>
|
||||
/// for the element-type and value-decode logic:
|
||||
/// <list type="bullet">
|
||||
/// <item>DataType must be a defined enum value.</item>
|
||||
@@ -501,7 +501,7 @@ public class TemplateService
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// WP-3: Alarm Definitions
|
||||
// Alarm Definitions
|
||||
// ========================================================================
|
||||
|
||||
/// <summary>
|
||||
@@ -539,14 +539,14 @@ public class TemplateService
|
||||
if (collisions.Count > 0)
|
||||
return Result<TemplateAlarm>.Failure(string.Join(" ", collisions));
|
||||
|
||||
// TemplateEngine-020: save-then-audit so the audit row carries the
|
||||
// Save-then-audit so the audit row carries the
|
||||
// real alarm Id rather than a literal "0".
|
||||
await _repository.AddTemplateAlarmAsync(alarm, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
await _auditService.LogAsync(user, "Create", "TemplateAlarm", alarm.Id.ToString(), alarm.Name, alarm, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Propagate the new member to derived descendants (#1/#2).
|
||||
// Propagate the new member to derived descendants.
|
||||
await ReconcileDescendantsAsync(templateId, user, cancellationToken);
|
||||
|
||||
return Result<TemplateAlarm>.Success(alarm);
|
||||
@@ -601,7 +601,7 @@ public class TemplateService
|
||||
}
|
||||
}
|
||||
|
||||
// One-way LockedInDerived ratchet on base templates (TemplateEngine-022).
|
||||
// One-way LockedInDerived ratchet on base templates.
|
||||
if (template?.IsDerived != true)
|
||||
{
|
||||
var lockedInDerivedError = LockEnforcer.ValidateLockedInDerivedChange(
|
||||
@@ -631,7 +631,7 @@ public class TemplateService
|
||||
await _auditService.LogAsync(user, "Update", "TemplateAlarm", alarmId.ToString(), existing.Name, existing, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Propagate the changed effective value to derived descendants (#1/#2).
|
||||
// Propagate the changed effective value to derived descendants.
|
||||
await ReconcileDescendantsAsync(existing.TemplateId, user, cancellationToken);
|
||||
|
||||
return Result<TemplateAlarm>.Success(existing);
|
||||
@@ -668,14 +668,14 @@ public class TemplateService
|
||||
await _auditService.LogAsync(user, "Delete", "TemplateAlarm", alarmId.ToString(), alarm.Name, null, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Remove the now-orphaned inherited placeholder from derived descendants (#1/#2).
|
||||
// Remove the now-orphaned inherited placeholder from derived descendants.
|
||||
await ReconcileDescendantsAsync(alarm.TemplateId, user, cancellationToken);
|
||||
|
||||
return Result<bool>.Success(true);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// WP-4: Script Definitions
|
||||
// Script Definitions
|
||||
// ========================================================================
|
||||
|
||||
/// <summary>
|
||||
@@ -709,14 +709,14 @@ public class TemplateService
|
||||
if (collisions.Count > 0)
|
||||
return Result<TemplateScript>.Failure(string.Join(" ", collisions));
|
||||
|
||||
// TemplateEngine-020: save-then-audit so the audit row carries the
|
||||
// Save-then-audit so the audit row carries the
|
||||
// real script Id rather than a literal "0".
|
||||
await _repository.AddTemplateScriptAsync(script, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
await _auditService.LogAsync(user, "Create", "TemplateScript", script.Id.ToString(), script.Name, script, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Propagate the new member to derived descendants (#1/#2).
|
||||
// Propagate the new member to derived descendants.
|
||||
await ReconcileDescendantsAsync(templateId, user, cancellationToken);
|
||||
|
||||
return Result<TemplateScript>.Success(script);
|
||||
@@ -768,7 +768,7 @@ public class TemplateService
|
||||
}
|
||||
}
|
||||
|
||||
// One-way LockedInDerived ratchet on base templates (TemplateEngine-022).
|
||||
// One-way LockedInDerived ratchet on base templates.
|
||||
if (template?.IsDerived != true)
|
||||
{
|
||||
var lockedInDerivedError = LockEnforcer.ValidateLockedInDerivedChange(
|
||||
@@ -787,7 +787,7 @@ public class TemplateService
|
||||
existing.TriggerType = proposed.TriggerType;
|
||||
existing.TriggerConfiguration = proposed.TriggerConfiguration;
|
||||
existing.MinTimeBetweenRuns = proposed.MinTimeBetweenRuns;
|
||||
// M2.5 (#9): per-script execution timeout is an overridable field.
|
||||
// Per-script execution timeout is an overridable field.
|
||||
existing.ExecutionTimeoutSeconds = proposed.ExecutionTimeoutSeconds;
|
||||
existing.ParameterDefinitions = proposed.ParameterDefinitions;
|
||||
existing.ReturnDefinition = proposed.ReturnDefinition;
|
||||
@@ -802,7 +802,7 @@ public class TemplateService
|
||||
await _auditService.LogAsync(user, "Update", "TemplateScript", scriptId.ToString(), existing.Name, existing, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Propagate the changed effective value to derived descendants (#1/#2).
|
||||
// Propagate the changed effective value to derived descendants.
|
||||
await ReconcileDescendantsAsync(existing.TemplateId, user, cancellationToken);
|
||||
|
||||
return Result<TemplateScript>.Success(existing);
|
||||
@@ -839,14 +839,14 @@ public class TemplateService
|
||||
await _auditService.LogAsync(user, "Delete", "TemplateScript", scriptId.ToString(), script.Name, null, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Remove the now-orphaned inherited placeholder from derived descendants (#1/#2).
|
||||
// Remove the now-orphaned inherited placeholder from derived descendants.
|
||||
await ReconcileDescendantsAsync(script.TemplateId, user, cancellationToken);
|
||||
|
||||
return Result<bool>.Success(true);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// WP-6: Composition with Recursive Nesting
|
||||
// Composition with Recursive Nesting
|
||||
// ========================================================================
|
||||
|
||||
/// <summary>
|
||||
@@ -911,7 +911,7 @@ public class TemplateService
|
||||
// No global name pre-check: derived templates store their contained
|
||||
// (slot) name, which need only be unique within the owner — and that is
|
||||
// already enforced above and by the (TemplateId, InstanceName) index.
|
||||
// TemplateEngine-020: CreateCascadedCompositionAsync already saves the
|
||||
// CreateCascadedCompositionAsync already saves the
|
||||
// composition row, so composition.Id is populated by the time control
|
||||
// returns here — the audit row therefore carries the real Id instead
|
||||
// of the pre-fix literal "0".
|
||||
@@ -1035,8 +1035,8 @@ public class TemplateService
|
||||
if (composition == null)
|
||||
return Result<bool>.Failure($"Composition with ID {compositionId} not found.");
|
||||
|
||||
// Identify the slot-owned derived template (post Phase-3 migration this is the
|
||||
// typical case; pre-migration the composition may still point at a base).
|
||||
// Identify the slot-owned derived template (this is now the
|
||||
// typical case; pre-migration data may still have the composition point at a base).
|
||||
var composedTemplate = await _repository.GetTemplateByIdAsync(composition.ComposedTemplateId, cancellationToken);
|
||||
|
||||
await _repository.DeleteTemplateCompositionAsync(compositionId, cancellationToken);
|
||||
@@ -1132,7 +1132,7 @@ public class TemplateService
|
||||
// other member types (TemplateNativeAlarmSource), and the inheritance
|
||||
// resolver + staleness summary count them — so materialize their inherited
|
||||
// placeholders here too, or a freshly-composed derived template reports
|
||||
// stale for every inherited native source (follow-up #1/#2).
|
||||
// stale for every inherited native source.
|
||||
foreach (var src in baseTemplate.NativeAlarmSources)
|
||||
{
|
||||
derived.NativeAlarmSources.Add(new TemplateNativeAlarmSource(src.Name)
|
||||
@@ -1151,15 +1151,15 @@ public class TemplateService
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Inherited-member propagation & resync (follow-up #1/#2)
|
||||
// Inherited-member propagation & resync
|
||||
// ========================================================================
|
||||
//
|
||||
// A derived template stores IsInherited placeholder rows mirroring the
|
||||
// members it inherits. BuildDerivedTemplate materializes them at compose time,
|
||||
// but a member ADDED / UPDATED / REMOVED on a base AFTER the derivation
|
||||
// existed never reached the children — so derived row-sets drifted incomplete
|
||||
// (the editor's editable tabs missed inherited members; #1) and stored rows
|
||||
// diverged from the resolved set (#2). Two mechanisms keep them in sync:
|
||||
// (the editor's editable tabs missed inherited members) and stored rows
|
||||
// diverged from the resolved set. Two mechanisms keep them in sync:
|
||||
// • ReconcileDescendantsAsync — called automatically after every base member
|
||||
// mutation, propagates the change to the whole derived subtree.
|
||||
// • ResyncInheritedMembersAsync — an explicit operator action (CLI + UI)
|
||||
@@ -1573,7 +1573,7 @@ public class TemplateService
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// WP-7: Path-Qualified Canonical Naming (via TemplateResolver)
|
||||
// Path-Qualified Canonical Naming (via TemplateResolver)
|
||||
// ========================================================================
|
||||
|
||||
/// <summary>
|
||||
@@ -1591,12 +1591,12 @@ public class TemplateService
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// WP-8/9/10/11: Override validation (integrated into Update* methods above)
|
||||
// Override validation (integrated into Update* methods above)
|
||||
// ========================================================================
|
||||
|
||||
/// <summary>
|
||||
/// Validates whether overriding a member by canonical name is allowed.
|
||||
/// Used for composition overrides (WP-11) and inheritance overrides (WP-10).
|
||||
/// Used for composition overrides and inheritance overrides.
|
||||
/// </summary>
|
||||
/// <param name="templateId">ID of the template.</param>
|
||||
/// <param name="canonicalName">Canonical name of the member to validate.</param>
|
||||
@@ -1625,7 +1625,7 @@ public class TemplateService
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// WP-12: Naming Collision Detection
|
||||
// Naming Collision Detection
|
||||
// ========================================================================
|
||||
|
||||
/// <summary>
|
||||
@@ -1647,7 +1647,7 @@ public class TemplateService
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// WP-13: Graph Acyclicity
|
||||
// Graph Acyclicity
|
||||
// ========================================================================
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace ZB.MOM.WW.ScadaBridge.TemplateEngine.Validation;
|
||||
|
||||
/// <summary>
|
||||
/// The authoritative design-time / deploy-blocking script gate. Delegates to the
|
||||
/// shared <see cref="ZB.MOM.WW.ScadaBridge.ScriptAnalysis"/> analyzer (M3.2): a
|
||||
/// shared <see cref="ZB.MOM.WW.ScadaBridge.ScriptAnalysis"/> analyzer: a
|
||||
/// real Roslyn semantic forbidden-API verdict
|
||||
/// (<see cref="ScriptTrustValidator.FindViolations(string, System.Collections.Generic.IEnumerable{Microsoft.CodeAnalysis.MetadataReference})"/>)
|
||||
/// followed by a real CSharpScript compile against the
|
||||
|
||||
@@ -65,7 +65,7 @@ public class SemanticValidator
|
||||
attributeMap.TryAdd(a.CanonicalName, a);
|
||||
}
|
||||
|
||||
// List-attribute type semantics (MV-5): element-type cardinality + default
|
||||
// List-attribute type semantics: element-type cardinality + default
|
||||
// value parseability. Trigger-operand rejection (rule 3) is handled below
|
||||
// by the existing NumericDataTypes guard (List is never numeric).
|
||||
ValidateListAttributes(configuration, errors);
|
||||
@@ -276,7 +276,7 @@ public class SemanticValidator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MV-5 — semantic validation of List-attribute type configuration. Two rules:
|
||||
/// Semantic validation of List-attribute type configuration. Two rules:
|
||||
/// <list type="number">
|
||||
/// <item><b>Element-type cardinality.</b> A <see cref="DataType.List"/> attribute
|
||||
/// must carry a non-empty <see cref="ResolvedAttribute.ElementDataType"/> that is
|
||||
@@ -369,7 +369,7 @@ public class SemanticValidator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #21 — Argument-type validation. Compares each positionally-matched call
|
||||
/// Argument-type validation. Compares each positionally-matched call
|
||||
/// argument expression against the target's declared parameter type and
|
||||
/// flags only CLEAR cross-category mismatches.
|
||||
///
|
||||
@@ -419,7 +419,7 @@ public class SemanticValidator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #20 — Return-type validation. When a call result is assigned directly
|
||||
/// Return-type validation. When a call result is assigned directly
|
||||
/// into a typed local declaration (<c>int x = CallScript(...)</c>,
|
||||
/// <c>bool b = await CallShared(...)</c>), compares the LHS declared type
|
||||
/// against the target's declared return type and flags clear mismatches.
|
||||
@@ -473,7 +473,7 @@ public class SemanticValidator
|
||||
{
|
||||
// Per-parameter declared TYPE in declared order (raw type strings).
|
||||
// One entry per parameter, so the existing count check is preserved
|
||||
// while #21 also has the types it needs for positional matching.
|
||||
// and positional matching has the types it needs.
|
||||
var parameters = ParseParameterTypes(script.ParameterDefinitions);
|
||||
result[script.CanonicalName] = parameters;
|
||||
}
|
||||
@@ -608,7 +608,7 @@ public class SemanticValidator
|
||||
IsShared = isShared,
|
||||
ArgumentCount = argExpressions.Count,
|
||||
ArgumentExpressions = argExpressions,
|
||||
// #20: the declared type the result is assigned into, if the
|
||||
// The declared type the result is assigned into, if the
|
||||
// call is the whole initializer of a typed local declaration.
|
||||
AssignedToType = ExtractAssignedToType(code, idx)
|
||||
});
|
||||
@@ -712,7 +712,7 @@ public class SemanticValidator
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #20 inference — looks backwards from the call's start index for a typed
|
||||
/// Inference — looks backwards from the call's start index for a typed
|
||||
/// local declaration whose initializer is exactly this call (optionally
|
||||
/// preceded by <c>await</c>). The call may be qualified by a simple receiver
|
||||
/// (<c>Instance.</c>, <c>Scripts.</c>, <c>Parent.</c>,
|
||||
@@ -842,7 +842,7 @@ public class SemanticValidator
|
||||
return start;
|
||||
}
|
||||
|
||||
// ── Script-level type vocabulary (#20/#21) ──────────────────────────────
|
||||
// ── Script-level type vocabulary ──────────────────────────────
|
||||
//
|
||||
// The template scripting "type system" exposed in ParameterDefinitions /
|
||||
// ReturnDefinition is a small set: String, Integer, Float, Boolean, plus
|
||||
@@ -1018,7 +1018,7 @@ public class SemanticValidator
|
||||
/// <summary>
|
||||
/// The declared type token the call result is assigned into, when the
|
||||
/// call is the whole initializer of a typed local declaration; otherwise
|
||||
/// null (var/untyped/unused/expression-embedded). Used by #20.
|
||||
/// null (var/untyped/unused/expression-embedded).
|
||||
/// </summary>
|
||||
public string? AssignedToType { get; init; }
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace ZB.MOM.WW.ScadaBridge.TemplateEngine.Validation;
|
||||
/// 7. Connection binding completeness — every data-sourced attribute must have a binding,
|
||||
/// and (on the deploy path) the bound connection must exist on the target site.
|
||||
/// Severity is context-dependent: a non-blocking Warning at template design time
|
||||
/// (bindings are set later) and a deploy-gating Error when enforced (M2.8 / #23).
|
||||
/// 8. List-attribute type semantics (MV-5, via <see cref="SemanticValidator"/>):
|
||||
/// (bindings are set later) and a deploy-gating Error when enforced.
|
||||
/// 8. List-attribute type semantics (via <see cref="SemanticValidator"/>):
|
||||
/// element-type cardinality, default-value parseability, and trigger-operand
|
||||
/// rejection for List attributes.
|
||||
/// 9. Does NOT verify tag path resolution on devices
|
||||
@@ -61,7 +61,7 @@ public class ValidationService
|
||||
/// <c>null</c> skips the capability check (its absence makes the check inert).
|
||||
/// </param>
|
||||
/// <param name="enforceConnectionBindings">
|
||||
/// M2.8 (#23): controls the severity of the connection-binding-completeness check.
|
||||
/// Controls the severity of the connection-binding-completeness check.
|
||||
/// <para>
|
||||
/// <c>false</c> (default) — template DESIGN-TIME: a data-sourced attribute that is
|
||||
/// not yet bound produces only a non-blocking <c>Warning</c>. Bindings are set later,
|
||||
@@ -77,7 +77,7 @@ public class ValidationService
|
||||
/// </para>
|
||||
/// </param>
|
||||
/// <param name="siteConnectionNames">
|
||||
/// M2.8 (#23): optional set of the data-connection names that actually exist on the
|
||||
/// Optional set of the data-connection names that actually exist on the
|
||||
/// target site (computed by the deploy pipeline from the site's loaded connections,
|
||||
/// mirroring <paramref name="alarmCapableConnectionNames"/>). When supplied (and
|
||||
/// <paramref name="enforceConnectionBindings"/> is <c>true</c>), every bound
|
||||
@@ -85,7 +85,7 @@ public class ValidationService
|
||||
/// is caught. <c>null</c> skips the "exists at site" half (it stays inert).
|
||||
/// </param>
|
||||
/// <param name="resolveSchemaRef">
|
||||
/// M9-T32b: optional JSON-Schema <c>$ref</c> resolution seam mapping a
|
||||
/// Optional JSON-Schema <c>$ref</c> resolution seam mapping a
|
||||
/// <c>lib:Name</c> reference target's name to the referenced schema JSON (or
|
||||
/// <c>null</c> when the library entry does not exist). Supplied on the deploy path
|
||||
/// (backed by <c>ISharedSchemaRepository</c>) so a dangling/cyclic/over-depth
|
||||
@@ -123,7 +123,7 @@ public class ValidationService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// M9-T32b — JSON-Schema <c>$ref</c> resolution check. Parses every script
|
||||
/// JSON-Schema <c>$ref</c> resolution check. Parses every script
|
||||
/// parameter/return schema (instance scripts and the supplied shared scripts)
|
||||
/// through <see cref="InboundApiSchema.ParseWithRefs"/>, resolving any
|
||||
/// <c>{"$ref":"lib:Name"}</c> reference via <paramref name="resolveSchemaRef"/>.
|
||||
@@ -191,7 +191,7 @@ public class ValidationService
|
||||
// Keep the lib:-qualified pointer name SEPARATE from the diagnostic
|
||||
// reason so the message reads "schema 'lib:Foo' could not be resolved
|
||||
// (cyclic reference)" rather than embedding the annotation inside the
|
||||
// lib:-looking string (M9-T32b code-review MINOR).
|
||||
// lib:-looking string.
|
||||
var reasonSuffix = missing.Reason is null ? string.Empty : $" ({missing.Reason})";
|
||||
errors.Add(ValidationEntry.Error(ValidationCategory.SchemaReference,
|
||||
$"Script '{scriptName}' {schemaLabel} references schema 'lib:{missing.Name}' which could not be resolved{reasonSuffix}.",
|
||||
@@ -416,7 +416,7 @@ public class ValidationService
|
||||
|
||||
if (string.IsNullOrWhiteSpace(expression))
|
||||
{
|
||||
// M9-T28a: the blank-expression finding is the only advisory one. Under the
|
||||
// The blank-expression finding is the only advisory one. Under the
|
||||
// default Advisory kind it stays a non-blocking warning (it merely never fires);
|
||||
// under Strict it is promoted to a deploy-blocking error. Pure escalation —
|
||||
// the message and category are unchanged.
|
||||
@@ -475,7 +475,7 @@ public class ValidationService
|
||||
|
||||
/// <summary>
|
||||
/// Reads the optional <c>"analysisKind"</c> discriminator from a trigger
|
||||
/// configuration (M9-T28a). <c>true</c> only when the value is the case-insensitive
|
||||
/// configuration. <c>true</c> only when the value is the case-insensitive
|
||||
/// literal <c>"Strict"</c>; everything else — a missing key, the literal
|
||||
/// <c>"Advisory"</c>, any other value, or malformed JSON — defaults to Advisory
|
||||
/// (<c>false</c>), preserving today's behavior exactly.
|
||||
@@ -587,7 +587,7 @@ public class ValidationService
|
||||
/// attributes (<see cref="ResolvedAttribute.DataSourceReference"/> != <c>null</c>)
|
||||
/// require a binding; static attributes are never flagged.
|
||||
///
|
||||
/// M2.8 (#23): the severity is context-dependent (see <paramref name="enforce"/>).
|
||||
/// The severity is context-dependent (see <paramref name="enforce"/>).
|
||||
/// At template design time (<c>enforce == false</c>) an unbound data-sourced
|
||||
/// attribute is legitimate (bindings are set later) so it is only a non-blocking
|
||||
/// <c>Warning</c>. On the deploy path (<c>enforce == true</c>) an unbound
|
||||
|
||||
Reference in New Issue
Block a user