@danmoisan/drm-copilot-mcp 1.1.21 → 1.1.23

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.
Files changed (91) hide show
  1. package/out/mcp-server.js +2568 -1261
  2. package/package.json +1 -1
  3. package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +1 -1
  4. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +4 -4
  5. package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +1 -1
  6. package/resources/claude-customizations/.claude/agents/feature-review.md +8 -0
  7. package/resources/claude-customizations/.claude/agents/orchestrator.md +1 -1
  8. package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +46 -6
  9. package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
  10. package/resources/claude-customizations/.claude/agents/pr-author.md +32 -7
  11. package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +1 -1
  12. package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +4 -3
  13. package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +2 -1
  14. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-green-ci.ps1 +325 -0
  15. package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +22 -6
  16. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +23 -10
  17. package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +29 -21
  18. package/resources/claude-customizations/.claude/hooks/enforce-file-size-limit.ps1 +244 -0
  19. package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +48 -0
  20. package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +22 -11
  21. package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +2 -1
  22. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +8 -2
  23. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +15 -10
  24. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.current-branch.ps1 +149 -0
  25. package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +2 -1
  26. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-feature-folder.ps1 +146 -0
  27. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +25 -3
  28. package/resources/claude-customizations/.claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1 +33 -6
  29. package/resources/claude-customizations/.claude/lib/file-size-policy/FileSizePolicy.psm1 +434 -0
  30. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateFeatureFolderRecord.psm1 +166 -0
  31. package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +8 -3
  32. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunRecordPath.psm1 +185 -0
  33. package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +11 -21
  34. package/resources/claude-customizations/.claude/rules/general-code-change.md +4 -1
  35. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +28 -5
  36. package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +2 -2
  37. package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
  38. package/resources/claude-customizations/.claude/rules/shell.md +1 -1
  39. package/resources/claude-customizations/.claude/settings.json +4 -0
  40. package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +2 -2
  41. package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +2 -1
  42. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -0
  43. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +11 -4
  44. package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +4 -1
  45. package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +90 -14
  46. package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +3 -1
  47. package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +39 -9
  48. package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +1 -1
  49. package/resources/claude-customizations/pack-manifests/core.json +14 -0
  50. package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +2 -1
  51. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
  52. package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +8 -0
  53. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +4 -1
  54. package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +1 -1
  55. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +1 -1
  56. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +1 -1
  57. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +1 -1
  58. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +1 -1
  59. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +1 -1
  60. package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +1 -1
  61. package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +8 -0
  62. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +1 -1
  63. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +1 -1
  64. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +1 -1
  65. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +1 -1
  66. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +1 -1
  67. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
  68. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +1 -1
  69. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +1 -1
  70. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +1 -1
  71. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +1 -1
  72. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +1 -1
  73. package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +1 -1
  74. package/resources/codex-and-agents-customizations/.codex/config.toml +7 -1
  75. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-file-size-limit.ps1 +282 -0
  76. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +2 -1
  77. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +2 -1
  78. package/resources/codex-and-agents-customizations/.codex/hooks/file-size-policy.ps1 +421 -0
  79. package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +1 -1
  80. package/resources/codex-and-agents-customizations/AGENTS.md +4 -1
  81. package/resources/codex-and-agents-customizations/pack-manifests/core.json +3 -0
  82. package/resources/customizations/.github/agents/commentary-remediation.agent.md +1 -1
  83. package/resources/customizations/.github/agents/python-execution-only-typed.agent.md +1 -1
  84. package/resources/customizations/.github/agents/python-typed-engineer.agent.md +1 -1
  85. package/resources/customizations/.github/instructions/general-code-change.instructions.md +5 -2
  86. package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +1 -1
  87. package/resources/customizations/.github/prompts/remediate-comments.prompt.md +1 -1
  88. package/resources/customizations/.github/skills/execution-environment/SKILL.md +2 -1
  89. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +8 -0
  90. package/resources/templates/policy_audit/code-review.yyyy-MM-ddTHH-mm.md +4 -4
  91. package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +4 -4
@@ -0,0 +1,421 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Codex twin of the tiered file-size policy functions (500 guidance, 700 advisory, 800 hard limit).
4
+
5
+ .DESCRIPTION
6
+ Dot-sourced by .codex/hooks/enforce-file-size-limit.ps1 as:
7
+ . (Join-Path $PSScriptRoot 'file-size-policy.ps1')
8
+
9
+ Codex hooks cannot import .claude/lib in a consumer repository, so the policy
10
+ functions of .claude/lib/file-size-policy/FileSizePolicy.psm1 are mirrored here.
11
+ Every function definition in this file is text-identical to the definition of the
12
+ same name in that module; tests/scripts/codex-hooks/file-size-policy.Tests.ps1
13
+ parses both files and fails on any difference, and runs the shared case rows
14
+ against this file. Edit the module first, then copy each changed definition here.
15
+
16
+ .NOTES
17
+ Compatible with PowerShell 7+.
18
+
19
+ Entrypoint-free by design: this file contains only function definitions, so
20
+ dot-sourcing it has no side effects and no exit-code semantics. It never reads
21
+ standard input and never reads any legacy Claude environment variable. Every
22
+ function is pure: no filesystem, process, network, environment, or clock access.
23
+ #>
24
+
25
+ function Get-FileSizePolicyLimit {
26
+ <#
27
+ .SYNOPSIS
28
+ Return the three tier limits of the file-size policy.
29
+ .OUTPUTS
30
+ A PSCustomObject with Guidance (500), Advisory (700), and HardLimit (800).
31
+ #>
32
+ [CmdletBinding()]
33
+ [OutputType([pscustomobject])]
34
+ param()
35
+
36
+ return [pscustomobject]@{
37
+ Guidance = 500
38
+ Advisory = 700
39
+ HardLimit = 800
40
+ }
41
+ }
42
+
43
+ function Get-FileSizeExcludedSegment {
44
+ <#
45
+ .SYNOPSIS
46
+ Return the directory names excluded from the file-size policy.
47
+ .DESCRIPTION
48
+ A path with any of these names as a directory segment is not covered. This
49
+ function is the single source of the excluded names: Test-FileSizeCoveredPath
50
+ and the repository gate traversal both read it. Each call returns a new array.
51
+ .OUTPUTS
52
+ System.String[].
53
+ #>
54
+ [CmdletBinding()]
55
+ [OutputType([string[]])]
56
+ param()
57
+
58
+ return [string[]]@('.git', 'node_modules', 'artifacts', 'coverage', 'dist', 'out', 'virtual', 'docs',
59
+ 'build', '.venv', 'venv', 'env', '__pycache__', '.pytest_cache', '.mypy_cache', '.ruff_cache', '.tox',
60
+ '.nox', 'htmlcov', '.vscode-test')
61
+ }
62
+
63
+ function Get-FileSizeLogicalLineCount {
64
+ <#
65
+ .SYNOPSIS
66
+ Count the logical lines of a text.
67
+ .DESCRIPTION
68
+ Splits the content on CRLF or LF. A trailing line terminator does not add a
69
+ line, and empty or null content has zero lines.
70
+ .PARAMETER Content
71
+ The file content.
72
+ .OUTPUTS
73
+ System.Int32.
74
+ #>
75
+ [CmdletBinding()]
76
+ [OutputType([int])]
77
+ param(
78
+ [Parameter(Mandatory)]
79
+ [AllowNull()]
80
+ [AllowEmptyString()]
81
+ [string] $Content
82
+ )
83
+
84
+ if ([string]::IsNullOrEmpty($Content)) {
85
+ return 0
86
+ }
87
+
88
+ $count = [regex]::Split($Content, '\r?\n').Count
89
+ if ($Content.EndsWith("`n")) {
90
+ # The split yields one empty trailing element after a final terminator.
91
+ $count--
92
+ }
93
+ return $count
94
+ }
95
+
96
+ function Get-FileSizeTier {
97
+ <#
98
+ .SYNOPSIS
99
+ Classify a logical line count into a policy tier.
100
+ .DESCRIPTION
101
+ Returns 'Below' (under 500), 'Guidance' (500 through 699), 'Advisory' (700
102
+ through 799), or 'HardLimit' (800 and above). The hard block applies only
103
+ above 800; a count of exactly 800 is in the HardLimit tier and still passes.
104
+ .PARAMETER LineCount
105
+ A non-negative logical line count.
106
+ .OUTPUTS
107
+ System.String.
108
+ #>
109
+ [CmdletBinding()]
110
+ [OutputType([string])]
111
+ param(
112
+ [Parameter(Mandatory)]
113
+ [int] $LineCount
114
+ )
115
+
116
+ if ($LineCount -lt 0) {
117
+ throw "Get-FileSizeTier: LineCount must be non-negative; received $LineCount."
118
+ }
119
+
120
+ $limit = Get-FileSizePolicyLimit
121
+ if ($LineCount -ge $limit.HardLimit) { return 'HardLimit' }
122
+ if ($LineCount -ge $limit.Advisory) { return 'Advisory' }
123
+ if ($LineCount -ge $limit.Guidance) { return 'Guidance' }
124
+ return 'Below'
125
+ }
126
+
127
+ function ConvertTo-FileSizeRelativePath {
128
+ <#
129
+ .SYNOPSIS
130
+ Convert a file path to a repository-relative forward-slash path.
131
+ .DESCRIPTION
132
+ Backslashes are normalized to forward slashes. A relative path is returned
133
+ without a leading './'. An absolute path under the repository root is
134
+ returned relative to the root (compared case-insensitively, because the
135
+ root may come from a case-insensitive file system). A path outside the root,
136
+ a relative path that climbs above the root, and the root itself return
137
+ $null, which callers treat as not covered.
138
+ .PARAMETER Path
139
+ The file path from a tool payload or a discovery.
140
+ .PARAMETER RepositoryRoot
141
+ The repository root directory.
142
+ .OUTPUTS
143
+ System.String, or $null for a path outside the repository root.
144
+ #>
145
+ [CmdletBinding()]
146
+ [OutputType([string])]
147
+ param(
148
+ [Parameter(Mandatory)]
149
+ [AllowNull()]
150
+ [AllowEmptyString()]
151
+ [string] $Path,
152
+
153
+ [Parameter(Mandatory)]
154
+ [string] $RepositoryRoot
155
+ )
156
+
157
+ if ([string]::IsNullOrWhiteSpace($Path)) {
158
+ return $null
159
+ }
160
+
161
+ $normalized = $Path.Replace('\', '/')
162
+ $isRooted = $normalized.StartsWith('/') -or ($normalized -match '^[A-Za-z]:/')
163
+ if (-not $isRooted) {
164
+ while ($normalized.StartsWith('./')) {
165
+ $normalized = $normalized.Substring(2)
166
+ }
167
+ if ($normalized -eq '..' -or $normalized.StartsWith('../') -or $normalized.Length -eq 0) {
168
+ return $null
169
+ }
170
+ return $normalized
171
+ }
172
+
173
+ $root = $RepositoryRoot.Replace('\', '/').TrimEnd('/')
174
+ $prefix = $root + '/'
175
+ if (-not $normalized.StartsWith($prefix, [System.StringComparison]::OrdinalIgnoreCase)) {
176
+ return $null
177
+ }
178
+
179
+ $relative = $normalized.Substring($prefix.Length)
180
+ if ($relative.Length -eq 0) {
181
+ return $null
182
+ }
183
+ return $relative
184
+ }
185
+
186
+ function Test-FileSizeCoveredPath {
187
+ <#
188
+ .SYNOPSIS
189
+ Report whether a repository-relative path is covered by the file-size policy.
190
+ .DESCRIPTION
191
+ A path is covered when its extension (case-insensitive) is in the allowlist
192
+ (py, ps1, psm1, ts, tsx, js, cjs, mjs, cs, sh, and bats), no directory segment
193
+ is an excluded name, and it is not under the worktrees folder of .claude.
194
+ Excluded directory names are matched exactly. Null or empty input is not covered.
195
+ .PARAMETER RelativePath
196
+ A repository-relative path, for example from ConvertTo-FileSizeRelativePath.
197
+ .OUTPUTS
198
+ System.Boolean.
199
+ #>
200
+ [CmdletBinding()]
201
+ [OutputType([bool])]
202
+ param(
203
+ [Parameter(Mandatory)]
204
+ [AllowNull()]
205
+ [AllowEmptyString()]
206
+ [string] $RelativePath
207
+ )
208
+
209
+ if ([string]::IsNullOrWhiteSpace($RelativePath)) {
210
+ return $false
211
+ }
212
+
213
+ $allowedExtension = @('.py', '.ps1', '.psm1', '.ts', '.tsx', '.js', '.cjs', '.mjs', '.cs', '.sh', '.bats')
214
+ $excludedSegment = @(Get-FileSizeExcludedSegment)
215
+
216
+ $normalized = $RelativePath.Replace('\', '/')
217
+ if ($normalized.StartsWith('.claude/worktrees/')) {
218
+ return $false
219
+ }
220
+
221
+ $segment = @($normalized.Split('/'))
222
+ for ($index = 0; $index -lt ($segment.Count - 1); $index++) {
223
+ if ($excludedSegment -ccontains $segment[$index]) {
224
+ return $false
225
+ }
226
+ }
227
+
228
+ $extension = [System.IO.Path]::GetExtension($segment[-1]).ToLowerInvariant()
229
+ return ($allowedExtension -contains $extension)
230
+ }
231
+
232
+ function Compare-FileSizeBaselineEntry {
233
+ <#
234
+ .SYNOPSIS
235
+ Compare one file's current size with its baseline entry under the strict ratchet.
236
+ .DESCRIPTION
237
+ Rows (S is the current size, B the recorded size):
238
+ S <= 800, no entry -> pass
239
+ S <= 800, entry -> 'stale-entry' (remove the entry)
240
+ S > 800, no entry -> 'new-over-limit'
241
+ S > 800, entry, S > B -> 'grew'
242
+ S > 800, entry, S == B -> pass
243
+ S > 800, entry, S < B -> 'tighten' (tighten the entry to S)
244
+ no file, entry -> 'missing-file' (stale entry for a deleted or renamed file)
245
+ no file, no entry -> pass
246
+ .PARAMETER Path
247
+ The repository-relative path, used in the violation message.
248
+ .PARAMETER CurrentSize
249
+ The current logical line count, or $null when no file exists on disk.
250
+ .PARAMETER BaselineSize
251
+ The recorded size, or $null when the baseline has no entry.
252
+ .OUTPUTS
253
+ $null on pass; otherwise a PSCustomObject with Path, Rule, and Message.
254
+ #>
255
+ [CmdletBinding()]
256
+ [OutputType([pscustomobject])]
257
+ param(
258
+ [Parameter(Mandatory)]
259
+ [string] $Path,
260
+
261
+ [AllowNull()]
262
+ [Nullable[int]] $CurrentSize,
263
+
264
+ [AllowNull()]
265
+ [Nullable[int]] $BaselineSize
266
+ )
267
+
268
+ $hardLimit = (Get-FileSizePolicyLimit).HardLimit
269
+ $rule = $null
270
+ $message = $null
271
+
272
+ if ($null -eq $CurrentSize) {
273
+ if ($null -ne $BaselineSize) {
274
+ $rule = 'missing-file'
275
+ $message = "stale baseline entry: '$Path' has no file on disk (deleted or renamed); remove the entry or move it with its recorded size unchanged."
276
+ }
277
+ } elseif ($CurrentSize -le $hardLimit) {
278
+ if ($null -ne $BaselineSize) {
279
+ $rule = 'stale-entry'
280
+ $message = "stale baseline entry: '$Path' has $CurrentSize lines, at or below the $hardLimit-line hard limit; remove the entry."
281
+ }
282
+ } elseif ($null -eq $BaselineSize) {
283
+ $rule = 'new-over-limit'
284
+ $message = "new file over the hard limit: '$Path' has $CurrentSize lines, above the $hardLimit-line hard limit; split the file."
285
+ } elseif ($CurrentSize -gt $BaselineSize) {
286
+ $rule = 'grew'
287
+ $message = "baselined file grew: '$Path' has $CurrentSize lines, above its recorded $BaselineSize; a baselined file may not grow."
288
+ } elseif ($CurrentSize -lt $BaselineSize) {
289
+ $rule = 'tighten'
290
+ $message = "baselined file shrank: '$Path' has $CurrentSize lines, below its recorded $BaselineSize; tighten the entry to $CurrentSize."
291
+ }
292
+
293
+ if ($null -eq $rule) {
294
+ return $null
295
+ }
296
+ return [pscustomobject]@{ Path = $Path; Rule = $rule; Message = $message }
297
+ }
298
+
299
+ function Resolve-FileSizeEditContent {
300
+ <#
301
+ .SYNOPSIS
302
+ Apply an Edit-tool old_string to new_string replacement to pre-edit content in memory.
303
+ .DESCRIPTION
304
+ Follows the replacement approach of Resolve-EditedCheckpointContent in
305
+ .claude/hooks/enforce-completion-consistency.ps1: CRLF is normalized to LF in
306
+ all three strings, matching is ordinal (no regular expression, so '$' in the
307
+ new text stays literal), one occurrence is replaced unless ReplaceAll is true,
308
+ and a second match after the first is ambiguous. Failure is 'no-old-string'
309
+ (absent or empty old string), 'not-found', or 'ambiguous'.
310
+ .PARAMETER Content
311
+ The pre-edit file content.
312
+ .PARAMETER OldString
313
+ The text to replace.
314
+ .PARAMETER NewString
315
+ The replacement text; null is treated as empty.
316
+ .PARAMETER ReplaceAll
317
+ Replace every occurrence instead of exactly one.
318
+ .OUTPUTS
319
+ A PSCustomObject with Content (the edited text, or $null on failure) and
320
+ Failure (a failure code, or $null on success).
321
+ #>
322
+ [CmdletBinding()]
323
+ [OutputType([pscustomobject])]
324
+ param(
325
+ [Parameter(Mandatory)]
326
+ [AllowNull()]
327
+ [AllowEmptyString()]
328
+ [string] $Content,
329
+
330
+ [Parameter(Mandatory)]
331
+ [AllowNull()]
332
+ [AllowEmptyString()]
333
+ [string] $OldString,
334
+
335
+ [AllowNull()]
336
+ [AllowEmptyString()]
337
+ [string] $NewString = '',
338
+
339
+ [bool] $ReplaceAll = $false
340
+ )
341
+
342
+ if ([string]::IsNullOrEmpty($OldString)) {
343
+ return [pscustomobject]@{ Content = $null; Failure = 'no-old-string' }
344
+ }
345
+
346
+ $text = ([string]$Content).Replace("`r`n", "`n")
347
+ $old = $OldString.Replace("`r`n", "`n")
348
+ $new = ([string]$NewString).Replace("`r`n", "`n")
349
+
350
+ $first = $text.IndexOf($old, [System.StringComparison]::Ordinal)
351
+ if ($first -lt 0) {
352
+ return [pscustomobject]@{ Content = $null; Failure = 'not-found' }
353
+ }
354
+ if ($ReplaceAll) {
355
+ return [pscustomobject]@{ Content = $text.Replace($old, $new); Failure = $null }
356
+ }
357
+
358
+ $second = $text.IndexOf($old, $first + $old.Length, [System.StringComparison]::Ordinal)
359
+ if ($second -ge 0) {
360
+ return [pscustomobject]@{ Content = $null; Failure = 'ambiguous' }
361
+ }
362
+
363
+ $edited = $text.Substring(0, $first) + $new + $text.Substring($first + $old.Length)
364
+ return [pscustomobject]@{ Content = $edited; Failure = $null }
365
+ }
366
+
367
+ function Get-FileSizeHookDecision {
368
+ <#
369
+ .SYNOPSIS
370
+ Decide whether a Write or Edit may leave a file at its resulting size.
371
+ .DESCRIPTION
372
+ Baseline-free pre-edit-size ratchet. A path that is not covered is allowed.
373
+ A covered result of at most 800 lines is allowed. A covered result above 800
374
+ lines is allowed only when the file already existed and the result is not
375
+ larger than its pre-edit size, so an already-large file may shrink or stay
376
+ the same size but may not grow; every other case is denied. The deny reason
377
+ starts with 'FILE_SIZE_LIMIT_BLOCKED:' and names the path, the resulting
378
+ count, the three tiers, and the split requirement.
379
+ .PARAMETER RelativePath
380
+ The repository-relative path; $null or empty (outside the repository) is not covered.
381
+ .PARAMETER ResultLineCount
382
+ The logical line count the file would have after the operation.
383
+ .PARAMETER PreEditLineCount
384
+ The logical line count before the operation, or $null for a new file.
385
+ .OUTPUTS
386
+ A PSCustomObject with Allowed (bool) and Reason ($null when allowed).
387
+ #>
388
+ [CmdletBinding()]
389
+ [OutputType([pscustomobject])]
390
+ param(
391
+ [Parameter(Mandatory)]
392
+ [AllowNull()]
393
+ [AllowEmptyString()]
394
+ [string] $RelativePath,
395
+
396
+ [Parameter(Mandatory)]
397
+ [int] $ResultLineCount,
398
+
399
+ [AllowNull()]
400
+ [Nullable[int]] $PreEditLineCount
401
+ )
402
+
403
+ $limit = Get-FileSizePolicyLimit
404
+ $isAllowed = (-not (Test-FileSizeCoveredPath -RelativePath $RelativePath)) -or
405
+ ($ResultLineCount -le $limit.HardLimit) -or
406
+ (($null -ne $PreEditLineCount) -and ($ResultLineCount -le $PreEditLineCount))
407
+ if ($isAllowed) {
408
+ return [pscustomobject]@{ Allowed = $true; Reason = $null }
409
+ }
410
+
411
+ $growth = ''
412
+ if ($null -ne $PreEditLineCount) {
413
+ $growth = " It has $PreEditLineCount lines now; a file already above the hard limit may shrink or stay the same size but may not grow."
414
+ }
415
+ $reason = "FILE_SIZE_LIMIT_BLOCKED: '$RelativePath' would have $ResultLineCount logical lines, above the " +
416
+ "$($limit.HardLimit)-line hard limit.$growth File-size policy tiers: $($limit.Guidance) lines is guidance " +
417
+ "(look for a logical split), $($limit.Advisory) lines is advisory (split more aggressively; reviewers report " +
418
+ "a non-blocking Warning), and above $($limit.HardLimit) lines a split is enforced regardless of logical " +
419
+ "separability. Split the file into smaller files so each stays at or below $($limit.HardLimit) lines."
420
+ return [pscustomobject]@{ Allowed = $false; Reason = $reason }
421
+ }
@@ -83,7 +83,7 @@ If the marker is missing or malformed, fail closed to `full-feature`.
83
83
  Stop implementation and return to the user when:
84
84
 
85
85
  - the scope estimate or an in-flight batch would exceed the 3-production-file cap in direct mode,
86
- - a file is near or would exceed the 500-line limit,
86
+ - a file is above or would exceed the 800-line hard limit of the tiered file-size policy (split it before proceeding; at 500 lines look for a logical split, and at 700 lines split more aggressively),
87
87
  - any QA gate delta is non-zero after self-correction,
88
88
  - the toolchain cannot be executed in the current environment (mark the change **unverified**),
89
89
  - orchestrator handoff mode is requested but the required context package is incomplete,
@@ -52,7 +52,10 @@ Run the full toolchain in this exact order and repeat until all steps pass in a
52
52
 
53
53
  ## File Size Limit
54
54
 
55
- - No production code, test code, or reusable script file may exceed **500 lines**.
55
+ - File size follows three tiers for production code, test code, and reusable script files, counted in logical lines (a trailing line terminator does not add a line):
56
+ - **500 lines (guidance):** look for a logical way to divide the file into multiple files, provided the parts can be separated logically. No gate fails at this tier.
57
+ - **700 lines (advisory):** look for a split more aggressively. Reviewers and `feature-review` report a non-blocking Warning for a file at or above 700 lines. No gate fails at this tier.
58
+ - **Above 800 lines (hard block):** split the file regardless of logical separability. The repository CI check and the PreToolUse hook block a file of 801 lines or more; a file of exactly 800 lines passes. Legacy files above 800 lines are listed in `config/file-size-baseline.json` and may shrink (with the entry tightened) or stay the same size, but may not grow.
56
59
  - Exceptions: temporary throwaway scripts created and deleted within an agent session; raw text fixtures for language-processing test data; Markdown documentation files.
57
60
 
58
61
  ## Error Handling and Logging
@@ -64,6 +64,8 @@
64
64
  ".codex/hooks/enforce-completion-consistency.ps1",
65
65
  ".codex/hooks/enforce-completion-helpers.ps1",
66
66
  ".codex/hooks/enforce-evidence-locations.ps1",
67
+ ".codex/hooks/enforce-file-size-limit.ps1",
68
+ ".codex/hooks/file-size-policy.ps1",
67
69
  ".codex/hooks/enforce-orchestration-preimplementation-gate.ps1",
68
70
  ".codex/hooks/enforce-powershell-batch-budget.ps1",
69
71
  ".codex/hooks/enforce-promotion-mcp-only.ps1",
@@ -79,6 +81,7 @@
79
81
  ".codex/scripts/codex-routing-cli-common.ps1",
80
82
  ".codex/scripts/Resolve-CodexDeployment.ps1",
81
83
  ".codex/scripts/Resolve-CodexTopology.ps1",
84
+ ".codex/scripts/post-codex-worktree-session.ps1",
82
85
  ".codex/prompts/generate-pr.md",
83
86
  ".codex/prompts/orchestrate-work.md",
84
87
  ".codex/agents/feature-reviewer.toml",
@@ -14,7 +14,7 @@ Relentlessly bring the targeted scope into full compliance with `.github/instruc
14
14
  - **Scope fidelity:** Accept a scope (single file, set of files, or entire repo) and remediate everything in that scope. Do not stop or return early; continue through all phases, using additional turns automatically if needed.
15
15
  - **Policy order:** Read and apply, in order: `.github/copilot-instructions.md`, general code-change, general unit-test, python code-change, python unit-test, and self-explanatory-commenting policies. Treat them as hard requirements.
16
16
  - **Docstrings & intent comments:** Ensure every class/function/method has robust docstrings; add intent-level comments for loops, branches, and multi-step blocks per the intent-first policy. Avoid low-value narration.
17
- - **Safety & structure:** Keep modules cohesive, under 500 lines, with strong typing and separation of concerns. Prefer helper extraction over dense inline logic when comments would become bulky.
17
+ - **Safety & structure:** Keep modules cohesive, within the tiered file-size policy of `general-code-change.instructions.md`, with strong typing and separation of concerns. Prefer helper extraction over dense inline logic when comments would become bulky.
18
18
  - **Autonomy:** Never ask for clarification once scope is given. Do not defer or ask for approval. If work requires multiple turns, continue automatically.
19
19
 
20
20
  ## Workflow
@@ -81,7 +81,7 @@ If the environment prevents running tools, STOP implementation and provide a pla
81
81
  - Coverage baseline for touched files (and overall if enforced)
82
82
  3) Summarize root cause / design constraint in one paragraph.
83
83
 
84
- Before exiting Phase A, perform a quick line-count check on all in-scope files. If any file is near the 500-line limit or planned additions would push it over 500, decide upfront to split now (counting new files against the budget) or seek an override before Phase B. If uncertain, treat it as at-risk and plan for a split rather than discovering it mid-execution. If an approved plan would create a 500-line violation, halt and seek clarification before proceeding.
84
+ Before exiting Phase A, perform a quick line-count check on all in-scope files and apply the tiered file-size policy: at 500 lines, look for a logical split; at 700 lines, split more aggressively; if any file is above 800 lines or planned additions would push it above 800, decide upfront to split it now (a hard stop, regardless of logical separability, counting new files against the budget) before Phase B. If uncertain, treat it as at-risk and plan for a split rather than discovering it mid-execution. If an approved plan would leave a file above 800 lines, halt and seek clarification before proceeding.
85
85
 
86
86
  Do not proceed to edits until the user explicitly approves (e.g., “Proceed.”).
87
87
  However, if a plan is provided in the initial prompt, it is already implicitly approved.
@@ -134,7 +134,7 @@ If no plan is provided, delegate the creation of a plan to the `atomic_planner`.
134
134
  - Mocking plan (what is mocked, where patched, and why)
135
135
  - Exact files to change (must match scope guardrails)
136
136
 
137
- Before exiting Phase B, perform a quick line-count check on all in-scope files. If any file is near the 500-line limit or planned additions would push it over 500, decide upfront to split now (counting new files against the budget) before Phase C. If uncertain, treat it as at-risk and plan for a split rather than discovering it mid-execution. If an approved plan would create a 500-line violation, halt and seek clarification before proceeding.
137
+ Before exiting Phase B, perform a quick line-count check on all in-scope files and apply the tiered file-size policy: at 500 lines, look for a logical split; at 700 lines, split more aggressively; if any file is above 800 lines or planned additions would push it above 800, decide upfront to split it now (a hard stop, regardless of logical separability, counting new files against the budget) before Phase C. If uncertain, treat it as at-risk and plan for a split rather than discovering it mid-execution. If an approved plan would leave a file above 800 lines, halt and seek clarification before proceeding.
138
138
 
139
139
  Do not proceed to edits until the user explicitly approves (e.g., “Proceed.”).
140
140
  However, if a plan is provided in the initial prompt, it is already implicitly approved.
@@ -143,8 +143,11 @@ Rules for functions:
143
143
 
144
144
  - A module/file should have a clear purpose (e.g. “QIF parsing,” “Lexile model,” “corpus download”).
145
145
  - Avoid dumping unrelated classes/functions into the same file.
146
- - Do not exceed 500 lines for any one file.
147
- - This 500-line limit applies to production code, test code, and reusable scripts.
146
+ - File size follows a tiered policy that applies to production code, test code, and reusable scripts:
147
+ - **500 lines (guidance):** look for logical ways to divide the file into multiple files, provided the parts can be separated logically. No gate fails at this tier.
148
+ - **700 lines (advisory):** look for a split more aggressively. Reviewers and `feature-review` report a non-blocking Warning for a file at or above 700 lines. No gate fails at this tier.
149
+ - **Above 800 lines (hard block):** a split is enforced regardless of logical separability. A file of 801 lines or more is blocked by the repository CI check and by the PreToolUse hook; a file of exactly 800 lines passes. Legacy files already above 800 lines are recorded in `config/file-size-baseline.json` and may shrink (with the entry tightened) or stay the same size, but may not grow.
150
+ - Lines are logical lines: the content split on line terminators, where a trailing terminator does not add a line.
148
151
  - Exceptions: temporary throwaway scripts created and deleted during an agent session; raw text fixtures used for language-processing test data; Markdown documentation files.
149
152
 
150
153
  2. Public vs internal
@@ -58,7 +58,7 @@ If you encounter any conflicting instructions, **halt and notify the user.**
58
58
 
59
59
  ## 3. Structure, Naming, and Comments
60
60
 
61
- - Keep scripts **cohesive and under 500 lines** (matches general policy).
61
+ - Keep scripts **cohesive** and within the tiered file-size policy of `general-code-change.instructions.md` (section 4, Module & File Structure).
62
62
  - Use approved verbs and descriptive nouns for functions (PSScriptAnalyzer will enforce).
63
63
  - Prefer modules/helpers over copy-paste between scripts; share common logic in dedicated helper functions.
64
64
  - Comment **why** for non-obvious patterns (e.g., rule suppressions, compatibility shims), not what.
@@ -25,7 +25,7 @@ Apply in this sequence:
25
25
  ## Execution Rules
26
26
 
27
27
  - Remediate the entire scope to add/adjust robust docstrings and intent comments for loops, branches, and multi-step blocks; avoid low-value narration.
28
- - Keep modules cohesive, under 500 lines, strongly typed; avoid `Any` unless justified.
28
+ - Keep modules cohesive, within the tiered file-size policy of `general-code-change.instructions.md`, strongly typed; avoid `Any` unless justified.
29
29
  - Maintain encoding/EOL and ASCII unless the file already uses Unicode.
30
30
  - Do not pause for approval or clarification once scope is set; continue across turns if needed until fully compliant.
31
31
 
@@ -83,6 +83,7 @@ Run these after editing any mirrored or bundled file; each is under `tests/scrip
83
83
 
84
84
  - `test_push_down_claude_resource_contracts.py` and `test_push_down_codex_and_agents_resource_contracts.py`: every distributable `.claude`, `.agents`, and `.codex` file exists in the bundle with equal text.
85
85
  - `test_push_down_claude_pack_manifest_completeness.py` and `test_push_down_codex_and_agents_pack_manifest_completeness.py`: every bundled file is listed in a pack manifest.
86
+ - `test_push_down_pack_manifest_dependency_closure.py`: every `$PSScriptRoot` dependency of a manifested PowerShell file, and every hook script named by `.claude/settings.json`, manifested agent frontmatter, or `.codex/config.toml`, is in core plus the owning pack.
86
87
  - The Codex generator check: `scripts/dev_tools/generate_codex_agent_variants.py` run in module form with `--check` (base agents are hand-edited; variants, bundle copies, and the Codex `core.json` are generated).
87
88
  - `test_codex_agent_wrapper_contracts.py` and `test_codex_handoff_contract_parity.py`: pinned Codex agent fragments and handoff parity.
88
89
  - `test_claude_rules_frontmatter.py`: rule `paths:` scopes and that every preloaded skill exists.
@@ -121,7 +122,7 @@ These pass every validator rule and are found only by reading the plan against t
121
122
  - Python: measure a module with `--cov=<dotted.module>`, `--cov-branch`, `--cov-report=term-missing`, and `--cov-report=json:<path>`; read branch figures from the JSON report.
122
123
  - TypeScript: a new production file needs its own entry in the `coverageThreshold` map of `extensions/drm-copilot/jest.config.cjs`; Jest runs through `node run-jest.cjs` in `extensions/drm-copilot/`.
123
124
  - PowerShell: per-file line coverage is read from `artifacts/pester/powershell-coverage.xml` written by the self-hosted PoshQC module.
124
- - No production, test, or reusable script file exceeds 500 physical lines; Markdown is exempt. Files at or near the limit are not extended; new logic goes into a new module and a new test file.
125
+ - File size follows three tiers for production, test, and reusable script files, counted in logical lines (a trailing terminator adds no line): at 500 lines look for a logical split (guidance); at 700 lines split more aggressively, and reviewers report a non-blocking Warning (advisory); above 800 lines a split is enforced regardless of logical separability (hard limit; exactly 800 passes). The hard limit is enforced by `tests/scripts/ci/FileSizePolicy.RepoGate.Tests.ps1` in the existing PowerShell shards against `config/file-size-baseline.json`, where legacy files above 800 may shrink (with the entry tightened) or stay equal but may not grow, and by the PreToolUse hook `.claude/hooks/enforce-file-size-limit.ps1` (`.codex/hooks/enforce-file-size-limit.ps1`). New logic in a file near a tier goes into a new module and a new test file. Markdown is exempt.
125
126
 
126
127
  ## Test Isolation Checks
127
128
 
@@ -154,6 +154,14 @@ Always apply:
154
154
  - `feature-audit.<timestamp>.md`
155
155
  - contains the five required major sections listed above
156
156
 
157
+ ## File Size Advisory
158
+
159
+ The tiered file-size policy (section 4, Module & File Structure, in `.github/instructions/general-code-change.instructions.md`) sets a 500-line guidance tier, a 700-line advisory tier, and an 800-line hard limit. Measure the logical line count of every added or modified covered file in the branch diff. Covered files have one of the extensions `.py`, `.ps1`, `.psm1`, `.ts`, `.tsx`, `.js`, `.cjs`, `.mjs`, `.cs`, `.sh`, or `.bats` and are not under a build, cache, dependency, virtual-environment, or `docs` directory. A logical line count splits the content on line terminators, and a trailing terminator does not add a line; it equals `@(Get-Content -LiteralPath <path>).Count`. Do not use `wc -l` or `Measure-Object -Line`.
160
+
161
+ - Report each covered file at or above 700 lines as a non-blocking `Warning` row in the Findings Table of `code-review.<timestamp>.md`, naming the file and its line count. Do not write the Warning to `remediation-inputs.<timestamp>.md`, and do not give it a remediation severity label.
162
+ - Report a covered file above 800 lines that has no entry in `config/file-size-baseline.json`, and any added or increased entry in `config/file-size-baseline.json`, as a blocking policy finding.
163
+ - Produce no finding for the 500-line guidance tier.
164
+
157
165
  ## Constraints
158
166
 
159
167
  - Prefer check-only commands.
@@ -9,7 +9,7 @@
9
9
  > 2. Replace all placeholders with concrete branch, file, test, and evidence details.
10
10
  > 3. Keep the sections that apply to the reviewed scope and delete inapplicable language subsections.
11
11
  > 4. Base all findings on verified evidence: diff inspection, toolchain output, coverage data, and feature-folder artifacts.
12
- > 5. Use severity labels consistently: `Blocker`, `Major`, `Minor`, `Nit`, `Info`.
12
+ > 5. Use severity labels consistently: `Blocker`, `Major`, `Minor`, `Nit`, `Info`, `Warning`. `Warning` is the non-blocking file-size advisory for a covered file at or above 700 logical lines; it names the file and its line count and is never carried into remediation inputs.
13
13
  > 6. End with a clear readiness recommendation that matches the actual findings.
14
14
  >
15
15
  > **When to use:**
@@ -52,8 +52,8 @@
52
52
 
53
53
  | Severity | File | Location | Finding | Recommendation | Rationale | Evidence |
54
54
  |---|---|---|---|---|---|---|
55
- | [Blocker/Major/Minor/Nit/Info] | `[path]` | `[line range / section / n/a]` | [Concrete issue] | [Concrete corrective action or note] | [Why it matters] | [Command output, artifact path, or inspected file reference] |
56
- | [Blocker/Major/Minor/Nit/Info] | `[path]` | `[line range / section / n/a]` | [Concrete issue] | [Concrete corrective action or note] | [Why it matters] | [Command output, artifact path, or inspected file reference] |
55
+ | [Blocker/Major/Minor/Nit/Info/Warning] | `[path]` | `[line range / section / n/a]` | [Concrete issue] | [Concrete corrective action or note] | [Why it matters] | [Command output, artifact path, or inspected file reference] |
56
+ | [Blocker/Major/Minor/Nit/Info/Warning] | `[path]` | `[line range / section / n/a]` | [Concrete issue] | [Concrete corrective action or note] | [Why it matters] | [Command output, artifact path, or inspected file reference] |
57
57
 
58
58
  [If applicable, add a short line such as `No Blockers or Major findings.`]
59
59
 
@@ -162,4 +162,4 @@
162
162
 
163
163
  ## Verdict
164
164
 
165
- [Provide the final review conclusion in 1-2 paragraphs. State whether the change is ready for normal PR flow, ready after a specific follow-up, or blocked. Ensure this conclusion is consistent with the Findings Table and PR readiness recommendation above.]
165
+ [Provide the final review conclusion in 1-2 paragraphs. State whether the change is ready for normal PR flow, ready after a specific follow-up, or blocked. Ensure this conclusion is consistent with the Findings Table and PR readiness recommendation above.]
@@ -159,7 +159,7 @@ Repeat one bullet per in-scope language that has coverage requirements. Keep the
159
159
  | Requirement | Status | Evidence |
160
160
  |------------|--------|----------|
161
161
  | **Cohesive modules** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Describe the purpose and cohesion of each module/file. Note organization strategy.] |
162
- | **Under 500 lines** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Report line counts for all files. Note any exceptions and justifications.] |
162
+ | **At or below the 800-line hard limit** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Report logical line counts for all covered files. FAIL for a file above 800 lines without a `config/file-size-baseline.json` entry, a baselined file that grew, or an added or increased baseline entry. Note each file at or above 700 lines as a non-blocking Warning. Note any exceptions.] |
163
163
  | **Public vs internal** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Describe the public API surface. Note how internals are hidden.] |
164
164
  | **No circular dependencies** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Describe the dependency graph. Confirm no circular dependencies exist.] |
165
165
 
@@ -253,7 +253,7 @@ Repeat one bullet per in-scope language that has coverage requirements. Keep the
253
253
 
254
254
  | Requirement | Status | Evidence |
255
255
  |------------|--------|----------|
256
- | **Cohesive and under 500 lines** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Report file line counts. Confirm all under limit.] |
256
+ | **Cohesive and at or below the 800-line hard limit** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Report logical line counts. FAIL for a file above 800 lines without a baseline entry or a baselined file that grew. Note each file at or above 700 lines as a non-blocking Warning.] |
257
257
  | **Approved verbs** | [✅/❌/N/A] [PASS/FAIL/N/A] | [List all function names and confirm verbs are approved.] |
258
258
  | **Comment why** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Describe commenting approach. Confirm focus on rationale.] |
259
259
 
@@ -285,7 +285,7 @@ Repeat one bullet per in-scope language that has coverage requirements. Keep the
285
285
  |------------|--------|----------|
286
286
  | **Portable shebang** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Confirm `#!/usr/bin/env bash` or `#!/bin/bash` used.] |
287
287
  | **Error handling** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Describe use of `set -e`, `set -u`, `set -o pipefail`, error traps.] |
288
- | **Under 500 lines** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Report file line counts.] |
288
+ | **At or below the 800-line hard limit** | [✅/❌/N/A] [PASS/FAIL/N/A] | [Report logical line counts. FAIL for a file above 800 lines without a baseline entry or a baselined file that grew. Note each file at or above 700 lines as a non-blocking Warning.] |
289
289
 
290
290
  ---
291
291
 
@@ -424,7 +424,7 @@ Repeat one bullet per in-scope language that has coverage requirements. Keep the
424
424
  | Average Time per Test | [X]ms | [✅/❌] Fast/Slow |
425
425
  | Discovery Time | [X]ms | [✅/❌] |
426
426
  | Functions/Classes Tested | [N]/[M] ([X]%) | [✅/❌] |
427
- | Test File Size | [N] lines | [✅/❌] Maintainable |
427
+ | Test File Size | [N] logical lines | [✅/❌] PASS at or below 800 lines, FAIL above 800 without a baseline entry; note a non-blocking Warning at or above 700 lines |
428
428
  | Code Coverage (if applicable) | [X]% lines, [Y]% branches | [✅/❌] |
429
429
 
430
430
  ---