@iceinvein/agent-skills 0.1.39 → 0.2.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.
- package/README.md +18 -2
- package/dist/cli/index.js +105 -28
- package/package.json +1 -1
- package/skills/index.json +14 -2
- package/skills/magpie/README.md +2 -1
- package/skills/magpie/SKILL.md +138 -45
- package/skills/magpie/bin/magpie.ts +43 -0
- package/skills/magpie/fixtures/example-pr/brief.json +18 -0
- package/skills/magpie/fixtures/fake-gh-nodiff.sh +38 -0
- package/skills/magpie/fixtures/fake-gh.sh +14 -0
- package/skills/magpie/package.json +1 -1
- package/skills/magpie/references/peer-review.md +7 -2
- package/skills/magpie/references/scout.md +90 -0
- package/skills/magpie/references/specialists.md +117 -6
- package/skills/magpie/scripts/__tests__/cli.test.ts +101 -1
- package/skills/magpie/scripts/__tests__/dedupe-cmd.test.ts +187 -0
- package/skills/magpie/scripts/__tests__/diff-chunks.test.ts +51 -0
- package/skills/magpie/scripts/__tests__/filter-diff-preservation.test.ts +54 -0
- package/skills/magpie/scripts/__tests__/findings-files.test.ts +35 -0
- package/skills/magpie/scripts/__tests__/gh.test.ts +90 -0
- package/skills/magpie/scripts/__tests__/git-diff.test.ts +83 -0
- package/skills/magpie/scripts/__tests__/helpers/git-fixture.ts +47 -0
- package/skills/magpie/scripts/__tests__/path-filter.test.ts +27 -0
- package/skills/magpie/scripts/__tests__/preview-cmd.test.ts +16 -0
- package/skills/magpie/scripts/__tests__/refresh.test.ts +45 -0
- package/skills/magpie/scripts/__tests__/render-cmd.test.ts +173 -1
- package/skills/magpie/scripts/__tests__/render-findings.test.ts +151 -1
- package/skills/magpie/scripts/__tests__/render-progress.test.ts +42 -0
- package/skills/magpie/scripts/__tests__/setup-cmd.test.ts +83 -1
- package/skills/magpie/scripts/__tests__/shard.test.ts +165 -0
- package/skills/magpie/scripts/__tests__/skill-lint.test.ts +207 -7
- package/skills/magpie/scripts/__tests__/types.test.ts +47 -0
- package/skills/magpie/scripts/dedupe-cmd.ts +58 -3
- package/skills/magpie/scripts/diff-chunks.ts +28 -0
- package/skills/magpie/scripts/findings-files.ts +32 -0
- package/skills/magpie/scripts/gh.ts +68 -14
- package/skills/magpie/scripts/git-diff.ts +111 -0
- package/skills/magpie/scripts/path-filter.ts +9 -5
- package/skills/magpie/scripts/preview-cmd.ts +11 -1
- package/skills/magpie/scripts/refresh.ts +32 -3
- package/skills/magpie/scripts/render-cmd.ts +35 -11
- package/skills/magpie/scripts/render-findings.ts +78 -2
- package/skills/magpie/scripts/render-progress.ts +6 -1
- package/skills/magpie/scripts/setup-cmd.ts +38 -1
- package/skills/magpie/scripts/shard.ts +171 -0
- package/skills/magpie/scripts/status-cmd.ts +7 -4
- package/skills/magpie/scripts/types.ts +50 -0
- package/skills/magpie/skill.json +2 -2
- package/skills/magpie/templates/styles.css +66 -0
- package/skills/migrate/README.md +194 -0
- package/skills/migrate/SKILL.md +197 -0
- package/skills/migrate/bin/migrate +15 -0
- package/skills/migrate/bin/migrate.ts +309 -0
- package/skills/migrate/biome.json +35 -0
- package/skills/migrate/bun.lock +24 -0
- package/skills/migrate/docs/architecture.md +294 -0
- package/skills/migrate/docs/reference.md +590 -0
- package/skills/migrate/fixtures/tiny-express/GROUND-TRUTH.md +39 -0
- package/skills/migrate/fixtures/tiny-express/app.js +29 -0
- package/skills/migrate/fixtures/tiny-express/cron.js +6 -0
- package/skills/migrate/fixtures/tiny-express/reports/daily-users.json +6 -0
- package/skills/migrate/fixtures/tiny-express/schema.sql +12 -0
- package/skills/migrate/fixtures/tiny-express/settings.json +4 -0
- package/skills/migrate/fixtures/tiny-express/views/users.html +9 -0
- package/skills/migrate/fixtures/tiny-webforms/Controllers/UsersController.cs +68 -0
- package/skills/migrate/fixtures/tiny-webforms/Default.aspx +7 -0
- package/skills/migrate/fixtures/tiny-webforms/Default.aspx.cs +14 -0
- package/skills/migrate/fixtures/tiny-webforms/GROUND-TRUTH.md +50 -0
- package/skills/migrate/fixtures/tiny-webforms/Integrations/BillingClient.cs +16 -0
- package/skills/migrate/fixtures/tiny-webforms/Jobs/NightlyDigestJob.cs +33 -0
- package/skills/migrate/fixtures/tiny-webforms/Reports/DailyUsers.rdl +11 -0
- package/skills/migrate/fixtures/tiny-webforms/Schema.sql +12 -0
- package/skills/migrate/fixtures/tiny-webforms/Site.master +16 -0
- package/skills/migrate/fixtures/tiny-webforms/Users.aspx +8 -0
- package/skills/migrate/fixtures/tiny-webforms/Users.aspx.cs +14 -0
- package/skills/migrate/fixtures/tiny-webforms/web.config +10 -0
- package/skills/migrate/install.sh +68 -0
- package/skills/migrate/package.json +17 -0
- package/skills/migrate/references/phases/enumerate.md +291 -0
- package/skills/migrate/references/phases/extract.md +652 -0
- package/skills/migrate/references/phases/parity.md +275 -0
- package/skills/migrate/references/phases/probe.md +135 -0
- package/skills/migrate/references/phases/queue.md +242 -0
- package/skills/migrate/references/phases/seam.md +416 -0
- package/skills/migrate/references/recipes/README.md +116 -0
- package/skills/migrate/references/recipes/aspnet.md +287 -0
- package/skills/migrate/references/run-ops.md +280 -0
- package/skills/migrate/scripts/__tests__/census.test.ts +775 -0
- package/skills/migrate/scripts/__tests__/check.test.ts +458 -0
- package/skills/migrate/scripts/__tests__/citations.test.ts +156 -0
- package/skills/migrate/scripts/__tests__/cli.test.ts +183 -0
- package/skills/migrate/scripts/__tests__/concurrency.test.ts +164 -0
- package/skills/migrate/scripts/__tests__/config.test.ts +112 -0
- package/skills/migrate/scripts/__tests__/e2e-express.test.ts +1093 -0
- package/skills/migrate/scripts/__tests__/e2e-webforms.test.ts +1276 -0
- package/skills/migrate/scripts/__tests__/e2e.test.ts +320 -0
- package/skills/migrate/scripts/__tests__/ids.test.ts +38 -0
- package/skills/migrate/scripts/__tests__/import.test.ts +155 -0
- package/skills/migrate/scripts/__tests__/init.test.ts +192 -0
- package/skills/migrate/scripts/__tests__/leaks.test.ts +176 -0
- package/skills/migrate/scripts/__tests__/lock.test.ts +183 -0
- package/skills/migrate/scripts/__tests__/paths.test.ts +129 -0
- package/skills/migrate/scripts/__tests__/phase-cmd.test.ts +151 -0
- package/skills/migrate/scripts/__tests__/phases.test.ts +70 -0
- package/skills/migrate/scripts/__tests__/queue.test.ts +475 -0
- package/skills/migrate/scripts/__tests__/report.test.ts +150 -0
- package/skills/migrate/scripts/__tests__/run-state.test.ts +136 -0
- package/skills/migrate/scripts/__tests__/status-reset.test.ts +318 -0
- package/skills/migrate/scripts/__tests__/store.test.ts +132 -0
- package/skills/migrate/scripts/__tests__/validate.test.ts +54 -0
- package/skills/migrate/scripts/census-cmd.ts +109 -0
- package/skills/migrate/scripts/census.ts +342 -0
- package/skills/migrate/scripts/check-cmd.ts +24 -0
- package/skills/migrate/scripts/check.ts +376 -0
- package/skills/migrate/scripts/citations.ts +92 -0
- package/skills/migrate/scripts/config.ts +237 -0
- package/skills/migrate/scripts/ids.ts +31 -0
- package/skills/migrate/scripts/import-cmd.ts +141 -0
- package/skills/migrate/scripts/init-cmd.ts +118 -0
- package/skills/migrate/scripts/leaks.ts +184 -0
- package/skills/migrate/scripts/lock.ts +188 -0
- package/skills/migrate/scripts/paths.ts +103 -0
- package/skills/migrate/scripts/phase-cmd.ts +63 -0
- package/skills/migrate/scripts/phases.ts +113 -0
- package/skills/migrate/scripts/queue-cmd.ts +98 -0
- package/skills/migrate/scripts/queue.ts +258 -0
- package/skills/migrate/scripts/report-cmd.ts +47 -0
- package/skills/migrate/scripts/report.ts +131 -0
- package/skills/migrate/scripts/reset-cmd.ts +120 -0
- package/skills/migrate/scripts/status-cmd.ts +52 -0
- package/skills/migrate/scripts/store.ts +159 -0
- package/skills/migrate/scripts/types.ts +137 -0
- package/skills/migrate/scripts/validate.ts +221 -0
- package/skills/migrate/skill.json +33 -0
- package/skills/migrate/templates/config.toml +27 -0
- package/skills/migrate/templates/queue-item.md +17 -0
- package/skills/migrate/tsconfig.json +18 -0
- package/skills/migrate/uninstall.sh +31 -0
- package/skills/sluice/SKILL.md +82 -0
- package/skills/sluice/references/deep-channel.md +94 -0
- package/skills/sluice/references/finish.md +35 -0
- package/skills/sluice/references/intent.md +29 -0
- package/skills/sluice/references/review.md +42 -0
- package/skills/sluice/references/root-cause.md +38 -0
- package/skills/sluice/references/show-or-say.md +36 -0
- package/skills/sluice/references/test-first.md +35 -0
- package/skills/sluice/references/verify.md +26 -0
- package/skills/sluice/skill.json +32 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# aspnet
|
|
2
|
+
|
|
3
|
+
Covers `[source].stack` values in the ASP.NET / .NET Framework family:
|
|
4
|
+
`aspnet-webforms`, `aspnet-mvc`, `aspnet-webapi`, and `dotnet-framework`. Real
|
|
5
|
+
ASP.NET sources routinely mix WebForms, MVC, and Web API in one checkout (a
|
|
6
|
+
WebForms app growing a Web API layer for AJAX calls is the common case), so
|
|
7
|
+
several surfaces below name more than the two-direction floor. That
|
|
8
|
+
granularity is extracted from a private plugin's own lens recipes that ran a
|
|
9
|
+
real migration campaign, where this mixing was the norm rather than the
|
|
10
|
+
exception.
|
|
11
|
+
|
|
12
|
+
Every probe uses `rg` (ripgrep). If it is not installed, `grep -rnE
|
|
13
|
+
--include='*.ext' '<pattern>' <path>` finds the same matches on real BSD
|
|
14
|
+
`grep`; the one place the exact pattern text has to differ between the two
|
|
15
|
+
tools is noted where it occurs (tables' raw-ADO probe). Replace `<source>`
|
|
16
|
+
with the checkout root. These are starting points, not a fixed script:
|
|
17
|
+
adapt the glob and the pattern to how a real source actually lays things
|
|
18
|
+
out, and the surface's lens census is what decides whether the result is
|
|
19
|
+
complete, not this file. See `references/recipes/README.md` for the
|
|
20
|
+
contract this file fills in, and `references/phases/enumerate.md` for the
|
|
21
|
+
contract itself.
|
|
22
|
+
|
|
23
|
+
Every probe below was run against four throwaway ASP.NET-shaped trees,
|
|
24
|
+
built independently of each other across three review rounds (different
|
|
25
|
+
directory layouts, different
|
|
26
|
+
C# formatting, different edge cases in the same construct, including
|
|
27
|
+
partial-class controllers, multi-part and bracket-quoted SQL identifiers,
|
|
28
|
+
and WebForms master pages) before being written down. Where a probe missed
|
|
29
|
+
something planted in one of those trees, or, worse, returned a name that
|
|
30
|
+
did not correspond to a real element, the probe was fixed and every tree
|
|
31
|
+
was re-checked; where a gap cannot be closed (noted per-direction below),
|
|
32
|
+
it is stated rather than the claim weakened around it. Independent review
|
|
33
|
+
against trees built without sight of these fixtures has twice found gaps
|
|
34
|
+
these trees did not exercise; each is folded into the fixes and disclosures
|
|
35
|
+
below rather than only into this file's revision history. Every direction
|
|
36
|
+
below has since been run against a committed fixture as well,
|
|
37
|
+
`fixtures/tiny-webforms`, by `scripts/__tests__/e2e-webforms.test.ts`, which
|
|
38
|
+
records each one's count with the probe command beside it as that count's
|
|
39
|
+
evidence, zero-finding directions included.
|
|
40
|
+
|
|
41
|
+
## routes
|
|
42
|
+
|
|
43
|
+
- **Attribute routing (code)**: HTTP-verb attributes (`[HttpGet]`,
|
|
44
|
+
`[HttpPost]`, ...), `[Route(...)]`, and `[RoutePrefix(...)]`, in any of
|
|
45
|
+
their C#-legal forms: bare (`[HttpGet]`, no parens), comma-combined with
|
|
46
|
+
another attribute in the same brackets (`[HttpPost, Route("")]`), or
|
|
47
|
+
spaced inside the brackets (`[ Route(...) ]`, `[Route (...)]`). A regex
|
|
48
|
+
anchored to `\(` right after the attribute name, an earlier version of
|
|
49
|
+
this probe, misses all of these except the plain parenthesised form.
|
|
50
|
+
Probe: `rg -n -g '*.cs' '[\[,]\s*(RoutePrefix|Route|HttpGet|HttpPost|HttpPut|HttpDelete|HttpPatch|HttpHead|HttpOptions)\b' <source>`
|
|
51
|
+
Known gap: this also matches the same words inside a comment or a string
|
|
52
|
+
(`// see [Route] above`), since the probe reads text, not parsed syntax.
|
|
53
|
+
That is a classification-time false positive for the enumerating agent to
|
|
54
|
+
skip, not something the regex can rule out.
|
|
55
|
+
Known gap, overcounting (RoutePrefix): a class-level `[RoutePrefix("...")]`
|
|
56
|
+
line matches too, and it annotates no action at all: it is a prefix
|
|
57
|
+
applied to every action underneath it, not a route of its own. Exclude it
|
|
58
|
+
entirely before counting anything; it is not a case of one action
|
|
59
|
+
matched twice, it is a line that never named an action to begin with.
|
|
60
|
+
This differs from convention routing's disclosed `MapRoute`/
|
|
61
|
+
`MapHttpRoute` gap in one important way: `MapRoute` is a separately
|
|
62
|
+
labelled supporting probe, run outside the regex this direction counts,
|
|
63
|
+
so nothing about it was ever in the tally to subtract from. `RoutePrefix`
|
|
64
|
+
is matched by the very regex this direction counts, so it has to be
|
|
65
|
+
subtracted from that count directly, a stronger and easier-to-miss
|
|
66
|
+
burden on the reader than a probe whose result was never combined with
|
|
67
|
+
this one's in the first place.
|
|
68
|
+
Known gap, overcounting (split attributes): the verb attribute and the
|
|
69
|
+
`Route` attribute frequently sit on separate lines rather than combined
|
|
70
|
+
in one bracket (`[HttpGet]` on one line, `[Route("...")]` on the next),
|
|
71
|
+
and both lines match, naming the same action twice. Run against a
|
|
72
|
+
controller with one `RoutePrefix` and three actions, each written with
|
|
73
|
+
its verb and `Route` attributes on separate lines, this probe returns
|
|
74
|
+
seven matched lines: one `RoutePrefix` plus two lines per action.
|
|
75
|
+
Excluding the `RoutePrefix` line (the paragraph above) leaves six;
|
|
76
|
+
deduplicating each action's two lines down to the one action they both
|
|
77
|
+
annotate leaves three, the count this direction reports, the same unit
|
|
78
|
+
convention routing counts, not the raw seven matched lines.
|
|
79
|
+
- **Convention routing (code)**: public action methods on a class whose name
|
|
80
|
+
contains `Controller`. A convention-routed action carries no attribute at
|
|
81
|
+
all, so the registration statement is not a stand-in for it: counting
|
|
82
|
+
`MapRoute` / `MapHttpRoute` calls instead of actions undercounts by orders
|
|
83
|
+
of magnitude, because one registration statement can service every
|
|
84
|
+
conventionally-routed action in the project. The count this direction
|
|
85
|
+
reports has to be actions, since that is the unit `routes` is counting.
|
|
86
|
+
The glob is `*Controller*.cs`, not the narrower `*Controller.cs`: a
|
|
87
|
+
partial class split across `ReportsController.cs` and
|
|
88
|
+
`ReportsController.Extra.cs` has actions in both files, and the narrower
|
|
89
|
+
glob never reaches the second one, which undercounts in exactly the way
|
|
90
|
+
that breaks `total <= sum(directions)` when nothing else is there to mask
|
|
91
|
+
it.
|
|
92
|
+
Probe: `rg -n -g '*Controller*.cs' 'public\s+\S+\s+\w+\s*\(' <source>`
|
|
93
|
+
Supporting evidence, not the count: `rg -n -g '*.cs' '\.MapRoute\(|MapHttpRoute\(' <source>`
|
|
94
|
+
confirms a conventional route table is actually registered, which is
|
|
95
|
+
worth knowing even though it does not say how many actions it serves.
|
|
96
|
+
Known gap, overlap: this probe's matches overlap the attribute-routing
|
|
97
|
+
direction above, because an attribute-routed action is still a public
|
|
98
|
+
method in a `*Controller*.cs` file. The two directions are not
|
|
99
|
+
independent counts of disjoint evidence; they are two ways of finding
|
|
100
|
+
some of the same actions plus each other's blind spots (attributes this
|
|
101
|
+
probe cannot see are named here, and conventionally-routed actions the
|
|
102
|
+
other probe cannot see are named there). Do not sum the two raw counts
|
|
103
|
+
into `total`: dedupe by action identity (class plus method, or the
|
|
104
|
+
resolved URL) the same way `enumerate.md`'s merge step already requires
|
|
105
|
+
whenever two directions both name the same real element, and record the
|
|
106
|
+
deduped count. Known gap, false positives: the widened glob also matches
|
|
107
|
+
a file like `UsersControllerTests.cs`, and the pattern itself matches a
|
|
108
|
+
comment or string shaped like a method signature, the same class of
|
|
109
|
+
false positive the attribute-routing direction discloses above; both are
|
|
110
|
+
classification-time calls for the enumerating agent, not something the
|
|
111
|
+
probe can rule out.
|
|
112
|
+
- **WebForms filesystem**: a `.aspx` page or `.ashx` handler is its own route
|
|
113
|
+
by virtue of existing on disk; there is no registration to grep for.
|
|
114
|
+
Probe: `find <source> -type f \( -name '*.aspx' -o -name '*.ashx' \)`
|
|
115
|
+
|
|
116
|
+
## tables
|
|
117
|
+
|
|
118
|
+
- **DDL and migrations**: `CREATE TABLE` statements in `.sql` scripts, and
|
|
119
|
+
the migration-builder calls that create a table without ever emitting
|
|
120
|
+
that literal text (EF Migrations' `migrationBuilder.CreateTable(`,
|
|
121
|
+
FluentMigrator's `Create.Table(`). A table defined only through a
|
|
122
|
+
migration and never in a static `.sql` file is invisible to the first
|
|
123
|
+
probe alone; the second is what catches it.
|
|
124
|
+
Probe: `rg -n -g '*.sql' -i '^\s*CREATE TABLE' <source>`
|
|
125
|
+
Probe: `rg -n -g '*.cs' 'migrationBuilder\.CreateTable\(|Create\.Table\(' <source>`
|
|
126
|
+
- **ORM**: EF `DbSet<T>` properties on a `DbContext`, and `[Table("...")]`
|
|
127
|
+
attributes on the mapped classes.
|
|
128
|
+
Probe: `rg -n -g '*.cs' 'DbSet<|\[Table\(' <source>`
|
|
129
|
+
- **Raw ADO command text**: table names embedded in `SqlCommand` /
|
|
130
|
+
`CommandText` strings, for code that never goes through the ORM at all.
|
|
131
|
+
This probe does not extract a name at all: an earlier version stripped the
|
|
132
|
+
match down to a single capture group (`-o -r '$2'`), and that convenience
|
|
133
|
+
is what let it fabricate a table name that never existed. A stray `UPDATE`
|
|
134
|
+
or `FROM` inside a comment (`// ... no FROM/INTO/UPDATE verb in the
|
|
135
|
+
command`) extracted the next bare word as if it were a real identifier,
|
|
136
|
+
and a three-part name (`FROM ReportingServer.dbo.Orders`) resolved to the
|
|
137
|
+
middle qualifier (`dbo`) instead of the table, the same bug Finding 4
|
|
138
|
+
closed one level down. A fabricated name is worse than a miss: it enters
|
|
139
|
+
the ledger looking exactly like a real one, and nothing downstream can
|
|
140
|
+
tell the difference. So this probe prints the whole matched line instead,
|
|
141
|
+
and a person or agent reads the actual table name out of it rather than
|
|
142
|
+
trusting an auto-extracted token.
|
|
143
|
+
Probe: `rg -n -g '*.cs' '(FROM|INTO|UPDATE)\s+((\[[^]]+\]|\w+)\.)*(\[[^]]+\]|\w+)' <source> | grep -Ev '^[^:]+:[0-9]+:[[:space:]]*//'`
|
|
144
|
+
The pattern itself also had to change to stop under-matching: `\w+` alone
|
|
145
|
+
cannot start on a bracket, so `UPDATE [dbo].[Invoices]`, the ordinary
|
|
146
|
+
SQL Server style for tooling-generated code, matched nothing at all
|
|
147
|
+
before this fix. The alternation `\[[^]]+\]|\w+` accepts either a
|
|
148
|
+
bracket-quoted segment or a plain identifier for every part of the name,
|
|
149
|
+
and `(...)*` repeats that for as many dot-separated qualifiers as the
|
|
150
|
+
source actually has (schema, database, linked server, or more), not just
|
|
151
|
+
one. The trailing `grep -Ev` drops a line whose first non-space character
|
|
152
|
+
is `//`, which is what would have caught the fabrication case above, and
|
|
153
|
+
nothing else: a trailing `// ...` after real code on the same line
|
|
154
|
+
survives, and so does any `/* ... */` block comment, whether it is a
|
|
155
|
+
standalone line or a continuation line inside a multi-line block (a line
|
|
156
|
+
starting with ` * `, the ordinary XML-doc and block-comment continuation
|
|
157
|
+
style, has no `//` at all and is not touched by this filter). Verified
|
|
158
|
+
directly: both a one-line `/* ... */` mentioning `UPDATE` and a
|
|
159
|
+
continuation line reading `* Continuation line mentioning UPDATE
|
|
160
|
+
dbo.Invoices...` inside a multi-line `/* */` block both pass through
|
|
161
|
+
unfiltered, each shown as its own real, unmodified line. That does not
|
|
162
|
+
reopen the fabrication this probe was fixed to close, since the full line
|
|
163
|
+
is still what is shown, but it is a hit a reader has to recognise as a
|
|
164
|
+
comment rather than one the pipeline discards for them.
|
|
165
|
+
Known gap, precisely: bracket-quoted (`[dbo].[Invoices]`) and plain
|
|
166
|
+
identifiers are handled, with any number of dot-separated qualifier
|
|
167
|
+
segments. Double-quoted ANSI identifiers (`"dbo"."Invoices"`) are not.
|
|
168
|
+
SQL-looking text inside an ordinary, verbatim, or interpolated string
|
|
169
|
+
literal that is not actually a `SqlCommand` argument (a log message, a
|
|
170
|
+
test fixture string, a piece of sample data) also matches and is shown as
|
|
171
|
+
a hit; it is an honest line, not a fabricated name, but a reader
|
|
172
|
+
classifying output will meet it and should expect to.
|
|
173
|
+
Stored-procedure calls (`SqlCommand("EXEC dbo.RecalculateLeadScore",
|
|
174
|
+
conn)`, or a `CommandType.StoredProcedure` command with the name set
|
|
175
|
+
separately) name a procedure, not a table, and carry none of the
|
|
176
|
+
`SELECT`/`INSERT`/`UPDATE` verb shapes this probe looks for, so they are
|
|
177
|
+
invisible to it by construction, not by an oversight this probe could
|
|
178
|
+
close. A table name built by string interpolation or concatenation
|
|
179
|
+
(`FROM {tableName}`, `FROM " + tbl`) is the same kind of construction gap:
|
|
180
|
+
the identifier a probe would need to report is not in the source text at
|
|
181
|
+
all. `rg -n -g '*.cs' '(FROM|INTO|UPDATE)\s+\{' <source>` at least flags
|
|
182
|
+
that call site for a person to trace by hand; it does not name the table.
|
|
183
|
+
The `grep -rE --include` fallback for the primary probe above matches
|
|
184
|
+
identically on real BSD `grep`, with one substitution: BSD grep does not
|
|
185
|
+
accept `\]` as an escaped literal inside a negated bracket expression
|
|
186
|
+
(`[^\]]` silently matches nothing, with no error message), so the class
|
|
187
|
+
must be written `[^]]`, with the `]` placed first, which both `rg` and BSD
|
|
188
|
+
`grep` accept the same way.
|
|
189
|
+
|
|
190
|
+
## jobs
|
|
191
|
+
|
|
192
|
+
- **Quartz.NET**: `IJob` implementations and `JobBuilder` / `ScheduleJob`
|
|
193
|
+
registrations.
|
|
194
|
+
Probe: `rg -n -g '*.cs' 'IJob\b|JobBuilder\.Create|ScheduleJob\(' <source>`
|
|
195
|
+
- **Hangfire**: `RecurringJob` and `BackgroundJob` call sites.
|
|
196
|
+
Probe: `rg -n -g '*.cs' 'RecurringJob\.|BackgroundJob\.' <source>`
|
|
197
|
+
Known gap: a job registered through DI (`services.AddHangfire(...)`,
|
|
198
|
+
an injected `IRecurringJobManager`'s `.AddOrUpdate(...)`) never calls the
|
|
199
|
+
static `RecurringJob`/`BackgroundJob` methods this probe looks for, so it
|
|
200
|
+
is invisible to a static-call-only probe. A separate probe for
|
|
201
|
+
`AddHangfire\(|IRecurringJobManager\b` would find the registration site,
|
|
202
|
+
not the job itself, and this recipe does not attempt that second probe.
|
|
203
|
+
- **OS/config scheduling**: exported Windows Task Scheduler XML, and
|
|
204
|
+
scheduling-flavored `web.config` `appSettings` entries (a cron string, an
|
|
205
|
+
interval key), for jobs that were never wired through a .NET scheduler
|
|
206
|
+
library at all.
|
|
207
|
+
Probe: `rg -n -g '*.xml' -g '*.config' -i 'cron|schedule|<Task version' <source>`
|
|
208
|
+
|
|
209
|
+
## reports
|
|
210
|
+
|
|
211
|
+
- **Definitions on disk**: SSRS `.rdl` and `.rdlc` files.
|
|
212
|
+
Probe: `find <source> -type f \( -name '*.rdl' -o -name '*.rdlc' \)`
|
|
213
|
+
- **Menu and navigation entries**: report links in a site map, a Razor
|
|
214
|
+
layout, a WebForms master page, or a nav/menu partial. Scoping to
|
|
215
|
+
`*.sitemap` alone misses an MVC application's ordinary navigation, which
|
|
216
|
+
lives in `_Layout.cshtml`, and misses a WebForms application's, which
|
|
217
|
+
lives in a `.master` page; a checkout mixing WebForms and MVC, which this
|
|
218
|
+
recipe's own preamble says is the common case, needs all of these globs,
|
|
219
|
+
not just the sitemap. These can also name a report the checkout no
|
|
220
|
+
longer ships an `.rdl` for.
|
|
221
|
+
Probe: `rg -n -g '*.sitemap' -g '_Layout.cshtml' -g '*.master' -g '*Nav*.cshtml' -g '*Menu*.cshtml' -i 'report' <source>`
|
|
222
|
+
Known gap: a menu built entirely from a database table (a `Menus` or
|
|
223
|
+
`NavigationItems` row set rendered at runtime, with no report name ever
|
|
224
|
+
written into any file this probe reads) is unreachable by any grep
|
|
225
|
+
probe, the same class of gap as the string-interpolated table name
|
|
226
|
+
disclosed under `tables` above: the identifier does not exist in the
|
|
227
|
+
source text.
|
|
228
|
+
- **Report-builder registrations**: a catalog class or config section that
|
|
229
|
+
maps a report key to its `.rdl` / `.rdlc` path, independent of both
|
|
230
|
+
directions above.
|
|
231
|
+
Probe: `rg -n -g '*.cs' '\.rdlc?"' <source>`
|
|
232
|
+
|
|
233
|
+
## screens
|
|
234
|
+
|
|
235
|
+
- **Filesystem**: `.aspx` pages (WebForms) and `.cshtml` views (MVC). A
|
|
236
|
+
shared layout or partial (`_Layout.cshtml`) matches the same glob; telling
|
|
237
|
+
it apart from an actual screen is the enumerating agent's classification
|
|
238
|
+
call, not something a filename pattern can make for it.
|
|
239
|
+
Probe: `find <source> -type f \( -name '*.aspx' -o -name '*.cshtml' \)`
|
|
240
|
+
- **Sitemap/nav registration**: entries in `Web.sitemap`, a Razor layout, a
|
|
241
|
+
WebForms master page, or a nav/menu partial. Same scoping gap as the
|
|
242
|
+
reports direction above, in both dimensions: an MVC application's real
|
|
243
|
+
navigation usually lives in `_Layout.cshtml`, and a WebForms
|
|
244
|
+
application's in a `.master` page, neither a sitemap; the content pattern
|
|
245
|
+
also has to cover a plain WebForms anchor (`href="~/..."`) or server nav
|
|
246
|
+
control (`NavigateUrl="~/..."`), not only the sitemap's XML `url=`
|
|
247
|
+
attribute or MVC's `Html.ActionLink`/`Url.Action`, since a `.master` page
|
|
248
|
+
almost never uses the latter two.
|
|
249
|
+
Probe: `rg -n -g '*.sitemap' -g '_Layout.cshtml' -g '*.master' -g '*Nav*.cshtml' -g '*Menu*.cshtml' '(url|href|NavigateUrl)="~/|Html\.ActionLink\(|Url\.Action\(' <source>`
|
|
250
|
+
Known gap: the same database-driven menu gap disclosed under `reports`
|
|
251
|
+
above applies here identically, since both directions read the same
|
|
252
|
+
files for the same reason.
|
|
253
|
+
|
|
254
|
+
## integrations
|
|
255
|
+
|
|
256
|
+
- **Outbound HTTP call sites (code)**: `HttpClient` and `WebClient`
|
|
257
|
+
construction.
|
|
258
|
+
Probe: `rg -n -g '*.cs' 'new HttpClient\(|new WebClient\(' <source>`
|
|
259
|
+
- **WCF service references (code)**: `ClientBase<T>` / `ChannelFactory<T>`
|
|
260
|
+
proxies and `[ServiceContract]` interfaces.
|
|
261
|
+
Probe: `rg -n -g '*.cs' 'ClientBase<|ChannelFactory<|\[ServiceContract\]' <source>`
|
|
262
|
+
- **Configured endpoints**: `<endpoint>` entries under
|
|
263
|
+
`<system.serviceModel><client>` in `web.config`, which can name an
|
|
264
|
+
integration no call site in code constructs directly (a proxy generated
|
|
265
|
+
entirely from config at runtime).
|
|
266
|
+
Probe: `rg -n -g '*.config' '<endpoint\b' <source>`
|
|
267
|
+
|
|
268
|
+
## workflows
|
|
269
|
+
|
|
270
|
+
- **Multi-step controller flow (code)**: a wizard-shaped controller with
|
|
271
|
+
sequentially named actions (`Step1`, `Step2`, ...).
|
|
272
|
+
Probe: `rg -n -g '*.cs' 'ActionResult Step[0-9]+' <source>`
|
|
273
|
+
- **State carriers (code)**: `Session[...]` and `TempData[...]` reads and
|
|
274
|
+
writes tying those steps together, independent of how the actions
|
|
275
|
+
themselves happen to be named.
|
|
276
|
+
Probe: `rg -n -g '*.cs' 'Session\[|TempData\[' <source>`
|
|
277
|
+
|
|
278
|
+
## settings
|
|
279
|
+
|
|
280
|
+
- **Storage**: `appSettings` and `connectionStrings` entries in
|
|
281
|
+
`web.config`.
|
|
282
|
+
Probe: `rg -n -g '*.config' '<add (key|name)=' <source>`
|
|
283
|
+
- **Read sites**: `ConfigurationManager.AppSettings[...]` and
|
|
284
|
+
`ConfigurationManager.ConnectionStrings[...]` reads in code, which can name
|
|
285
|
+
a key `web.config` never declares (an environment-variable override, a key
|
|
286
|
+
added only at deploy time).
|
|
287
|
+
Probe: `rg -n -g '*.cs' 'ConfigurationManager\.(AppSettings|ConnectionStrings)' <source>`
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Run operations
|
|
2
|
+
|
|
3
|
+
This file holds what is true across every phase of a run rather than any one
|
|
4
|
+
of them: how the orchestrator dispatches subagents, how their work gets
|
|
5
|
+
checkpointed into the store, what happens when a subagent goes quiet, and
|
|
6
|
+
what an agent sees when it contends with another for the store lock.
|
|
7
|
+
`SKILL.md`'s Aborting section names the batch-checkpoint discipline and says
|
|
8
|
+
Aborting assumes it was followed; `references/phases/enumerate.md` and
|
|
9
|
+
`references/phases/extract.md` both point here for dispatch and checkpoint
|
|
10
|
+
mechanics instead of restating them. This file is what they are pointing at.
|
|
11
|
+
|
|
12
|
+
This is not a phase manual. The six-section shape every file under
|
|
13
|
+
`references/phases/` uses (Purpose, Inputs, Procedure, What closes it,
|
|
14
|
+
Degradation, Commands) does not fit here: there is no single phase this file
|
|
15
|
+
belongs to, and nothing below is an exit condition `migrate check` gates.
|
|
16
|
+
|
|
17
|
+
A note on how to read what follows. Dispatch and the watchdog are
|
|
18
|
+
orchestration policy carried from a real migration campaign; nothing in the
|
|
19
|
+
CLI enforces a pulse interval or a discovery order, so those sections are
|
|
20
|
+
marked as guidance. The batch checkpoint loop and the store lock are
|
|
21
|
+
different: every claim about their mechanics, message text, and exit codes
|
|
22
|
+
below was run against a scratch store while writing this file, not recalled
|
|
23
|
+
or paraphrased.
|
|
24
|
+
|
|
25
|
+
## Dispatch
|
|
26
|
+
|
|
27
|
+
Guidance, not CLI-enforced.
|
|
28
|
+
|
|
29
|
+
The orchestrator does source discovery itself, inline, before dispatching
|
|
30
|
+
anything. A subagent it dispatches starts at classification, not discovery,
|
|
31
|
+
with verified paths already in the prompt. A subagent that has to rediscover
|
|
32
|
+
its own paths is a subagent re-deriving something the orchestrator already
|
|
33
|
+
resolved, on its own dime, and re-litigating a decision that has already been
|
|
34
|
+
made once.
|
|
35
|
+
|
|
36
|
+
One lens per agent when lenses are heavy. Fanout unit is (surface, lens) in
|
|
37
|
+
phase 1 (enumerate) and capability in phase 3 (extract): an agent enumerating
|
|
38
|
+
`routes` under the `code` lens never needs to know what the `nav` lens found
|
|
39
|
+
for the same surface, and an agent mining `user-management` never needs to
|
|
40
|
+
know what `invoicing` looks like.
|
|
41
|
+
|
|
42
|
+
## The batch checkpoint loop
|
|
43
|
+
|
|
44
|
+
Enforced. Every claim in this section was run.
|
|
45
|
+
|
|
46
|
+
Agents never write JSONL directly. The loop is:
|
|
47
|
+
|
|
48
|
+
1. **Accumulate roughly ten rows** of findings in memory (a lens's elements,
|
|
49
|
+
a capability's requirements, whatever the current phase produces).
|
|
50
|
+
2. **Write them to a batch file** (`batch.json`, or any name you choose) in
|
|
51
|
+
the envelope shape `references/phases/*.md` and `docs/reference.md`
|
|
52
|
+
describe: `{"batch": "...", "phase": "...", "rows": [...]}`.
|
|
53
|
+
3. **Run `migrate import`** (`elements`, `reqs`, or `deltas`, matching what
|
|
54
|
+
you accumulated).
|
|
55
|
+
4. **Commit.** A git commit right after the import succeeds is the
|
|
56
|
+
checkpoint. If the run is aborted or crashes anywhere after this point,
|
|
57
|
+
`.migrate/` at the last commit is a complete, valid store as of that
|
|
58
|
+
batch; nothing between commits needs to be recreated by memory, because
|
|
59
|
+
nothing important was ever only in memory.
|
|
60
|
+
|
|
61
|
+
**Validation happens at write time, so a malformed row cannot enter the
|
|
62
|
+
store.** Import is all-or-nothing: one invalid row in a batch means nothing
|
|
63
|
+
in that batch is written, not a partial batch you'd have to reason about on
|
|
64
|
+
resume. Run against a scratch store, a batch with one row missing its
|
|
65
|
+
`element` text produced:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
import: element route-get-api-orders-detail: missing element text
|
|
69
|
+
import: 1 error(s), nothing written
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Exit `1`. The element count in `elements.jsonl` was unchanged; the one good
|
|
73
|
+
row in that same batch was not written either, because the batch is the unit.
|
|
74
|
+
|
|
75
|
+
**The batch id lands in `phases.json`, which is what makes the checkpoint
|
|
76
|
+
mechanical rather than remembered.** A successful import appends the batch's
|
|
77
|
+
id and row count to that phase's `batches` array. `savePhases` writes the file
|
|
78
|
+
with `JSON.stringify(file, null, 2)`, so every phase nests under a top-level
|
|
79
|
+
`"phases"` key beside a `"version"`, and each batch object spreads across four
|
|
80
|
+
lines rather than sitting on one. Real content of `.migrate/phases.json` after
|
|
81
|
+
two imports into `enumerate`, copied out of the file unedited, indentation
|
|
82
|
+
included:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"version": 1,
|
|
87
|
+
"phases": {
|
|
88
|
+
"probe": {
|
|
89
|
+
"status": "pending",
|
|
90
|
+
"batches": [],
|
|
91
|
+
"pending": []
|
|
92
|
+
},
|
|
93
|
+
"enumerate": {
|
|
94
|
+
"status": "running",
|
|
95
|
+
"batches": [
|
|
96
|
+
{
|
|
97
|
+
"id": "b-routes-code-001",
|
|
98
|
+
"count": 1
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "b-routes-code-002",
|
|
102
|
+
"count": 1
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"pending": []
|
|
106
|
+
},
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
(the remaining six phases follow in the same shape, each still `pending` with
|
|
110
|
+
an empty `batches`, and are cut here for length; nothing about them differs
|
|
111
|
+
from `probe` above.)
|
|
112
|
+
|
|
113
|
+
Nobody has to remember which batches already landed: `migrate status` and
|
|
114
|
+
`migrate phase enumerate` both read this array back, which is what makes
|
|
115
|
+
resuming a crashed run a read rather than a recollection.
|
|
116
|
+
|
|
117
|
+
## When the store is locked
|
|
118
|
+
|
|
119
|
+
Enforced. Every claim in this section was run.
|
|
120
|
+
|
|
121
|
+
`import`, `census`, `phase --status`, and `reset` each take one lock over the
|
|
122
|
+
whole store (`.migrate/.lock`) for the length of their read-modify-write. Those
|
|
123
|
+
four are the whole set; every other command either only reads the store, or
|
|
124
|
+
does not touch it. Without
|
|
125
|
+
it, two agents importing at once each read the same base file, and whichever
|
|
126
|
+
one rewrites last silently discards the other's rows. The default wait is 30
|
|
127
|
+
seconds, polling with backoff (25ms, growing by roughly 1.5x each attempt, up
|
|
128
|
+
to a 250ms cap; read directly from `scripts/lock.ts`, not independently timed
|
|
129
|
+
here). A wait longer than that, or a lock file that looks broken rather than
|
|
130
|
+
merely held, ends in exit `3`.
|
|
131
|
+
|
|
132
|
+
**Exit `3` means retry, not fix the batch.** It is its own code, distinct
|
|
133
|
+
from `1` (a content or domain failure: your batch or query was well-formed
|
|
134
|
+
and the answer is no) and `2` (a malformed request: a bad flag, a missing
|
|
135
|
+
file). A lock failure says the request itself was fine; there is nothing
|
|
136
|
+
about your `batch.json`, or about the `--phase` you named, to go back and
|
|
137
|
+
inspect, regardless of which of the three ways below the lock failed. (Three
|
|
138
|
+
ways the lock can fail, not three commands that take it: four commands do,
|
|
139
|
+
listed above.)
|
|
140
|
+
|
|
141
|
+
That said, "retry" resolves the three underlying causes differently, and only
|
|
142
|
+
one of them clears on its own. Verified against a scratch store: a lock held
|
|
143
|
+
by a genuinely live process that outlasted the 30-second timeout produced the
|
|
144
|
+
timeout message and exit `3` on the first attempt (elapsed 30.091s), then, on
|
|
145
|
+
a second attempt with nothing else changed, waited out the remaining hold and
|
|
146
|
+
succeeded on its own once that process actually released the lock (elapsed
|
|
147
|
+
4.627s, exit `0`, no `--force-unlock` involved). An ordinary contended or
|
|
148
|
+
slow lock genuinely does resolve with a bare retry, possibly more than one.
|
|
149
|
+
The two stale conditions below do not: retried bare, with no other change, a
|
|
150
|
+
corrupt lock file produced the identical exit `3` message on a second
|
|
151
|
+
attempt, immediately, because nothing about the file is different the second
|
|
152
|
+
time. Retry is the right first move for exit `3` in general; only
|
|
153
|
+
`--force-unlock`, after confirming safety, moves a stale lock forward.
|
|
154
|
+
|
|
155
|
+
**What a waiting agent sees.** `import`, `census`, and `reset` announce the
|
|
156
|
+
wait on stderr, once, the first time they see a live holder. Verified against a
|
|
157
|
+
scratch store, holding the lock with a real running process and then
|
|
158
|
+
attempting an import produced (path and pid shortened for readability; the
|
|
159
|
+
message text is exact):
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
import: waiting for store lock (held by pid 51234 since 2026-08-07T09:14:02.001Z)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
`phase --status` is the one that does not print this line. It waits on the
|
|
166
|
+
same lock with the same backoff, silently: run against a scratch store with a
|
|
167
|
+
live holder released two seconds in, `migrate phase enumerate --status running`
|
|
168
|
+
printed nothing at all until it succeeded, 1.85 seconds later. `reset` does
|
|
169
|
+
print it, verified the same way against a live holder released two seconds in:
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
reset: waiting for store lock (held by pid 74987 since 2026-08-08T00:00:00.000Z)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
If the wait for any of the four ends in a timeout instead, all four report it
|
|
176
|
+
the same way, with their own command name prefixed:
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
import: timed out after 30000ms waiting for the store lock held by pid 51234 since 2026-08-07T09:14:02.001Z
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Verified with a real 30-second wait against a live holder (elapsed time
|
|
183
|
+
measured at 30.070s): the timeout is real, not advisory, and the message
|
|
184
|
+
names the same holder the waiting announcement did. When the lock file
|
|
185
|
+
itself is absent for the whole timeout instead of naming a holder, the
|
|
186
|
+
message falls back to naming the path instead:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
import: timed out after 30000ms waiting for the store lock at /repo/.migrate/.lock
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Two conditions are refused immediately rather than waited out**, because
|
|
193
|
+
neither one is a lock that contention will ever resolve on its own: a holder
|
|
194
|
+
pid that has confirmed exited, and a lock file that fails to parse five
|
|
195
|
+
reads in a row. Verified against a scratch store, both returned in well
|
|
196
|
+
under a second, not anywhere near the 30-second timeout (0.031s and 0.259s
|
|
197
|
+
respectively in the runs that produced these):
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
import: store lock held by pid 51234, which is not running. Re-run with --force-unlock after confirming no other agent is writing
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
```
|
|
204
|
+
import: store lock at /repo/.migrate/.lock is unreadable; re-run with --force-unlock after confirming no other agent is writing
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Both messages, and the timeout messages above, are copied verbatim from
|
|
208
|
+
`scripts/lock.ts`; only the pid, timestamp, and path are illustrative. Note
|
|
209
|
+
the two stale messages are not identically punctuated in the source (one
|
|
210
|
+
capitalizes "Re-run" after a period, the other lowercases "re-run" after a
|
|
211
|
+
semicolon) and this file preserves that rather than smoothing it over, so
|
|
212
|
+
what you read here matches what you'll see on screen exactly.
|
|
213
|
+
|
|
214
|
+
**`--force-unlock` is only appropriate after confirming the named pid is not
|
|
215
|
+
running and no other agent is mid-write.** It exists on `import`, `census`,
|
|
216
|
+
`phase`, and `reset`, the same four commands that take the lock at all.
|
|
217
|
+
Verified against a scratch store holding a dead holder's lock: each of the four
|
|
218
|
+
exits `3` without the flag and `0` with it. `reset` matters most here of the
|
|
219
|
+
four, since it is the one whose whole job is deleting rows. What it actually
|
|
220
|
+
does is blunt: it unlinks the lock file
|
|
221
|
+
unconditionally, before this process even checks who, if anyone, holds it.
|
|
222
|
+
The CLI does not verify staleness for you when you pass this flag; the
|
|
223
|
+
message says "after confirming no other agent is writing" because that
|
|
224
|
+
confirmation is entirely on you.
|
|
225
|
+
|
|
226
|
+
**Forcing a lock a live agent holds will lose that agent's rows.** If the
|
|
227
|
+
current holder is genuinely mid read-modify-write, unlinking its lock file
|
|
228
|
+
does not stop it. Both processes now race to rewrite the same store file, and
|
|
229
|
+
whichever one finishes and renames last wins, silently discarding whatever
|
|
230
|
+
the other one wrote. This is exactly the hazard the lock exists to prevent in
|
|
231
|
+
the first place, just re-opened by force. Confirm the named pid is actually
|
|
232
|
+
gone (not merely busy) before reaching for this flag, not after.
|
|
233
|
+
|
|
234
|
+
Verified: forcing a lock whose holder pid had genuinely exited (`pid 999999`,
|
|
235
|
+
not present on the system) removed the lock file and let the import through
|
|
236
|
+
in the same call:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
import elements: 1 added, 0 updated, batch b-routes-code-002
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Watchdog
|
|
243
|
+
|
|
244
|
+
Guidance, not CLI-enforced.
|
|
245
|
+
|
|
246
|
+
Pulse roughly every 30 minutes on a dispatched subagent that has been running
|
|
247
|
+
a while. Movement in its transcript (a tool call, a written batch, anything)
|
|
248
|
+
means it is alive; let it keep going. No movement gets exactly one resume,
|
|
249
|
+
and that resume says write-first: whatever findings it is holding, checkpoint
|
|
250
|
+
them (batch, import, commit) before doing anything else. Still nothing after
|
|
251
|
+
that resume means abandon the subagent and do the remaining work inline,
|
|
252
|
+
never send a second resume. A transcript that has already gone quiet once and
|
|
253
|
+
been resumed once is a transcript that keeps growing every time you poke it,
|
|
254
|
+
and a resumed transcript eventually becomes unresumable from bloat alone, so
|
|
255
|
+
the second attempt is not a smaller version of the first risk, it is a worse
|
|
256
|
+
one.
|
|
257
|
+
|
|
258
|
+
## Report verification
|
|
259
|
+
|
|
260
|
+
Guidance for prose reports; the numeric part is now enforced by `migrate
|
|
261
|
+
check` instead.
|
|
262
|
+
|
|
263
|
+
The rule that every number in a report must be re-derived by a command the
|
|
264
|
+
writer actually ran exists because, before there was a store, coverage
|
|
265
|
+
arithmetic was hand-written and hand-verified, and the hand-written numbers
|
|
266
|
+
were wrong more than once. With the census living in the store, `migrate
|
|
267
|
+
check` (and `migrate status`) is the derivation: the coverage line, the
|
|
268
|
+
census balance, the run-state gate are commands, not claims someone typed.
|
|
269
|
+
The re-derive rule now narrows to prose: a queue item's evidence section, a
|
|
270
|
+
seam validator's raw script output, anything written in English about what a
|
|
271
|
+
lens or a validator found. Those still need to be something a command
|
|
272
|
+
actually produced or a person actually observed, quoted rather than
|
|
273
|
+
summarized from memory, for exactly the reason the original rule existed.
|
|
274
|
+
|
|
275
|
+
**Scorer and mapper stay separated for benchmark runs.** When the method
|
|
276
|
+
itself is being validated against a benchmark rather than run against a live
|
|
277
|
+
migration, the agent producing the mapping and the agent scoring it against
|
|
278
|
+
ground truth must not be the same agent, and must not share context that
|
|
279
|
+
would let one see the other's answer. This is a v1 documented discipline,
|
|
280
|
+
not a CLI verb; `migrate` has no benchmark command in this milestone.
|