arkgate 3.0.0 → 3.0.2

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.
@@ -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
- export function buildRemediationPlan(root, activeViolations, governedPercent = null, totalFiles = null) {
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
- activeViolations.length > 0
185
- ? `Resolve ${activeViolations.length} architecture violation(s) without weakening the contract.`
186
- : emptyScope
187
- ? '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.'
188
- : governedLow
189
- ? `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.`
190
- : 'No active violations — the architecture already meets its contract.',
191
- // The loop's termination signal (Phase H): nothing left to remediate AND the contract
192
- // actually governs real code. Empty scope or low coverage is not "met".
193
- met: activeViolations.length === 0 && !notHonestlyEnforced,
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
- export function runPlan(root, activeViolations, asJson, governedPercent = null, totalFiles = null) {
210
- const plan = buildRemediationPlan(root, activeViolations, governedPercent, totalFiles);
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
- line(modeMark, `${mode.toUpperCase()} — ${modeHelp[mode]}`);
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
@@ -50,7 +50,7 @@ __export(gate_exports, {
50
50
  module.exports = __toCommonJS(gate_exports);
51
51
 
52
52
  // src/version.ts
53
- var version = "3.0.0";
53
+ var version = "3.0.2";
54
54
 
55
55
  // src/domain/adapterContract.ts
56
56
  var ARK_ANALYSIS_RESULT_SCHEMA_VERSION = "1.0";
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.0";
5
+ declare const version = "3.0.2";
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.0";
5
+ declare const version = "3.0.2";
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
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var version = "3.0.0";
2
+ var version = "3.0.2";
3
3
 
4
4
  // src/domain/adapterContract.ts
5
5
  var ARK_ANALYSIS_RESULT_SCHEMA_VERSION = "1.0";
@@ -75,10 +75,31 @@ 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. Full routing table: full-install
83
+ `AGENTS.md` / [README skill table](../README.md#other-skills-only-when-you-need-them).
84
+
85
+ **Design fitness (3.0.1+):** after edges are clean, doctor can still report **ENFORCE · design-weak**.
86
+
87
+ ```bash
88
+ npx ark-check --doctor --json # doctor.designFitness + doctor.designSmells[]
89
+ npx ark-check --plan --json # plan.goal.designWeak + plan.patternBets[] (never mechanical-safe)
90
+ ```
91
+
92
+ Smell ids (stable): `io-under-application`, `handler-in-persistence`, `god-module`,
93
+ `domain-logic-in-ui`, `facade-sql-in-routes`, `mixed-pattern-cluster`, `soft-contract`.
94
+ Each has `evidence[]` paths. Plan **B** bets include `pilot`, `successSignal`, `killSwitch`,
95
+ and **`neverMechanicalSafe: true`** — loop/autoPatch must ignore them. For judgment I/O moves
96
+ use **extraction cards** ([brownfield-adoption.md](brownfield-adoption.md) §6). Multi-PR residual
97
+ may optionally be persisted as a short Shape plan under the repo; not a gate requirement.
98
+
78
99
  **Full-skill agent co-pilot:** after explicitly installing the `/ark-*` pack, use
79
100
  `/ark-autopilot` (explore-first, dual plan A remediation + B pattern bets). Recon without
80
101
  applying: `/ark-explore`. The default compact router uses MCP/CLI directly. Never treat empty
81
- `--plan` as “architecture healthy” without the explore pass.
102
+ `--plan` steps as “architecture healthy” when `designWeak` / non-empty `patternBets` remain.
82
103
 
83
104
  `ark init --archetype <id>` maps playbook ids to named presets (`hexagonal`, `layered`,
84
105
  `feature-sliced`, `monorepo`). With `--yes` and no archetype, Ark auto-selects from
package/docs/ai-gates.md CHANGED
@@ -50,6 +50,13 @@ you pass `--force`, so review and commit only the templates that match your proj
50
50
  `autoPatch` flags), the supported profile for the active host, and the evidence actually found.
51
51
  Supported capability and installed guarantee are deliberately separate.
52
52
 
53
+ **Design fitness (3.0.1+):** the same doctor JSON may include `doctor.designFitness` and
54
+ `doctor.designSmells[]` (path evidence). Edge-clean `operatingMode: enforce` can still set
55
+ `designFitness.designWeak: true` (**ENFORCE · design-weak**). That is Shape residual, not a
56
+ write-path failure. Companion plan JSON: `plan.patternBets[]` with `neverMechanicalSafe: true`
57
+ — never treat as write-boundary `autoPatch` / mechanical-safe. See
58
+ [package-surface.md](package-surface.md) and [brownfield-adoption.md](brownfield-adoption.md) §6.
59
+
53
60
  If your project uses Codex or Grok, treat MCP registration as part of the default
54
61
  setup, not an optional extra. Ark works best when the agent can read `ark://manifest`
55
62
  before it writes code; that is the fast path to avoiding architecture drift during
@@ -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.
@@ -35,17 +35,22 @@ the layer globs so day-one **governed%** is real (not a false-green empty contra
35
35
  ### 2. See the plan yourself (optional)
36
36
 
37
37
  ```bash
38
- npx ark-check --plan # human view (includes Governed: N%)
39
- npx ark-check --plan --json # { ok, plan: { goal, counts, steps } }
38
+ npx ark-check --plan # human view (includes Governed: N%; pattern bets when design-weak)
39
+ npx ark-check --plan --json # { ok, plan: { goal, counts, steps, patternBets?, designSmells? } }
40
+ npx ark-check --doctor --json # designFitness / designSmells when residual is design-weak
40
41
  ```
41
42
 
42
- Each step is tagged `mechanical-safe` / `judgment` / `deferred` with a `confidence`,
43
+ Each **A** step is tagged `mechanical-safe` / `judgment` / `deferred` with a `confidence`,
43
44
  `rationale`, and often `remediationKind`. Auto-safe kinds: type-only type move, pure-type **file**
44
45
  relocate, `import type` of pure-type modules, and named type-export imports from mixed modules
45
46
  (`import-type-of-type-exports`). `goal.met` is true only when
46
47
  there are no active violations **and** governed coverage is meaningful — so a clean plan that
47
48
  checks almost nothing is not "done."
48
49
 
50
+ When edges are clean but design residual remains, JSON also sets `goal.designWeak` and
51
+ `patternBets[]` (each with `neverMechanicalSafe: true`). Those are **B** (Shape) bets — not
52
+ auto-applied. Extraction cards: [brownfield-adoption.md](../brownfield-adoption.md) §6.
53
+
49
54
  ### 3. Carry the plan out — the autopilot
50
55
 
51
56
  In your agent, run:
@@ -54,10 +59,12 @@ In your agent, run:
54
59
  /ark-autopilot
55
60
  ```
56
61
 
57
- It runs the whole flow (newbie tier): confirms the plan, hands off to `/ark-loop` to apply the
58
- `mechanical-safe` steps one at a time — **validating each with `ark-check` and rolling back any
59
- regression** — proposes each `judgment` step for a yes/no, loops until `goal.met`, and reports
60
- what was auto-applied vs proposed vs deferred. Nothing lands until you review the diff.
62
+ It runs the whole flow (newbie tier): **explore first** (map + dual plan), hands off to
63
+ `/ark-loop` for plan **A** `mechanical-safe` steps one at a time — **validating each with
64
+ `ark-check` and rolling back any regression** — proposes each A `judgment` and each B
65
+ pattern/Shape bet for a yes/no, and reports what was auto-applied vs proposed vs deferred.
66
+ Nothing lands until you review the diff. Empty A with open B is **not** “architecture healthy
67
+ finished.”
61
68
 
62
69
  Expert entry: skip the autopilot and use the pieces — `ark init` / `/ark-contract` to shape the
63
70
  contract, `ark-check --plan` for the work, `/ark-fix` for targeted fixes, `ark-check
@@ -15,11 +15,13 @@ 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. |
21
23
  | **Config JSON Schema** | `arkgate/schema` or `arkgate/schema/ark.config.schema.json` | Stable package resource subpaths for editor completion and contract tooling. |
22
- | **Agent skills** | `/ark-*` templates installed by `--install-agent-gates` | Skill *names* and “default flow” are stable; internal skill prose may evolve (e.g. explore dual-plan seed, day-zero origin order). |
24
+ | **Agent skills** | `/ark-*` templates installed by `--install-agent-gates` | Skill *names* and “default flow” are stable; internal skill prose may evolve (e.g. When/not when, explore Shape dual-plan seed, extraction cards, day-zero origin order). |
23
25
  | **ESLint subpath** | `arkgate/eslint` | Config-driven layer/import rules; loads consumer `ark.config.json`. |
24
26
  | **GitHub Action** | `pedroknigge/arkgate` (see `action.yml`) | The `uses:` tag/SHA selects the checker source; `version` remains an optional exact npm compatibility override. |
25
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkgate",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "ArkGate — architecture co-pilot for AI TypeScript (write gate, CI gate, plan/loop)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
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.0",
9
+ "version": "3.0.2",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "arkgate",
14
- "version": "3.0.0",
14
+ "version": "3.0.2",
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 — exploratory match of contract to real product code, classify ungoverned dirs, mine business rules into the manifest, freeze only real debt. Deep source analysis required.
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 + opportunity plan** ranked residual edges + **explore-style bets** (what to improve next week).
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 proposals applied or deferred, **top opportunities still open**.
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,