arkgate 3.0.0 → 3.0.1
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/CHANGELOG.md +21 -1
- package/README.md +16 -14
- package/bin/ark-check.mjs +10 -2
- package/bin/lib/ci-and-commands.mjs +20 -15
- package/bin/lib/design-smells.mjs +434 -0
- package/bin/lib/doctor-plan.mjs +149 -16
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/docs/agent-guide.md +6 -0
- package/docs/brownfield-adoption.md +52 -1
- package/docs/package-surface.md +2 -0
- package/package.json +1 -1
- package/server.json +2 -2
- package/templates/skills/ark-adopt.md +26 -3
- package/templates/skills/ark-architect.md +7 -0
- package/templates/skills/ark-autopilot.md +37 -20
- package/templates/skills/ark-contract.md +7 -0
- package/templates/skills/ark-coverage.md +44 -45
- package/templates/skills/ark-explain.md +8 -0
- package/templates/skills/ark-explore.md +117 -47
- package/templates/skills/ark-fix.md +22 -0
- package/templates/skills/ark-loop.md +15 -1
- package/templates/skills/ark-place.md +7 -0
- package/templates/skills/ark-think.md +24 -20
package/bin/lib/doctor-plan.mjs
CHANGED
|
@@ -25,6 +25,12 @@ import {
|
|
|
25
25
|
violationEdge,
|
|
26
26
|
} from './violations.mjs';
|
|
27
27
|
import { buildUnclassifiedSuggestions } from './suggestions.mjs';
|
|
28
|
+
import {
|
|
29
|
+
detectDesignSmells,
|
|
30
|
+
buildPatternBetsFromSmells,
|
|
31
|
+
summarizeDesignFitness,
|
|
32
|
+
isDesignWeak,
|
|
33
|
+
} from './design-smells.mjs';
|
|
28
34
|
|
|
29
35
|
const color = {
|
|
30
36
|
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
@@ -142,7 +148,25 @@ export function runCoverage(root, config, files, rules, asJson) {
|
|
|
142
148
|
// Co-pilot Phase F — turn active violations into a classified, ordered remediation PLAN with an
|
|
143
149
|
// embedded GOAL. This is the `plan` primitive the future apply-loop (Phase H, `loop`) consumes
|
|
144
150
|
// and the autopilot (Phase I) drives toward the `goal`. Read-only: it changes no files.
|
|
145
|
-
|
|
151
|
+
/**
|
|
152
|
+
* @param {string} root
|
|
153
|
+
* @param {object[]} activeViolations
|
|
154
|
+
* @param {number|null} [governedPercent]
|
|
155
|
+
* @param {number|null} [totalFiles]
|
|
156
|
+
* @param {object} [options]
|
|
157
|
+
* @param {object[]} [options.designSmells]
|
|
158
|
+
* @param {object[]} [options.patternBets]
|
|
159
|
+
* @param {object} [options.config]
|
|
160
|
+
* @param {string[]} [options.files]
|
|
161
|
+
* @param {object} [options.coverage]
|
|
162
|
+
*/
|
|
163
|
+
export function buildRemediationPlan(
|
|
164
|
+
root,
|
|
165
|
+
activeViolations,
|
|
166
|
+
governedPercent = null,
|
|
167
|
+
totalFiles = null,
|
|
168
|
+
options = {}
|
|
169
|
+
) {
|
|
146
170
|
// A plan with 0 violations but ~0% governed (or ZERO files in scope) is a FALSE green:
|
|
147
171
|
// nothing is actually being checked. Treat as "not done — classify / fix include first."
|
|
148
172
|
const governedLow = governedPercent != null && governedPercent < 50;
|
|
@@ -177,20 +201,54 @@ export function buildRemediationPlan(root, activeViolations, governedPercent = n
|
|
|
177
201
|
judgment: countOf('judgment'),
|
|
178
202
|
deferred: countOf('deferred'),
|
|
179
203
|
};
|
|
204
|
+
|
|
205
|
+
// Plan B (pattern bets) — never mechanical-safe; additive within major (P03).
|
|
206
|
+
let designSmells = options.designSmells;
|
|
207
|
+
if (!designSmells && options.config && options.files) {
|
|
208
|
+
designSmells = detectDesignSmells(
|
|
209
|
+
root,
|
|
210
|
+
options.config,
|
|
211
|
+
options.files,
|
|
212
|
+
options.coverage ?? null
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
designSmells = designSmells ?? [];
|
|
216
|
+
const patternBets =
|
|
217
|
+
options.patternBets ?? buildPatternBetsFromSmells(designSmells);
|
|
218
|
+
const edgesMet = activeViolations.length === 0 && !notHonestlyEnforced;
|
|
219
|
+
const designWeak = isDesignWeak(designSmells, {
|
|
220
|
+
activeViolations: activeViolations.length,
|
|
221
|
+
governedPercent,
|
|
222
|
+
totalFiles,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
let statement =
|
|
226
|
+
activeViolations.length > 0
|
|
227
|
+
? `Resolve ${activeViolations.length} architecture violation(s) without weakening the contract.`
|
|
228
|
+
: emptyScope
|
|
229
|
+
? 'No source files matched the contract include paths — this "clean" result checks nothing. Fix include/layers (monorepo → apps/packages, or /ark-adopt) so Ark has real code to govern.'
|
|
230
|
+
: governedLow
|
|
231
|
+
? `No violations — but Ark governs only ${governedPercent}% of your code, so this "clean" result checks almost nothing. Classify the rest (ark-check --coverage, then /ark-adopt) so it's actually enforced.`
|
|
232
|
+
: 'No active violations — the architecture already meets its contract.';
|
|
233
|
+
if (designWeak) {
|
|
234
|
+
statement =
|
|
235
|
+
'No active edge violations — contract edges are clean, but design smells remain (ENFORCE · design-weak). Shape residual is plan B only; not healthy finished.';
|
|
236
|
+
}
|
|
237
|
+
|
|
180
238
|
return {
|
|
181
239
|
version: '1',
|
|
182
240
|
goal: {
|
|
183
|
-
statement
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
241
|
+
statement,
|
|
242
|
+
// Edge remediation termination (Phase H). Design-weak does NOT flip met false
|
|
243
|
+
// (would break loop semantics) — it is reported separately for honesty.
|
|
244
|
+
met: edgesMet,
|
|
245
|
+
designWeak,
|
|
246
|
+
...(designWeak
|
|
247
|
+
? {
|
|
248
|
+
designWeakLabel:
|
|
249
|
+
'ENFORCE · design-weak — use patternBets / dual-plan B; never auto-apply as mechanical-safe',
|
|
250
|
+
}
|
|
251
|
+
: {}),
|
|
194
252
|
...(governedPercent != null ? { governedPercent } : {}),
|
|
195
253
|
...(totalFiles != null ? { totalFiles } : {}),
|
|
196
254
|
...(emptyScope ? { emptyScope: true } : {}),
|
|
@@ -198,17 +256,38 @@ export function buildRemediationPlan(root, activeViolations, governedPercent = n
|
|
|
198
256
|
autoApplicable: counts.mechanicalSafe,
|
|
199
257
|
needsDecision: counts.judgment,
|
|
200
258
|
deferred: counts.deferred,
|
|
259
|
+
patternBetCount: patternBets.length,
|
|
201
260
|
},
|
|
202
261
|
counts,
|
|
203
262
|
steps,
|
|
263
|
+
// Additive: pattern evolution bets derived from design smells (never auto).
|
|
264
|
+
patternBets,
|
|
265
|
+
designSmells,
|
|
204
266
|
};
|
|
205
267
|
}
|
|
206
268
|
|
|
207
269
|
// `--plan`: print the classified remediation plan. Dual-focus output — a one-line headline
|
|
208
270
|
// anyone can read, then the per-step detail a developer acts on. Read-only.
|
|
209
|
-
|
|
210
|
-
|
|
271
|
+
/**
|
|
272
|
+
* @param {object} [options] optional { config, files, coverage, designSmells, patternBets }
|
|
273
|
+
*/
|
|
274
|
+
export function runPlan(
|
|
275
|
+
root,
|
|
276
|
+
activeViolations,
|
|
277
|
+
asJson,
|
|
278
|
+
governedPercent = null,
|
|
279
|
+
totalFiles = null,
|
|
280
|
+
options = {}
|
|
281
|
+
) {
|
|
282
|
+
const plan = buildRemediationPlan(
|
|
283
|
+
root,
|
|
284
|
+
activeViolations,
|
|
285
|
+
governedPercent,
|
|
286
|
+
totalFiles,
|
|
287
|
+
options
|
|
288
|
+
);
|
|
211
289
|
// Honesty: a zero-violation plan with almost nothing governed is NOT "ok".
|
|
290
|
+
// design-weak still ok:true for edge goal.met, but JSON carries designWeak + patternBets.
|
|
212
291
|
const planOk = plan.goal.met === true;
|
|
213
292
|
if (asJson) {
|
|
214
293
|
console.log(JSON.stringify({ ok: planOk, plan }, null, 2));
|
|
@@ -217,6 +296,13 @@ export function runPlan(root, activeViolations, asJson, governedPercent = null,
|
|
|
217
296
|
console.log(color.bold(`Ark plan — ${path.basename(path.resolve(root)) || '.'}`));
|
|
218
297
|
console.log('');
|
|
219
298
|
console.log(plan.goal.statement);
|
|
299
|
+
if (plan.goal.designWeak) {
|
|
300
|
+
console.log(
|
|
301
|
+
color.yellow(
|
|
302
|
+
` ENFORCE · design-weak — ${plan.patternBets?.length ?? 0} pattern bet(s) (never auto-apply)`
|
|
303
|
+
)
|
|
304
|
+
);
|
|
305
|
+
}
|
|
220
306
|
if (governedPercent != null) {
|
|
221
307
|
const pctLabel =
|
|
222
308
|
governedPercent < 50
|
|
@@ -224,6 +310,14 @@ export function runPlan(root, activeViolations, asJson, governedPercent = null,
|
|
|
224
310
|
: color.dim(`Governed: ${governedPercent}% of in-scope files`);
|
|
225
311
|
console.log(pctLabel);
|
|
226
312
|
}
|
|
313
|
+
if (plan.patternBets?.length && activeViolations.length === 0) {
|
|
314
|
+
console.log('');
|
|
315
|
+
console.log(color.bold('Pattern bets (B) — judgment only'));
|
|
316
|
+
for (const bet of plan.patternBets.slice(0, 5)) {
|
|
317
|
+
console.log(` [decide] ${bet.smellId} ${color.dim(bet.pilot)}`);
|
|
318
|
+
console.log(color.dim(` success: ${bet.successSignal}`));
|
|
319
|
+
}
|
|
320
|
+
}
|
|
227
321
|
if (activeViolations.length === 0) return plan;
|
|
228
322
|
console.log('');
|
|
229
323
|
console.log(
|
|
@@ -245,7 +339,7 @@ export function runPlan(root, activeViolations, asJson, governedPercent = null,
|
|
|
245
339
|
console.log('');
|
|
246
340
|
console.log(
|
|
247
341
|
color.dim(
|
|
248
|
-
'Plan only — no files changed. "auto" = an agent can safely apply it; "decide" = your call.'
|
|
342
|
+
'Plan only — no files changed. "auto" = an agent can safely apply it; "decide" = your call. patternBets are never auto.'
|
|
249
343
|
)
|
|
250
344
|
);
|
|
251
345
|
return plan;
|
|
@@ -283,6 +377,12 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
283
377
|
const activeCount = violations.length - suppressed;
|
|
284
378
|
const missingSkills = skillGaps.reduce((sum, gap) => sum + gap.missing, 0);
|
|
285
379
|
const staleSkills = skillGaps.reduce((sum, gap) => sum + gap.stale, 0);
|
|
380
|
+
const designSmells = detectDesignSmells(root, config, files, cov);
|
|
381
|
+
const designFitness = summarizeDesignFitness(designSmells, {
|
|
382
|
+
activeViolations: activeCount,
|
|
383
|
+
governedPercent: cov.governed.percent,
|
|
384
|
+
totalFiles: cov.governed.totalFiles,
|
|
385
|
+
});
|
|
286
386
|
|
|
287
387
|
if (asJson) {
|
|
288
388
|
console.log(
|
|
@@ -304,6 +404,9 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
304
404
|
return p ? p.files / total : null;
|
|
305
405
|
})(),
|
|
306
406
|
}),
|
|
407
|
+
// Path-correct ENFORCE can still be design-weak (P02).
|
|
408
|
+
designFitness,
|
|
409
|
+
designSmells,
|
|
307
410
|
governed: cov.governed,
|
|
308
411
|
emptyLayers: cov.emptyLayers,
|
|
309
412
|
layersWithoutRules: cov.layersWithoutRules,
|
|
@@ -412,7 +515,18 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
412
515
|
enforce:
|
|
413
516
|
'Guard — contract coverage is honest and checked edges are clean. You do not pick this mode; you arrived here. Next: keep the host-appropriate write path and CI check on; only NEW violations should fail.',
|
|
414
517
|
};
|
|
415
|
-
|
|
518
|
+
const modeTitle =
|
|
519
|
+
mode === 'enforce' && designFitness.designWeak
|
|
520
|
+
? 'ENFORCE · design-weak'
|
|
521
|
+
: mode.toUpperCase();
|
|
522
|
+
line(
|
|
523
|
+
modeMark,
|
|
524
|
+
`${modeTitle} — ${
|
|
525
|
+
designFitness.designWeak
|
|
526
|
+
? 'Guard on edges is honest, but design smells remain (Shape residual). You do not pick this mode. Next: /ark-explore dual-plan B or /ark-autopilot for pattern bets — never treat empty plan A as healthy finished.'
|
|
527
|
+
: modeHelp[mode]
|
|
528
|
+
}`
|
|
529
|
+
);
|
|
416
530
|
if (emptyScope) {
|
|
417
531
|
line(
|
|
418
532
|
bad,
|
|
@@ -420,6 +534,25 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
420
534
|
);
|
|
421
535
|
}
|
|
422
536
|
|
|
537
|
+
console.log('');
|
|
538
|
+
console.log(color.bold('Design fitness'));
|
|
539
|
+
if (designSmells.length === 0) {
|
|
540
|
+
line(ok, designFitness.label);
|
|
541
|
+
} else {
|
|
542
|
+
line(designFitness.designWeak ? warn : warn, designFitness.label);
|
|
543
|
+
for (const smell of designSmells.slice(0, 5)) {
|
|
544
|
+
line(' ', color.dim(`[${smell.id}] ${smell.message}`));
|
|
545
|
+
if (smell.evidence?.length) {
|
|
546
|
+
line(' ', color.dim(`evidence: ${smell.evidence.slice(0, 4).join(', ')}`));
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (designFitness.designWeak) {
|
|
550
|
+
actions.push(
|
|
551
|
+
'shape residual: /ark-explore (shape-focus) or /ark-autopilot dual-plan B — pattern bets are never mechanical-safe'
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
423
556
|
console.log('');
|
|
424
557
|
console.log(color.bold('Coverage'));
|
|
425
558
|
const govMark =
|
package/dist/index.cjs
CHANGED
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import { a as ArkConfigRule, b as ArkConfigLayer, A as ArkConfig, c as ArkConfig
|
|
|
2
2
|
export { d as ARK_CONFIG_SCHEMA, e as ARK_CONFIG_SCHEMA_VERSION, l as loadArkConfigContract, p as parseArkConfigJson } from './configContract-BxSIwVRo.cjs';
|
|
3
3
|
|
|
4
4
|
/** ArkGate library version — single source of truth. */
|
|
5
|
-
declare const version = "3.0.
|
|
5
|
+
declare const version = "3.0.1";
|
|
6
6
|
|
|
7
7
|
/** Versioned public result contract shared by every ArkGate enforcement adapter. */
|
|
8
8
|
declare const ARK_ANALYSIS_RESULT_SCHEMA_VERSION: "1.0";
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { a as ArkConfigRule, b as ArkConfigLayer, A as ArkConfig, c as ArkConfig
|
|
|
2
2
|
export { d as ARK_CONFIG_SCHEMA, e as ARK_CONFIG_SCHEMA_VERSION, l as loadArkConfigContract, p as parseArkConfigJson } from './configContract-BxSIwVRo.js';
|
|
3
3
|
|
|
4
4
|
/** ArkGate library version — single source of truth. */
|
|
5
|
-
declare const version = "3.0.
|
|
5
|
+
declare const version = "3.0.1";
|
|
6
6
|
|
|
7
7
|
/** Versioned public result contract shared by every ArkGate enforcement adapter. */
|
|
8
8
|
declare const ARK_ANALYSIS_RESULT_SCHEMA_VERSION: "1.0";
|
package/dist/index.js
CHANGED
package/docs/agent-guide.md
CHANGED
|
@@ -75,6 +75,12 @@ To remove a compact host integration, preview `ark start --remove-host <host>` a
|
|
|
75
75
|
only after review. Ark removes only its exact compact artifacts, leaves customized files untouched
|
|
76
76
|
as unresolved decisions, and restores the integration with `ark start --tools <host> --apply`.
|
|
77
77
|
|
|
78
|
+
**Skill roles (avoid overlap):** `/ark-explore` = map + dual-plan **seed** + Shape residual
|
|
79
|
+
(no apply). `/ark-coverage` = Ark **fitness** only (governed/gates). `/ark-think` = one decision
|
|
80
|
+
(2–3 options). `/ark-adopt` = brownfield Align/Stabilize + seed Shape B. `/ark-autopilot` =
|
|
81
|
+
explore then apply A + propose/apply-with-ok B. `/ark-loop` = plan A only. Empty plan A is not
|
|
82
|
+
“architecture healthy” if design-weak residual remains.
|
|
83
|
+
|
|
78
84
|
**Full-skill agent co-pilot:** after explicitly installing the `/ark-*` pack, use
|
|
79
85
|
`/ark-autopilot` (explore-first, dual plan A remediation + B pattern bets). Recon without
|
|
80
86
|
applying: `/ark-explore`. The default compact router uses MCP/CLI directly. Never treat empty
|
|
@@ -86,10 +86,61 @@ violations — the ratchet only moves toward zero.
|
|
|
86
86
|
`/ark-fix` resolves each cluster at the root cause; fixing a frozen violation shrinks the
|
|
87
87
|
baseline permanently. Re-freeze lower with `--update-baseline` as you go.
|
|
88
88
|
|
|
89
|
+
## 6. Shape residual — extraction cards (judgment assist, P05)
|
|
90
|
+
|
|
91
|
+
When edges are green (`ark-check --plan` has empty `steps[]`) but doctor reports
|
|
92
|
+
**ENFORCE · design-weak** (`designSmells` / `patternBets`), you are in **Shape** work. Plan A
|
|
93
|
+
is done; plan **B** is not auto-applicable.
|
|
94
|
+
|
|
95
|
+
Use one **extraction card** per pilot (I/O relocate, god-module split, domain-out-of-UI).
|
|
96
|
+
Agents and humans fill the same fields — never invent a codemod engine or silent apply:
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
### Extraction card
|
|
100
|
+
Pilot: <one directory or feature path>
|
|
101
|
+
Smell: <doctor designSmells[].id or agent-detected id>
|
|
102
|
+
Move: <what moves, e.g. query bytes verbatim → OrderRepository adapter>
|
|
103
|
+
Do not:
|
|
104
|
+
- rewrite queries / touch schema / migrations
|
|
105
|
+
- weaken ark.config.json to silence the smell
|
|
106
|
+
- auto-apply as mechanical-safe or invent new mechanical-safe kinds
|
|
107
|
+
- big-bang the whole monorepo
|
|
108
|
+
Success: <falsifiable signal, e.g. 0 routes import @prisma/client>
|
|
109
|
+
Kill-switch: <when to stop, e.g. if 2 PRs still confuse ownership → stop layer add>
|
|
110
|
+
Next: /ark-fix (one cluster) | /ark-autopilot (user ok on B) | /ark-explore shape-focus
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
CLI sensors:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
ark-check --doctor --json # designFitness.designWeak + designSmells[].evidence
|
|
117
|
+
ark-check --plan --json # patternBets[] with neverMechanicalSafe: true
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Fixture for CI honesty: `tests/fixtures/design-weak-enforce/` (empty plan A + non-empty B).
|
|
121
|
+
|
|
122
|
+
### Optional: durable Shape plan (multi-PR)
|
|
123
|
+
|
|
124
|
+
CLI `patternBets` and extraction cards are enough for a single session. If residual spans
|
|
125
|
+
**multiple PRs or agents**, optionally persist one human-readable plan under the repo
|
|
126
|
+
(e.g. `docs/plans/shape-<pilot>/README.md` or any team path) with:
|
|
127
|
+
|
|
128
|
+
| Field | Source |
|
|
129
|
+
|-------|--------|
|
|
130
|
+
| Phase | Align / Stabilize / **Shape** |
|
|
131
|
+
| Golden vs legacy patterns | explore concurrent-patterns table |
|
|
132
|
+
| Smell ids / patternBets | `ark-check --doctor --json` / `--plan --json` |
|
|
133
|
+
| Extraction cards | §6 template above |
|
|
134
|
+
| Status of pilot | e.g. dual path (legacy + new) → real (only golden) when smells clear |
|
|
135
|
+
|
|
136
|
+
This is **optional narrative**, not a gate. Ark does not require a docs skill or a fixed
|
|
137
|
+
folder layout. Prefer one authority plan; promote or archive it when the pilot is real.
|
|
138
|
+
|
|
89
139
|
## What Ark does NOT do here
|
|
90
140
|
|
|
91
141
|
Ark reorganizes and governs code — it never touches your data model. Migrating raw SQL to a
|
|
92
142
|
repository moves the same query to another file; the schema, migrations, and the database are
|
|
93
143
|
untouched. And the burn-down itself is the team's work (or a codemod, or an agent loop) — Ark
|
|
94
144
|
diagnoses, orders it, and gives you the pattern; it doesn't auto-run hundreds of edits against
|
|
95
|
-
your restricted data layer.
|
|
145
|
+
your restricted data layer. **Extraction cards are judgment assists only** — no general codemod
|
|
146
|
+
and no silent auto-apply of plan B.
|
package/docs/package-surface.md
CHANGED
|
@@ -15,6 +15,8 @@ This document is the consumer contract for **what is stable** vs **what is exper
|
|
|
15
15
|
| Surface | How you use it | Stability notes |
|
|
16
16
|
|---------|----------------|-----------------|
|
|
17
17
|
| **CLI** | `arkgate` / `arkgate-check` (aliases `ark` / `ark-check`) | Flags and human text may improve; **JSON output shapes** for `--json` (check, doctor, plan, coverage, recommend) are stable within a major. Additive fields OK; removals/renames are major. |
|
|
18
|
+
| **Doctor design fitness (P02+)** | `ark-check --doctor --json` → `doctor.designFitness`, `doctor.designSmells[]` | Additive. Stable smell `id`s: `io-under-application`, `handler-in-persistence`, `god-module`, `domain-logic-in-ui`, `facade-sql-in-routes`, `mixed-pattern-cluster`, `soft-contract`. Each smell has `evidence[]` paths and `fix`. Does **not** fail the gate by itself. |
|
|
19
|
+
| **Plan pattern B (P03+)** | `ark-check --plan --json` → `plan.patternBets[]`, `plan.goal.designWeak` | Additive. Each bet: `id`, `smellId`, `pilot`, `evidence`, `successSignal`, `killSwitch`, **`neverMechanicalSafe: true`**, `class: "judgment"`. **Never** auto-applied by loop/autoPatch; not a `remediationKind` mechanical-safe. `goal.met` remains edge honesty only. |
|
|
18
20
|
| **MCP tools** | `arkgate-mcp` / `ark://…` resources | Tool names and primary argument shapes are stable within a major. |
|
|
19
21
|
| **`ark.config.json`** | Layer globs, rules, include/exclude, forbiddenGlobals, intent prefixes, `peerIsolation`, `dynamicImportAllowlist`, `safety` thresholds | Versioned by `schemaVersion`; unknown fields fail closed and migrations preserve the previous supported major. |
|
|
20
22
|
| **`arkgate/schema/analysis-result`** | Public CLI/MCP/hook diagnostic envelope (`schemaVersion`, `valid`, `diagnostics`) | Versioned JSON Schema; committed v1 compatibility fixture protects rule, severity, location, and evidence fields. |
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/pedroknigge/arkgate",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "3.0.
|
|
9
|
+
"version": "3.0.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "arkgate",
|
|
14
|
-
"version": "3.0.
|
|
14
|
+
"version": "3.0.1",
|
|
15
15
|
"runtimeHint": "npx",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ark-adopt
|
|
3
|
-
description: Brownfield onboarding —
|
|
3
|
+
description: Brownfield onboarding — match contract to real product code, classify ungoverned dirs, mine business rules, freeze only real debt, seed Shape dual-plan B for spaghetti residual. Deep source analysis required.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /ark-adopt — Bring Ark into an existing codebase
|
|
@@ -8,6 +8,18 @@ description: Brownfield onboarding — exploratory match of contract to real pro
|
|
|
8
8
|
Goal: contract reflects **product reality**, most code governed, only genuine debt frozen
|
|
9
9
|
with a burn-down. A green check over a wrong contract is a **false green**.
|
|
10
10
|
|
|
11
|
+
**Adopt is Align + Stabilize, then seed Shape.** Freezing debt without a pattern plan leaves
|
|
12
|
+
spaghetti “ENFORCE · design-weak”. Always end with dual-plan **B** seeds (or handoff explore)
|
|
13
|
+
when design smells remain after the contract is honest.
|
|
14
|
+
|
|
15
|
+
## When / not when
|
|
16
|
+
|
|
17
|
+
| Use `/ark-adopt` when… | Do **not** use it when… |
|
|
18
|
+
|------------------------|-------------------------|
|
|
19
|
+
| Existing messy repo; contract ≠ folders | Empty greenfield shape → `/ark-architect` |
|
|
20
|
+
| False-green / concentrated edge needs contract truth | Map-only without writing config/baseline → `/ark-explore` |
|
|
21
|
+
| Mine loose business rules into Domain / intents | Single violation fix → `/ark-fix` |
|
|
22
|
+
| Freeze **real** debt after contract is honest | Grind plan A only → `/ark-loop`; full apply loop → `/ark-autopilot` |
|
|
11
23
|
|
|
12
24
|
## Dual engine (mandatory)
|
|
13
25
|
|
|
@@ -78,22 +90,33 @@ Ark protects the **boundary around** a framework, not its internals. Nest/DI pub
|
|
|
78
90
|
- Deliver section **“Así te lo re-soluciono en el manifiesto”** with before/after contract snippets.
|
|
79
91
|
5. **Freeze only real debt** — `--update-baseline` (zero debt → **no empty baseline file** left behind).
|
|
80
92
|
6. **Gates + skills** — `--install-agent-gates` (CI monorepo-aware when `frontend/package.json` exists).
|
|
81
|
-
7. **Ratchet +
|
|
93
|
+
7. **Ratchet + Shape seed (mandatory exploratory close)** — after freeze/gates:
|
|
94
|
+
- Name phase: **Align** (contract honesty) → **Stabilize** (baseline real) → **Shape** (golden pattern).
|
|
95
|
+
- If plan A is empty but the tree still shows concurrent patterns, god modules, facade SQL,
|
|
96
|
+
domain logic in UI, or semantic false-green: emit **dual-plan B** (3–5 bets) with pilot,
|
|
97
|
+
success signal, kill-switch, and extraction cards for I/O moves — same bar as `/ark-explore` §G.
|
|
98
|
+
- Do **not** claim “adopt complete / healthy” solely because the check is green.
|
|
99
|
+
- Prefer handoff `/ark-autopilot` for B execution with user ok, or `/ark-explore` shape-focus
|
|
100
|
+
if the user only wanted a plan.
|
|
82
101
|
|
|
83
102
|
## Operating modes
|
|
84
103
|
|
|
85
104
|
Explain modes as **detected stages** (Setup / Align / Guard), not user settings.
|
|
105
|
+
**Guard on the contract ≠ Shape done.** Say `ENFORCE · design-weak` when B residual remains.
|
|
86
106
|
|
|
87
107
|
## Verify
|
|
88
108
|
|
|
89
109
|
`ark-check --root . --config ark.config.json --strict-config` (+ baseline only if non-empty file retained).
|
|
90
|
-
Report: governed% before/after, files written, frozen count, false positives avoided, manifest/intent
|
|
110
|
+
Report: governed% before/after, files written, frozen count, false positives avoided, manifest/intent
|
|
111
|
+
proposals applied or deferred, **phase**, **top Shape / design-weak opportunities still open**
|
|
112
|
+
(with success signals).
|
|
91
113
|
|
|
92
114
|
## Never
|
|
93
115
|
|
|
94
116
|
- Freeze false positives to get green.
|
|
95
117
|
- Force runtime kernel over existing Nest/DI.
|
|
96
118
|
- Claim Enforce while governed% is low, cores empty with I/O in Application, or core bags ungoverned.
|
|
119
|
+
- End adopt with only “baseline written” when design-weak residual is visible in files you opened.
|
|
97
120
|
|
|
98
121
|
## Completion contract (skill incomplete if missing)
|
|
99
122
|
|
|
@@ -5,6 +5,13 @@ description: Choose the application shape, adopt phase-1 layers, scaffold direct
|
|
|
5
5
|
|
|
6
6
|
# /ark-architect — Choose your application shape and adopt Ark
|
|
7
7
|
|
|
8
|
+
## When / not when
|
|
9
|
+
|
|
10
|
+
| Use `/ark-architect` when… | Do **not** use it when… |
|
|
11
|
+
|----------------------------|-------------------------|
|
|
12
|
+
| Greenfield / thin tree; pick shape + phase-1 layers | Existing spaghetti brownfield → `/ark-adopt` (+ `/ark-explore` first if map missing) |
|
|
13
|
+
| Enthusiast before heavy codegen | Enforcement residual on mature tree → `/ark-autopilot` |
|
|
14
|
+
|
|
8
15
|
The user is building something new or early in Ark adoption. They may not know
|
|
9
16
|
layered architecture jargon. Your job: translate **what they want to build**
|
|
10
17
|
(application shape, not framework name) into an Ark preset, a phase-1 layer plan,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ark-autopilot
|
|
3
|
-
description: End-to-end
|
|
3
|
+
description: End-to-end co-pilot — explore first, dual plan A remediation + B pattern/Shape bets, mechanical-safe fixes, judgment design. Empty plan A is not healthy if design-weak. CLI is a sensor; you read and remediate files.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /ark-autopilot — Get to a sound architecture, end to end
|
|
@@ -11,15 +11,23 @@ execute **judgment** fixes you design from reading source (still validate with a
|
|
|
11
11
|
never weaken the gate).
|
|
12
12
|
|
|
13
13
|
**Not a plan grinder.** Empty `--plan` does **not** mean “architecture is healthy” without
|
|
14
|
-
the explore pass and dual-plan section B (pattern bets).
|
|
14
|
+
the explore pass and dual-plan section B (pattern / Shape bets).
|
|
15
15
|
|
|
16
|
+
## When / not when
|
|
17
|
+
|
|
18
|
+
| Use `/ark-autopilot` when… | Do **not** use it when… |
|
|
19
|
+
|----------------------------|-------------------------|
|
|
20
|
+
| “Make architecture sound” end-to-end | Map only, no apply → `/ark-explore` |
|
|
21
|
+
| Brownfield or greenfield with apply | Only fitness numbers → `/ark-coverage` |
|
|
22
|
+
| User wants A + B planned and A executed | Single edge fix → `/ark-fix`; plan A only → `/ark-loop` |
|
|
23
|
+
| Spaghetti under ENFORCE: Shape work with user ok on B | Contract false-green first → `/ark-adopt` / `/ark-contract` STOP paths |
|
|
16
24
|
|
|
17
25
|
## Related onboarding
|
|
18
26
|
|
|
19
27
|
- **Greenfield:** `/ark-architect` or `ark-check --recommend` / `ark start`.
|
|
20
28
|
- **Brownfield:** `/ark-adopt` — match contract to reality; do not force a starter preset.
|
|
21
|
-
- **Deep map only:** `/ark-explore` — full recon
|
|
22
|
-
- **Adoption
|
|
29
|
+
- **Deep map only:** `/ark-explore` — full recon / dual-plan seed without applying.
|
|
30
|
+
- **Adoption fitness only:** `/ark-coverage` — governed% + capability gaps (not pattern dual-plan).
|
|
23
31
|
- **Default path:** `ark start` → `/ark-autopilot` → `ark-check --doctor`.
|
|
24
32
|
|
|
25
33
|
## Dual engine (mandatory)
|
|
@@ -64,30 +72,38 @@ Useful first wave: **core product tree** | **field path** (examples/starters) |
|
|
|
64
72
|
|
|
65
73
|
Do this **before** grinding plan A — plan lists *violations*, not *product reality*.
|
|
66
74
|
Use the **`/ark-explore` decision-grade bar** (compressed into the autopilot report, not optional fluff).
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
Include explore **§G** when spaghetti / design-weak signals fire.
|
|
76
|
+
|
|
77
|
+
1. **Headline** — product one-liner + honesty (mode, governed%, false-green / false-promise /
|
|
78
|
+
**ENFORCE·design-weak** risk).
|
|
79
|
+
2. **Map** — entry points, lived layout vs globs (one screen). **Concurrent patterns** table when ≥2 styles.
|
|
80
|
+
3. **Phase ladder** — name **Align | Stabilize | Shape** (explore §G).
|
|
81
|
+
4. **Field path** — if `examples/` / gallery / starter docs exist: open ≥2, **run** their check when cheap; flag soft-green or broken demos. Else `Field path: n/a` + internal norm.
|
|
82
|
+
5. **Agent/gate reality** — installed hooks vs install templates (e.g. `--hook` vs `--hook-repair`); MCP; CI gate present.
|
|
83
|
+
6. **Coupling** — fan-in / exports / importers for hotspots (LOC alone is a hint).
|
|
84
|
+
7. **False-green soft block** — doctor/coverage: empty Domain/Persistence while Application owns I/O (`airtable`, `supabase`, `prisma`, `drizzle`, `repositories`, …). Doctor gap id: `contract-false-green-io-under-application`. If so:
|
|
74
85
|
**STOP — do not continue this skill as complete.** **STOP — false-green: invoke /ark-adopt or /ark-contract before claiming ENFORCE.** Do not claim goal.met / ENFORCE from type-only cleanup while doctor reports `contract-false-green-io-under-application`.
|
|
75
|
-
|
|
86
|
+
8. **Seed dual plan B** — 2–5 pattern / Shape bets ranked (impact × effort × enforceability). Each B row needs pilot + success signal; I/O bets need an **extraction card** (explore §G).
|
|
76
87
|
|
|
77
88
|
Min bar: **≥12 source files** across **≥4 meaningful directories** (not only files in `steps[]`).
|
|
78
|
-
Standalone long report: `/ark-explore`. Adoption
|
|
89
|
+
Standalone long report: `/ark-explore`. Adoption fitness only: `/ark-coverage`.
|
|
79
90
|
|
|
80
91
|
## Dual plan (always emit)
|
|
81
92
|
|
|
82
93
|
| Section | Source | Question | Auto-apply? |
|
|
83
94
|
|---------|--------|----------|-------------|
|
|
84
|
-
| **A. Remediation** | `--plan --json` + opened step files | What must change so the gate is honest? | Only `mechanical-safe` by default |
|
|
85
|
-
| **B. Pattern /
|
|
95
|
+
| **A. Remediation** | `--plan --json` + opened step files | What must change so the **gate** is honest? | Only `mechanical-safe` by default |
|
|
96
|
+
| **B. Pattern / Shape** | Explore §B/§G (not coverage alone) | What **design** must improve even if A is empty? | **Never** as mechanical-safe |
|
|
86
97
|
|
|
87
98
|
**Section A** — group by edge; treat `peerIsolation` / cross-slice as **judgment**.
|
|
88
|
-
**Section B** examples: peerIsolation, move rules out of UI,
|
|
99
|
+
**Section B** examples: choose golden pattern + pilot migrate-on-touch, peerIsolation, move rules out of UI, write-path repair, split god modules, Domain placement / intents, facade SQL → port/adapter (extraction card). Cap **3–5** B rows. Each row: evidence path + **así te lo re-soluciono** + next skill/command + **success signal** + **pilot** (+ kill-switch if new layer).
|
|
89
100
|
|
|
90
|
-
B does **not** count as “architecture healthy finished.” Report B as `proposed | deferred | applied-with-user-ok`.
|
|
101
|
+
B does **not** count as “architecture healthy finished.” Report B as `proposed | deferred | applied-with-user-ok`.
|
|
102
|
+
When A is empty and B is non-empty: status is **`goal.met on edges · Shape residual open`** — never “done” without listing B.
|
|
103
|
+
Prefer CLI `patternBets[]` / `designSmells[]` when present; apply B only with explicit user ok using
|
|
104
|
+
**extraction cards** (`docs/brownfield-adoption.md` §6) — never mechanical-safe, never silent.
|
|
105
|
+
If B will take multiple PRs, offer (do not require) persisting a short Shape plan under the
|
|
106
|
+
repo so the next agent session continues the same pilot — still never auto-apply B.
|
|
91
107
|
|
|
92
108
|
## Origin snapshot (day-zero picture)
|
|
93
109
|
|
|
@@ -136,12 +152,13 @@ B does **not** count as “architecture healthy finished.” Report B as `propos
|
|
|
136
152
|
|
|
137
153
|
## Done criteria
|
|
138
154
|
|
|
139
|
-
- Explore pass completed (decision-grade map + paths + field path or n/a + B seeds).
|
|
140
|
-
- Dual plan emitted (A and/or B; if both empty, one-line justification).
|
|
155
|
+
- Explore pass completed (decision-grade map + paths + field path or n/a + phase + B seeds).
|
|
156
|
+
- Dual plan emitted (A and/or B; if both empty, one-line justification with evidence no design-weak smells).
|
|
141
157
|
- Origin present under `.ark/reports/origin.*` (frozen this run or earlier).
|
|
142
158
|
- Every applied A step validated by real `ark-check`.
|
|
143
159
|
- Final plan `goal.met` true **or** remaining A steps listed with file-level proposals.
|
|
144
|
-
- Open **B opportunities** listed; report HTML paths cited.
|
|
160
|
+
- Open **B / Shape opportunities** listed with success signals; report HTML paths cited when used.
|
|
161
|
+
- If A empty and design-weak present: B listed — **Incomplete?** must not claim full healthy stop.
|
|
145
162
|
|
|
146
163
|
## Completion contract (skill incomplete if missing)
|
|
147
164
|
|
|
@@ -5,6 +5,13 @@ description: Safely edit ark.config.json (layers, rules, forbiddenGlobals, inten
|
|
|
5
5
|
|
|
6
6
|
# /ark-contract — Change the architecture contract (safely)
|
|
7
7
|
|
|
8
|
+
## When / not when
|
|
9
|
+
|
|
10
|
+
| Use `/ark-contract` when… | Do **not** use it when… |
|
|
11
|
+
|---------------------------|-------------------------|
|
|
12
|
+
| Edit layers/rules/includes/intents with source evidence | Move product code without config change → `/ark-fix` / `/ark-loop` |
|
|
13
|
+
| Concentrated-edge / false-green STOP from other skills | Full map without config edit → `/ark-explore` |
|
|
14
|
+
|
|
8
15
|
The **one sanctioned way** to change layers/rules/`intentPrefixes`/includes.
|
|
9
16
|
Also used to **land mined business rules** into the executable manifest (`ark.config.json` + intent naming that `ark://manifest` exposes).
|
|
10
17
|
|