universal-dev-standards 5.8.0 → 5.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,55 @@
1
+ # UDS Language Packs
2
+
3
+ Language packs provide migration risk labels for specific source→target language pairs.
4
+ They extend the core `feature-manifest-standard` without polluting the core standard.
5
+
6
+ ## Naming Convention
7
+
8
+ ```
9
+ language-pack-<source>-to-<target>.ai.yaml
10
+ ```
11
+
12
+ Examples:
13
+ - `language-pack-php-to-csharp.ai.yaml`
14
+ - `language-pack-java-to-go.ai.yaml`
15
+ - `language-pack-python-to-rust.ai.yaml`
16
+
17
+ ## Available Language Packs
18
+
19
+ | Pack | Source | Target | Labels |
20
+ |------|--------|--------|--------|
21
+ | [language-pack-php-to-csharp.ai.yaml](language-pack-php-to-csharp.ai.yaml) | PHP | C# (ASP.NET Core) | SESSION_HANDLING, ORM_DIFFERENCES, TIMEZONE_HANDLING, FILE_UPLOAD_PATH, REGEX_DIFFERENCES, ARRAY_FUNCTIONS, EXCEPTION_HIERARCHY |
22
+
23
+ ## Usage
24
+
25
+ Reference language pack risk labels in `feature-manifest.yaml` alongside generic labels:
26
+
27
+ ```yaml
28
+ features:
29
+ - id: FM-001
30
+ name: UserLogin
31
+ migration_risks:
32
+ - SESSION_HANDLING # from language-pack-php-to-csharp
33
+ - NULL_SEMANTICS # from generic risks (feature-manifest-standard)
34
+ - ASYNC_MODEL # from generic risks
35
+ ```
36
+
37
+ ## Generic vs Language Pack Labels
38
+
39
+ | Type | Source | When to use |
40
+ |------|--------|-------------|
41
+ | Generic | `feature-manifest-standard.migration_risks.generic` | All migration projects |
42
+ | Language Pack | `ai/language-packs/<pack>.ai.yaml` | Specific source→target pairs |
43
+
44
+ ## Creating a New Language Pack
45
+
46
+ 1. Copy the structure from an existing pack
47
+ 2. Replace `source`, `target`, and `migration_risks` with the new pair's specifics
48
+ 3. Each risk label should have: `label`, `description`, `details` (optional but recommended)
49
+ 4. Submit via pull request to UDS with evidence from real migration projects
50
+
51
+ ## Architecture Decision
52
+
53
+ Language packs were separated from the core `feature-manifest-standard` in UDS v1.1.0
54
+ (XSPEC-203) to keep the core standard language-agnostic. See `ai/standards/feature-manifest-standard.ai.yaml`
55
+ `migration_risks.language_packs` for the extension point declaration.
@@ -0,0 +1,83 @@
1
+ # Language Pack: PHP → C# (ASP.NET Core) Migration Risks
2
+ # Migrated from: feature-manifest-standard v1.0.0 core standard
3
+ # Use with: feature-manifest.yaml features[].migration_risks
4
+
5
+ language_pack:
6
+ id: php-to-csharp
7
+ source: php
8
+ target: csharp
9
+ meta:
10
+ version: "1.0.0"
11
+ updated: "2026-05-13"
12
+ description: PHP to C# (ASP.NET Core) migration risk labels
13
+ migrated_from: "feature-manifest-standard v1.0.0 migration_risks.php_to_csharp"
14
+ references:
15
+ - "XSPEC-203: Language Pack Architecture"
16
+
17
+ migration_risks:
18
+ - label: SESSION_HANDLING
19
+ description: PHP session → ASP.NET Core Session/Cookie middleware differences
20
+ details: |
21
+ PHP sessions are file-backed by default and rely on PHPSESSID cookie.
22
+ ASP.NET Core uses IDistributedCache (Redis/SQL) backed sessions.
23
+ Check: session_start(), $_SESSION usage → ISession / IDistributedCache
24
+
25
+ - label: ORM_DIFFERENCES
26
+ description: Eloquent ORM → Entity Framework behavioral differences (lazy loading, conventions)
27
+ details: |
28
+ Eloquent uses ActiveRecord pattern; EF Core uses DataMapper/Unit of Work.
29
+ Lazy loading is opt-in in EF Core (vs default in Eloquent).
30
+ Check: Model relationships, ->with() eager loading, timestamps conventions
31
+
32
+ - label: TIMEZONE_HANDLING
33
+ description: PHP timezone functions → .NET DateTimeOffset handling
34
+ details: |
35
+ PHP date() and strtotime() are timezone-sensitive via date_default_timezone_set().
36
+ .NET uses DateTimeOffset for timezone-aware datetimes; DateTime is ambiguous.
37
+ Check: date(), strtotime(), Carbon usage → DateTimeOffset, TimeZoneInfo
38
+
39
+ - label: FILE_UPLOAD_PATH
40
+ description: PHP $_FILES superglobal → ASP.NET Core IFormFile interface
41
+ details: |
42
+ PHP uses $_FILES superglobal with move_uploaded_file().
43
+ ASP.NET Core uses IFormFile with CopyToAsync() and streaming.
44
+ Check: $_FILES, move_uploaded_file(), file validation logic
45
+
46
+ - label: REGEX_DIFFERENCES
47
+ description: PHP PCRE syntax vs .NET Regex syntax differences
48
+ details: |
49
+ PHP uses PCRE with delimiters (e.g., '/pattern/i'); .NET has no delimiters.
50
+ Named groups: PHP (?P<name>) vs .NET (?<name>).
51
+ Unicode properties and some PCRE extensions differ.
52
+ Check: preg_match(), preg_replace(), preg_split() usage
53
+
54
+ - label: ARRAY_FUNCTIONS
55
+ description: PHP array_* functions → LINQ equivalents
56
+ details: |
57
+ PHP array functions are procedural; .NET uses LINQ extension methods.
58
+ array_map() → .Select(); array_filter() → .Where(); array_reduce() → .Aggregate()
59
+ array_unique() → .Distinct(); usort() → .OrderBy()
60
+ Check: array_map, array_filter, array_reduce, usort, array_column usage
61
+
62
+ - label: EXCEPTION_HIERARCHY
63
+ description: PHP exception hierarchy vs .NET exception hierarchy differences
64
+ details: |
65
+ PHP: Exception → RuntimeException → InvalidArgumentException etc.
66
+ .NET: Exception → SystemException / ApplicationException → specific types
67
+ PHP allows catching multiple types with | (PHP 8+); .NET uses catch blocks.
68
+ Check: try/catch blocks, custom exception classes, exception type mapping
69
+
70
+ usage_example: |
71
+ # In feature-manifest.yaml:
72
+ features:
73
+ - id: FM-001
74
+ name: UserLogin
75
+ migration_risks:
76
+ - SESSION_HANDLING # from this language pack
77
+ - NULL_SEMANTICS # from generic risks (feature-manifest-standard)
78
+
79
+ - id: FM-007
80
+ name: OrderCancellation
81
+ migration_risks:
82
+ - ORM_DIFFERENCES # from this language pack
83
+ - ASYNC_MODEL # from generic risks
@@ -4,38 +4,32 @@
4
4
  standard:
5
5
  id: behavior-snapshot
6
6
  name: Behavior Snapshot Standard
7
- description: HTTP request/response golden file format for migration parity verification and refactoring characterization; defines snapshot schema, parity gate, and Gate 0 protocol
7
+ description: Multi-modal golden file format for migration parity verification and refactoring characterization; supports HTTP, CLI, File, and Event adapters; defines snapshot schema, parity gate, and Gate 0 protocol
8
8
 
9
9
  meta:
10
- version: "1.0.0"
11
- updated: "2026-05-12"
10
+ version: "1.1.0"
11
+ updated: "2026-05-13"
12
12
  source: core/behavior-snapshot.md
13
13
  references:
14
14
  - "XSPEC-201: Refactor/Migration Completeness Protocol"
15
+ - "XSPEC-203: Language Pack Architecture (multi-modal adapter extension)"
15
16
  - "Michael Feathers: Working Effectively with Legacy Code (characterization tests)"
16
17
  - "Golden Master Testing pattern"
17
18
 
18
19
  snapshot_schema:
19
20
  description: Format of a single snapshot JSON file in .snapshots/<feature-id>/<scenario>.json
20
21
  required_fields:
22
+ - name: adapter
23
+ type: string
24
+ description: "Snapshot adapter type: http (default) | cli | file | event"
25
+ default: "http"
26
+ backward_compat: "Omitting adapter field is equivalent to adapter: http — existing snapshots remain valid"
21
27
  - name: feature_id
22
28
  type: string
23
29
  description: FM-NNN from feature-manifest.yaml
24
30
  - name: scenario
25
31
  type: string
26
32
  description: "Scenario name (snake_case): happy_path, not_found, invalid_credentials, etc."
27
- - name: request
28
- type: object
29
- fields:
30
- method: "HTTP method (GET|POST|PUT|PATCH|DELETE)"
31
- path: "URL path (no base URL)"
32
- headers: "Optional request headers (omit auth tokens — use placeholder)"
33
- body: "Optional request body (JSON)"
34
- - name: response
35
- type: object
36
- fields:
37
- status: "HTTP status code (integer)"
38
- body: "Response body (JSON object)"
39
33
  - name: ignore_fields
40
34
  type: list
41
35
  description: |
@@ -43,8 +37,9 @@ standard:
43
37
  Use for legitimately non-deterministic values: timestamps, tokens, IDs.
44
38
  Do NOT use to hide business logic differences.
45
39
 
46
- example: |
40
+ http_example: |
47
41
  {
42
+ "adapter": "http",
48
43
  "feature_id": "FM-007",
49
44
  "scenario": "happy_path",
50
45
  "request": {
@@ -64,18 +59,108 @@ standard:
64
59
  "ignore_fields": ["refund_id", "cancelled_at"]
65
60
  }
66
61
 
62
+ adapters:
63
+ description: Adapter schemas for different software interaction types. Choose based on how the feature interacts with the outside world.
64
+
65
+ http:
66
+ description: HTTP request/response adapter — for web services and REST APIs (default)
67
+ fields:
68
+ request:
69
+ method: "HTTP method (GET|POST|PUT|PATCH|DELETE)"
70
+ path: "URL path (no base URL)"
71
+ headers: "Optional request headers (omit auth tokens — use placeholder)"
72
+ body: "Optional request body (JSON)"
73
+ response:
74
+ status: "HTTP status code (integer)"
75
+ body: "Response body (JSON object)"
76
+ when_to_use: "Feature is triggered by HTTP request and returns HTTP response"
77
+
78
+ cli:
79
+ description: CLI tool adapter — for command-line tools, scripts, and batch processors
80
+ fields:
81
+ args: "Command arguments array (excluding the program name itself)"
82
+ stdin: "Standard input string (null if the command reads no stdin)"
83
+ stdout: "Expected standard output string"
84
+ stderr: "Expected standard error string (empty string if none expected)"
85
+ exit_code: "Expected exit code (integer: 0 = success)"
86
+ when_to_use: "Feature is invoked via command-line arguments and produces stdout/stderr output"
87
+ example: |
88
+ {
89
+ "adapter": "cli",
90
+ "feature_id": "FM-012",
91
+ "scenario": "convert_csv_to_json",
92
+ "args": ["convert", "--input", "data.csv", "--format", "json"],
93
+ "stdin": null,
94
+ "stdout": "{\"rows\": 42, \"status\": \"ok\"}",
95
+ "stderr": "",
96
+ "exit_code": 0,
97
+ "ignore_fields": []
98
+ }
99
+
100
+ file:
101
+ description: File I/O adapter — for batch processors, report generators, and data pipelines
102
+ fields:
103
+ input_files: "List of input file descriptors: {path, content_hash}"
104
+ output_files: "List of expected output file descriptors: {path, content_hash}"
105
+ content_hash_format: "sha256:<hex> — use fixtures for deterministic input; capture hash from reference run for expected output"
106
+ when_to_use: "Feature reads input files and produces output files (no HTTP or CLI interaction)"
107
+ example: |
108
+ {
109
+ "adapter": "file",
110
+ "feature_id": "FM-015",
111
+ "scenario": "generate_monthly_report",
112
+ "input_files": [
113
+ { "path": "fixtures/sales_2026_04.csv", "content_hash": "sha256:abc123" }
114
+ ],
115
+ "output_files": [
116
+ { "path": "output/report_2026_04.pdf", "content_hash": "sha256:def456" }
117
+ ],
118
+ "ignore_fields": []
119
+ }
120
+
121
+ event:
122
+ description: Event/message adapter — for event-driven systems, message queues, and daemons
123
+ fields:
124
+ trigger: "The triggering event or message: {type, queue/topic, payload}"
125
+ expected_state_changes: "List of expected database/state changes: {entity, field, from, to}"
126
+ expected_side_effects: "List of expected side effects using standard labels: EMAIL_SENT, QUEUE_MESSAGE_PUBLISHED, FILE_WRITTEN, HTTP_CALL_MADE"
127
+ when_to_use: "Feature is triggered by an event/message and produces state changes or side effects"
128
+ example: |
129
+ {
130
+ "adapter": "event",
131
+ "feature_id": "FM-020",
132
+ "scenario": "order_placed_triggers_inventory_deduction",
133
+ "trigger": {
134
+ "type": "message",
135
+ "queue": "orders.placed",
136
+ "payload": { "order_id": "ORD-001", "product_id": "PROD-007", "quantity": 1 }
137
+ },
138
+ "expected_state_changes": [
139
+ { "entity": "inventory", "field": "quantity", "from": 10, "to": 9 }
140
+ ],
141
+ "expected_side_effects": ["EMAIL_SENT", "QUEUE_MESSAGE_PUBLISHED"],
142
+ "ignore_fields": ["processed_at", "message_id"]
143
+ }
144
+
67
145
  directory_structure:
68
146
  root: ".snapshots/"
69
147
  layout: ".snapshots/<feature-id>/<scenario>.json"
70
148
  example: |
71
149
  .snapshots/
72
- FM-001-UserLogin/
150
+ FM-001-UserLogin/ ← http adapter
73
151
  happy_path.json
74
152
  invalid_credentials.json
75
- FM-007-OrderCancellation/
153
+ FM-007-OrderCancellation/ ← http adapter
76
154
  happy_path.json
77
155
  order_not_found.json
78
156
  MANUAL-refund_webhook.json
157
+ FM-012-ConvertCsv/ ← cli adapter
158
+ convert_csv_to_json.json
159
+ missing_input_file.json
160
+ FM-015-MonthlyReport/ ← file adapter
161
+ generate_monthly_report.json
162
+ FM-020-InventoryDeduction/ ← event adapter
163
+ order_placed_triggers_inventory_deduction.json
79
164
  manual_prefix:
80
165
  description: "Files prefixed MANUAL- contain manually authored snapshots (cannot be auto-recorded)"
81
166
  examples:
@@ -161,6 +246,25 @@ standard:
161
246
  Fix parity failures before promoting — they represent behavioral divergence.
162
247
  priority: required
163
248
 
249
+ - id: adapter-selection
250
+ trigger: creating a behavior snapshot
251
+ instruction: |
252
+ Select the adapter matching the feature's interaction type.
253
+ Use http ONLY for actual HTTP endpoint features.
254
+ Use cli for command-line tool features.
255
+ Use file for batch I/O and report generation features.
256
+ Use event for message-driven and daemon features.
257
+ When in doubt about which adapter to use, refer to the adapters section's when_to_use fields.
258
+ priority: required
259
+
260
+ - id: backward-compatibility
261
+ trigger: reading existing snapshot files without adapter field
262
+ instruction: |
263
+ Treat snapshot files missing the adapter field as adapter=http.
264
+ Do NOT require migration of existing snapshot files to add adapter field.
265
+ New snapshots should always include the adapter field explicitly.
266
+ priority: required
267
+
164
268
  related_standards:
165
269
  - feature-manifest-standard.ai.yaml
166
270
  - acceptance-criteria-traceability.ai.yaml
@@ -12,10 +12,13 @@ standard:
12
12
  - "Automate build, test, deploy, and rollback"
13
13
 
14
14
  meta:
15
- version: "1.0.0"
16
- updated: "2026-02-09"
15
+ version: "1.1.0"
16
+ updated: "2026-05-13"
17
17
  source: core/deployment-standards.md
18
- description: Safe deployment strategies, feature flags, rollback, environment parity, and DORA metrics
18
+ description: >
19
+ Safe deployment strategies, feature flags, rollback, environment parity, and DORA metrics.
20
+ v1.1.0: Added environment stratification responsibility matrix and stub server CI/CD
21
+ lifecycle rules (XSPEC-204).
19
22
 
20
23
  principles:
21
24
  core:
@@ -125,6 +128,108 @@ checklist:
125
128
  medium_term_24hr: ["Batch jobs successful", "Data consistency verified", "No memory leaks"]
126
129
  long_term_1wk: ["Flag cleanup scheduled", "Retrospective completed", "Docs updated"]
127
130
 
131
+ # ─────────────────────────────────────────────────────────
132
+ # Environment Stratification Responsibility Matrix (v1.1.0)
133
+ # ─────────────────────────────────────────────────────────
134
+ environment_stratification_matrix:
135
+ rule: >
136
+ Projects with external dependencies MUST build an environment stratification
137
+ responsibility matrix at test-planning time (not at release candidate review).
138
+ This matrix answers: "Which test flows can be fully verified in which environment?"
139
+ when_required: "Any project with external service dependencies (SMS, payment, IdP, messaging, etc.)"
140
+ where: "docs/testing/environment-stratification-matrix.md or in the test plan"
141
+
142
+ template: |
143
+ ## Environment Stratification Responsibility Matrix
144
+
145
+ | Flow / Feature | local UAT | Remote UAT | PRD |
146
+ |------------------------|:----------------:|:----------------:|:------------------:|
147
+ | Auth / Login | ✅ stub IdP | ✅ Keycloak/AD | ✅ Enterprise IdP |
148
+ | SMS Sending | ⚠️ L2-stub | ❌ / ⚠️ | ✅ Real + billing |
149
+ | Payment / Purchase | ⚠️ L2-stub | ⚠️ network-dep | ✅ Real + reconcile|
150
+ | User / Dept Management | ✅ | ✅ cross-machine | ✅ |
151
+ | Background Jobs | ✅ in-process | ✅ | ✅ |
152
+
153
+ Legend:
154
+ ✅ Full E2E verification possible
155
+ ⚠️ Flow passes through stub/mock — real-world dimensions NOT verified
156
+ ❌ Cannot test in this environment layer
157
+
158
+ ### PRD-only verification items (must plan PRD smoke test coverage)
159
+ - SMS billing correctness
160
+ - Payment real debit + bank reconciliation
161
+ - Enterprise AD group sync behavior
162
+
163
+ mandatory_rule: >
164
+ This matrix MUST be reviewed at test planning stage alongside
165
+ acceptance-criteria-traceability. It is NOT acceptable to discover
166
+ PRD-only verification items for the first time during release candidate review.
167
+
168
+ # ─────────────────────────────────────────────────────────
169
+ # Stub Server CI/CD Lifecycle Rules (v1.1.0)
170
+ # ─────────────────────────────────────────────────────────
171
+ stub_server_cicd_rules:
172
+ rationale: >
173
+ Production CI/CD artifacts commonly exclude stub server directories for valid
174
+ security reasons (e.g., MockSoap/, tests/stub-server/ excluded from build.ps1).
175
+ Without explicit rules, this creates an undocumented "UAT cannot test X" situation
176
+ that is discovered too late in the release cycle.
177
+
178
+ build_time:
179
+ rules:
180
+ - "Production artifact MUST exclude all stub server code directories"
181
+ - "Exclusion rule MUST be documented in docs/uat/STUB-EXCLUSION-RATIONALE.md"
182
+ - "CI build verification step MUST confirm stub directories are absent from artifact"
183
+ example_ps1: |
184
+ # build.ps1 — explicit exclusion with documentation comment
185
+ # Stub server excluded from production artifact (see docs/uat/STUB-EXCLUSION-RATIONALE.md)
186
+ # Consequence: UAT machine cannot run SMS/MMS flow without sidecar deployment (see Option A below)
187
+ $exclude = @("MockSoap", "tests/stub-server", "test-fixtures")
188
+
189
+ uat_deployment:
190
+ rule: "Choose Option A or Option B; document the choice; do NOT leave it undocumented"
191
+ options:
192
+ option_a_sidecar_deploy:
193
+ name: "Sidecar Deployment (Recommended)"
194
+ description: >
195
+ Stub server deployed as separate process to UAT machine;
196
+ application configured via env var to reach the stub endpoint.
197
+ benefit: "Decoupled from app artifact; independently updatable"
198
+ example_github_actions: |
199
+ deploy-stub-server:
200
+ environment: uat
201
+ steps:
202
+ - name: Deploy stub server to UAT
203
+ run: |
204
+ ssh uat-machine "cd /opt/stub-server && pm2 start server.js --name stub-server"
205
+ - name: Configure app to use stub
206
+ run: echo "SMS_ENDPOINT=http://uat-machine:9999/soap" >> $GITHUB_ENV
207
+ example_gitlab_ci: |
208
+ deploy-stub-server:
209
+ stage: deploy
210
+ environment: uat
211
+ script:
212
+ - ssh uat-machine "pm2 start tests/stub-server/server.js --name stub-server"
213
+ only: [uat-branch, tags]
214
+
215
+ option_b_prd_smoke_deferral:
216
+ name: "PRD Smoke Deferral"
217
+ description: >
218
+ Document which flows cannot be tested in UAT; explicitly mark them as
219
+ PRD-smoke-only items. These items must appear in the environment stratification matrix.
220
+ requirement: "Must be reflected as ❌ in environment stratification matrix with PRD smoke plan"
221
+
222
+ prd_prohibitions:
223
+ - "MUST NOT deploy or run stub servers in PRD environment"
224
+ - "MUST NOT include stub server code in PRD artifact"
225
+ - "MUST NOT allow network access to stub server endpoints from PRD"
226
+
227
+ forbidden_state: >
228
+ It is NEVER acceptable to have "no stub server AND no real service AND no documented
229
+ deferral" for a testable flow. Every flow must be either:
230
+ (a) fully testable in UAT via real service or Level 2 stub server, OR
231
+ (b) explicitly documented as PRD-smoke-only with a smoke test plan.
232
+
128
233
  physical_spec:
129
234
  type: custom_script
130
235
  validator: