arkgate 4.6.0 → 4.6.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 +25 -1
- package/README.md +9 -5
- package/bin/ark-check-runtime.mjs +98 -7
- package/bin/ark-mcp-runtime.mjs +17 -1
- package/bin/ark.mjs +5 -3
- package/bin/lib/agent-projection.mjs +1 -1
- package/bin/lib/analysis-engine.mjs +3 -3
- package/bin/lib/ci-and-commands.mjs +11 -11
- package/bin/lib/config-contract.mjs +2 -0
- package/bin/lib/contract-smells.mjs +5 -5
- package/bin/lib/design-smells.mjs +1 -1
- package/bin/lib/doctor-advisories.mjs +9 -0
- package/bin/lib/doctor-plan.mjs +4 -4
- package/bin/lib/field-install.mjs +1 -1
- package/bin/lib/html-report-advisories.mjs +20 -0
- package/bin/lib/improvement-compass-map.mjs +20 -20
- package/bin/lib/pilot-loop.mjs +1 -1
- package/bin/lib/post-green-path.mjs +2 -2
- package/bin/lib/prepare-change.mjs +9 -0
- package/bin/lib/product-copy.mjs +1 -1
- package/bin/lib/status-command.mjs +14 -0
- package/bin/lib/status-manifest.mjs +17 -0
- package/bin/lib/team-parliament-io.mjs +338 -0
- package/bin/lib/team-parliament.mjs +383 -0
- package/bin/lib/upgrade-whats-new.mjs +16 -0
- package/bin/lib/violations.mjs +8 -4
- package/dist/{configTypes-CC0FEXoF.d.ts → configTypes-B8uIcLaG.d.ts} +5 -0
- package/dist/eslint/index.cjs +2 -2
- package/dist/eslint/index.d.ts +1 -1
- package/dist/eslint/index.js +2 -2
- package/dist/index.cjs +19 -19
- package/dist/index.d.ts +61 -2
- package/dist/index.js +22 -22
- package/docs/README.md +5 -5
- package/docs/agent-guide.md +21 -17
- package/docs/configuration.md +36 -2
- package/docs/develop.md +13 -1
- package/docs/enthusiast/README.md +1 -1
- package/docs/enthusiast/how-to-agent-gates.md +3 -3
- package/docs/enthusiast/how-to-pick-shape.md +2 -2
- package/docs/enthusiast/tutorial-first-project.md +4 -3
- package/docs/package-surface.md +5 -3
- package/docs/product-voice.md +48 -10
- package/docs/use.md +6 -1
- package/package.json +2 -2
- package/schemas/ark.config.schema.json +9 -0
- package/schemas/ark.status-manifest.schema.json +51 -0
- package/server.json +3 -3
- package/templates/agent-skills/README.md +1 -1
- package/templates/agent-skills/ark-adopt/SKILL.md +46 -19
- package/templates/agent-skills/ark-architect/SKILL.md +24 -145
- package/templates/agent-skills/ark-autopilot/SKILL.md +40 -30
- package/templates/agent-skills/ark-contract/SKILL.md +21 -105
- package/templates/agent-skills/ark-coverage/SKILL.md +3 -0
- package/templates/agent-skills/ark-explain/SKILL.md +7 -4
- package/templates/agent-skills/ark-explore/SKILL.md +25 -17
- package/templates/agent-skills/ark-fix/SKILL.md +34 -157
- package/templates/agent-skills/ark-loop/SKILL.md +31 -153
- package/templates/agent-skills/ark-place/SKILL.md +25 -13
- package/templates/agent-skills/ark-runtime/SKILL.md +3 -3
- package/templates/agent-skills/ark-think/SKILL.md +5 -2
- package/templates/agent-skills/ark-upgrade/SKILL.md +11 -7
- package/templates/skills/ark-adopt.md +46 -19
- package/templates/skills/ark-architect.md +24 -145
- package/templates/skills/ark-autopilot.md +40 -30
- package/templates/skills/ark-contract.md +21 -105
- package/templates/skills/ark-coverage.md +3 -0
- package/templates/skills/ark-explain.md +7 -4
- package/templates/skills/ark-explore.md +25 -17
- package/templates/skills/ark-fix.md +34 -157
- package/templates/skills/ark-loop.md +31 -153
- package/templates/skills/ark-place.md +25 -13
- package/templates/skills/ark-runtime.md +3 -3
- package/templates/skills/ark-think.md +5 -2
- package/templates/skills/ark-upgrade.md +11 -7
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
import { printParseHealthSection, summarizeParseHealth } from './parse-health.mjs';
|
|
20
20
|
import { detectGraphBlindSpots, printGraphBlindSection } from './graph-blind.mjs';
|
|
21
21
|
import { summarizeRulesUnderContract } from './rules-under-contract.mjs';
|
|
22
|
+
import { collectStewardNudge } from './team-parliament-io.mjs';
|
|
22
23
|
|
|
23
24
|
export function computeDoctorAdvisories(root, config, cov, rules, files, ts, parseHealth, facts) {
|
|
24
25
|
const physicalCohesion = computePhysicalCohesion(root, files);
|
|
@@ -49,6 +50,7 @@ export function computeDoctorAdvisories(root, config, cov, rules, files, ts, par
|
|
|
49
50
|
graphBlindSpots: detectGraphBlindSpots(ts, root, files),
|
|
50
51
|
// AR12 — Rules under contract (honest counts; real test I/O, never empty-fileContents stub).
|
|
51
52
|
// P1M: pass classification so extraMergeTeeth cannot arm at 0% governed.
|
|
53
|
+
stewardNudge: collectStewardNudge(root, config),
|
|
52
54
|
rulesUnderContract: summarizeRulesUnderContract(root, config, factPaths, {
|
|
53
55
|
governedPercent: cov?.governed?.percent ?? null,
|
|
54
56
|
populatedLayerCount: Array.isArray(cov?.layers)
|
|
@@ -70,4 +72,11 @@ export function printDoctorAdvisories(advisories, io) {
|
|
|
70
72
|
printReshapeDecisionsSection(advisories.physicalCohesion?.reshapeDecisions, io);
|
|
71
73
|
printParseHealthSection(advisories.parseHealth, io);
|
|
72
74
|
printGraphBlindSection(advisories.graphBlindSpots, io);
|
|
75
|
+
const nudge = advisories.stewardNudge;
|
|
76
|
+
if ((nudge?.needsStewards || nudge?.drift) && nudge.ask) {
|
|
77
|
+
console.log('');
|
|
78
|
+
console.log(io.color.bold('Stewards (advisory)'));
|
|
79
|
+
io.line(io.warn, nudge.ask);
|
|
80
|
+
if (nudge.nextAction) io.line(' ', io.color.dim(`Next: ${nudge.nextAction}`));
|
|
81
|
+
}
|
|
73
82
|
}
|
package/bin/lib/doctor-plan.mjs
CHANGED
|
@@ -208,7 +208,7 @@ export function runCoverage(root, config, files, rules, asJson) {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
console.log('');
|
|
211
|
-
console.log('Apply these via /ark-
|
|
211
|
+
console.log('Apply these via /ark-adopt (adds the layer patterns to ark.config.json).');
|
|
212
212
|
}
|
|
213
213
|
if (layersWithoutRules.length > 0) {
|
|
214
214
|
console.log('');
|
|
@@ -846,7 +846,7 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
846
846
|
suggest:
|
|
847
847
|
'thin or new tree; architecture config is not yet in charge. You do not pick this light. Next: ark start (preview), then ark start --apply; re-check with --doctor.',
|
|
848
848
|
adapt:
|
|
849
|
-
'config and tree still disagree, or debt is open. The write path does not fully protect you yet. You do not pick this light. Next: do doctor top action #1 (often /ark-adopt
|
|
849
|
+
'config and tree still disagree, or debt is open. The write path does not fully protect you yet. You do not pick this light. Next: do doctor top action #1 (often /ark-adopt or /ark-autopilot).',
|
|
850
850
|
enforce:
|
|
851
851
|
'honest coverage and clean checked imports. You arrived here; you never turn Enforce on. Next: keep the host write path and CI check; only NEW violations should fail.',
|
|
852
852
|
};
|
|
@@ -973,7 +973,7 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
973
973
|
}
|
|
974
974
|
if (cov.suggestions.length > 0) {
|
|
975
975
|
line(warn, `${cov.suggestions.length} ungoverned director(y/ies) — proposals: ${arkCommand(root, 'ark-check', '--coverage')}`);
|
|
976
|
-
actions.push('classify the ungoverned directories (/ark-
|
|
976
|
+
actions.push('classify the ungoverned directories (/ark-adopt)');
|
|
977
977
|
}
|
|
978
978
|
if (cov.emptyLayers.length > 0) line(warn, `Empty layers (pattern matches nothing): ${cov.emptyLayers.join(', ')}`);
|
|
979
979
|
if (cov.layersWithoutRules.length > 0) line(warn, `Layers with no rule edge: ${cov.layersWithoutRules.join(', ')}`);
|
|
@@ -1060,7 +1060,7 @@ export function runDoctor(root, config, files, rules, violations, asJson, option
|
|
|
1060
1060
|
}
|
|
1061
1061
|
if (activeCount > 0) {
|
|
1062
1062
|
actions.push(
|
|
1063
|
-
`resolve the non-baselined violations — see the classified plan (${arkCommand(root, 'ark-check', '--plan')}), then /ark-
|
|
1063
|
+
`resolve the non-baselined violations — see the classified plan (${arkCommand(root, 'ark-check', '--plan')}), then /ark-autopilot`
|
|
1064
1064
|
);
|
|
1065
1065
|
}
|
|
1066
1066
|
}
|
|
@@ -506,7 +506,7 @@ export function detectContractFalseGreenRisk(root, config, coverage) {
|
|
|
506
506
|
`Contract may be a false green: empty core layer(s) [${emptyCores.join(', ')}] while ` +
|
|
507
507
|
`Application-class globs still cover I/O paths (${ioPaths.slice(0, 5).join(', ')}` +
|
|
508
508
|
`${ioPaths.length > 5 ? ', …' : ''}). A clean check can miss real coupling.`,
|
|
509
|
-
fix: 'Run /ark-adopt
|
|
509
|
+
fix: 'Run /ark-adopt — reclassify persistence/auth dirs out of Application before claiming ENFORCE.',
|
|
510
510
|
};
|
|
511
511
|
}
|
|
512
512
|
|
|
@@ -311,12 +311,32 @@ function deepModuleCoachHtml(coach) {
|
|
|
311
311
|
</section>`;
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
+
function stewardNudgeHtml(nudge) {
|
|
315
|
+
if (!nudge || nudge.notAScore !== true) return '';
|
|
316
|
+
const ask =
|
|
317
|
+
(nudge.needsStewards || nudge.drift) && typeof nudge.ask === 'string' && nudge.ask
|
|
318
|
+
? `<p>${esc(nudge.ask)}</p>`
|
|
319
|
+
: '<p class="muted">No steward list gap (advisory).</p>';
|
|
320
|
+
const next =
|
|
321
|
+
typeof nudge.nextAction === 'string' && nudge.nextAction
|
|
322
|
+
? `<p class="muted">Next: ${esc(nudge.nextAction)}</p>`
|
|
323
|
+
: '';
|
|
324
|
+
return `
|
|
325
|
+
<section class="section card" data-advisory="stewardNudge">
|
|
326
|
+
<h2>Stewards <span class="muted">(advisory — never changes the verdict)</span></h2>
|
|
327
|
+
${ask}
|
|
328
|
+
${next}
|
|
329
|
+
<p class="muted">GitHub handle or email. Never invent names. Always <code>notAScore</code>.</p>
|
|
330
|
+
</section>`;
|
|
331
|
+
}
|
|
332
|
+
|
|
314
333
|
export function renderAdvisorySections(advisories, escape) {
|
|
315
334
|
if (!advisories || typeof advisories !== 'object') return '';
|
|
316
335
|
if (typeof escape === 'function') esc = escape;
|
|
317
336
|
return [
|
|
318
337
|
improvementCompassHtml(advisories.improvementCompass),
|
|
319
338
|
deepModuleCoachHtml(advisories.deepModuleCoach),
|
|
339
|
+
stewardNudgeHtml(advisories.stewardNudge),
|
|
320
340
|
contractHealthHtml(advisories.contractHealth),
|
|
321
341
|
ambientStateHtml(advisories.ambientState),
|
|
322
342
|
physicalCohesionHtml(advisories.physicalCohesion),
|
|
@@ -118,11 +118,11 @@ function mapDesignSmells(byId, smells) {
|
|
|
118
118
|
const shapeAction = {
|
|
119
119
|
kind: 'skill',
|
|
120
120
|
ref: '/ark-explore',
|
|
121
|
-
summary: 'Map Shape residual (shape-focus), then one extraction pilot with
|
|
121
|
+
summary: 'Map Shape residual (shape-focus), then apply one extraction pilot with /ark-autopilot.',
|
|
122
122
|
};
|
|
123
123
|
const dipAction = {
|
|
124
124
|
kind: 'skill',
|
|
125
|
-
ref: '/ark-
|
|
125
|
+
ref: '/ark-autopilot',
|
|
126
126
|
summary: 'Inject a port/adapter for I/O; keep domain pure.',
|
|
127
127
|
};
|
|
128
128
|
switch (id) {
|
|
@@ -147,7 +147,7 @@ function mapDesignSmells(byId, smells) {
|
|
|
147
147
|
attach('srp', 'God modules own too many responsibilities — split by concern (one pilot).', {
|
|
148
148
|
kind: 'skill',
|
|
149
149
|
ref: '/ark-autopilot',
|
|
150
|
-
summary: 'One Shape pilot
|
|
150
|
+
summary: 'One Shape pilot this turn — never multi-pilot batch.',
|
|
151
151
|
});
|
|
152
152
|
break;
|
|
153
153
|
case 'mixed-pattern-cluster':
|
|
@@ -161,12 +161,12 @@ function mapDesignSmells(byId, smells) {
|
|
|
161
161
|
case 'soft-contract':
|
|
162
162
|
attach('maintainability', 'Soft contract walls (layers without deny rules) hide maintainability debt.', {
|
|
163
163
|
kind: 'skill',
|
|
164
|
-
ref: '/ark-
|
|
164
|
+
ref: '/ark-adopt',
|
|
165
165
|
summary: 'Add real layer rules so the AI has hard walls.',
|
|
166
166
|
});
|
|
167
167
|
attach('coupling', 'Layers with files but almost no deny rules allow free peer coupling.', {
|
|
168
168
|
kind: 'skill',
|
|
169
|
-
ref: '/ark-
|
|
169
|
+
ref: '/ark-adopt',
|
|
170
170
|
summary: 'Tighten inter-layer allows/denies without weakening enforcement.',
|
|
171
171
|
});
|
|
172
172
|
break;
|
|
@@ -213,7 +213,7 @@ function mapViolations(byId, violations) {
|
|
|
213
213
|
}
|
|
214
214
|
const edgeAction = {
|
|
215
215
|
kind: 'skill',
|
|
216
|
-
ref: '/ark-
|
|
216
|
+
ref: '/ark-autopilot',
|
|
217
217
|
summary: 'Clear the active edge residual, then re-doctor.',
|
|
218
218
|
};
|
|
219
219
|
if (upper === 'LAYER_IMPORT_VIOLATION' ||
|
|
@@ -229,7 +229,7 @@ function mapViolations(byId, violations) {
|
|
|
229
229
|
if (upper.includes('PEER_ISOLATION') || upper === 'PEER_ISOLATION_VIOLATION') {
|
|
230
230
|
attach('coupling', 'Peer isolation residual — slices import each other freely.', {
|
|
231
231
|
kind: 'skill',
|
|
232
|
-
ref: '/ark-
|
|
232
|
+
ref: '/ark-autopilot',
|
|
233
233
|
summary: 'Peer isolation fixes are judgment-class — one cluster at a time.',
|
|
234
234
|
});
|
|
235
235
|
continue;
|
|
@@ -237,12 +237,12 @@ function mapViolations(byId, violations) {
|
|
|
237
237
|
if (upper === 'FORBIDDEN_GLOBAL' || upper.startsWith('FORBIDDEN_')) {
|
|
238
238
|
attach('dip', 'Forbidden globals / effect surfaces break dependency inversion.', {
|
|
239
239
|
kind: 'skill',
|
|
240
|
-
ref: '/ark-
|
|
240
|
+
ref: '/ark-autopilot',
|
|
241
241
|
summary: 'Inject a port instead of the forbidden global.',
|
|
242
242
|
});
|
|
243
243
|
attach('testability', 'Forbidden ambient effects reduce pure-domain testability.', {
|
|
244
244
|
kind: 'skill',
|
|
245
|
-
ref: '/ark-
|
|
245
|
+
ref: '/ark-autopilot',
|
|
246
246
|
summary: 'Replace ambient effects with injectable ports.',
|
|
247
247
|
});
|
|
248
248
|
continue;
|
|
@@ -250,12 +250,12 @@ function mapViolations(byId, violations) {
|
|
|
250
250
|
if (upper === 'CAPABILITY_VIOLATION') {
|
|
251
251
|
attach('dip', 'Denied capability use — invert through an allowed adapter/port.', {
|
|
252
252
|
kind: 'skill',
|
|
253
|
-
ref: '/ark-
|
|
253
|
+
ref: '/ark-autopilot',
|
|
254
254
|
summary: 'Capability walls require port injection (judgment, not mechanical-safe).',
|
|
255
255
|
});
|
|
256
256
|
attach('testability', 'Capability violations couple domain code to I/O — harder to unit-test.', {
|
|
257
257
|
kind: 'skill',
|
|
258
|
-
ref: '/ark-
|
|
258
|
+
ref: '/ark-autopilot',
|
|
259
259
|
summary: 'Keep pure layers free of denied capabilities.',
|
|
260
260
|
});
|
|
261
261
|
continue;
|
|
@@ -263,7 +263,7 @@ function mapViolations(byId, violations) {
|
|
|
263
263
|
if (upper.startsWith('ARKRULE_') || upper === 'INVARIANT_UNCOVERED') {
|
|
264
264
|
attach('encapsulation', 'ArkRules structure / invariant residual inside a layer.', {
|
|
265
265
|
kind: 'skill',
|
|
266
|
-
ref: '/ark-
|
|
266
|
+
ref: '/ark-autopilot',
|
|
267
267
|
summary: 'Label [ArkRules]; structure fixes are judgment — never invent mechanical-safe.',
|
|
268
268
|
});
|
|
269
269
|
attach('domain', 'Intra-layer domain structure or invariant coverage residual.', {
|
|
@@ -282,7 +282,7 @@ function mapCountsAndFlags(byId, facts) {
|
|
|
282
282
|
pushEvidence(lens, 'cycles', `count:${cycleCount}`);
|
|
283
283
|
markResidual(lens, 'Import cycles couple modules tightly.', {
|
|
284
284
|
kind: 'skill',
|
|
285
|
-
ref: '/ark-
|
|
285
|
+
ref: '/ark-autopilot',
|
|
286
286
|
summary: 'Break cycles with a judgment extraction — one pilot.',
|
|
287
287
|
});
|
|
288
288
|
}
|
|
@@ -296,7 +296,7 @@ function mapCountsAndFlags(byId, facts) {
|
|
|
296
296
|
pushEvidence(lens, 'peerIsolation', `count:${peer}`);
|
|
297
297
|
markResidual(lens, 'Peer isolation residual remains.', {
|
|
298
298
|
kind: 'skill',
|
|
299
|
-
ref: '/ark-
|
|
299
|
+
ref: '/ark-autopilot',
|
|
300
300
|
summary: 'Peer isolation is judgment-class residual.',
|
|
301
301
|
});
|
|
302
302
|
}
|
|
@@ -314,7 +314,7 @@ function mapCountsAndFlags(byId, facts) {
|
|
|
314
314
|
markResidual(srp, 'Mirrored clusters suggest split-by-concern residual (architecture SRP).', {
|
|
315
315
|
kind: 'skill',
|
|
316
316
|
ref: '/ark-autopilot',
|
|
317
|
-
summary: 'One reshape/extraction pilot
|
|
317
|
+
summary: 'One reshape/extraction pilot this turn.',
|
|
318
318
|
});
|
|
319
319
|
}
|
|
320
320
|
const pureN = Number(facts.pureOrCapabilityResidual) || 0;
|
|
@@ -327,7 +327,7 @@ function mapCountsAndFlags(byId, facts) {
|
|
|
327
327
|
pushEvidence(dip, 'forbiddenGlobals', `residual:${fgN}`);
|
|
328
328
|
markResidual(dip, 'Pure / capability / forbidden residual weakens dependency inversion.', {
|
|
329
329
|
kind: 'skill',
|
|
330
|
-
ref: '/ark-
|
|
330
|
+
ref: '/ark-autopilot',
|
|
331
331
|
summary: 'Inject ports; keep pure layers free of effects.',
|
|
332
332
|
});
|
|
333
333
|
const test = byId.get('testability');
|
|
@@ -337,7 +337,7 @@ function mapCountsAndFlags(byId, facts) {
|
|
|
337
337
|
pushEvidence(test, 'forbiddenGlobals', `residual:${fgN}`);
|
|
338
338
|
markResidual(test, 'Impure domain or capability residual reduces testability.', {
|
|
339
339
|
kind: 'skill',
|
|
340
|
-
ref: '/ark-
|
|
340
|
+
ref: '/ark-autopilot',
|
|
341
341
|
summary: 'Prefer ports over concrete I/O in pure/domain modules.',
|
|
342
342
|
});
|
|
343
343
|
}
|
|
@@ -347,7 +347,7 @@ function mapCountsAndFlags(byId, facts) {
|
|
|
347
347
|
pushEvidence(enc, 'arkRules', `structureResidual:${arkN}`);
|
|
348
348
|
markResidual(enc, 'ArkRules structure residual — encapsulation inside the layer.', {
|
|
349
349
|
kind: 'skill',
|
|
350
|
-
ref: '/ark-
|
|
350
|
+
ref: '/ark-autopilot',
|
|
351
351
|
summary: 'Fix structure sensors under [ArkRules] without inventing mechanical-safe.',
|
|
352
352
|
});
|
|
353
353
|
const domain = byId.get('domain');
|
|
@@ -368,7 +368,7 @@ function mapCountsAndFlags(byId, facts) {
|
|
|
368
368
|
markResidual(m, 'Design-weak: checked edges may be clean, but design residual remains — not finished.', {
|
|
369
369
|
kind: 'skill',
|
|
370
370
|
ref: '/ark-explore',
|
|
371
|
-
summary: 'Shape door: explore shape-focus → dual-plan B → one pilot
|
|
371
|
+
summary: 'Shape door: explore shape-focus → dual-plan B → one /ark-autopilot pilot.',
|
|
372
372
|
});
|
|
373
373
|
}
|
|
374
374
|
if (facts.dirtyBaselineRisk === true || (Number(facts.baselineStale) || 0) > 0) {
|
|
@@ -409,7 +409,7 @@ function mapCountsAndFlags(byId, facts) {
|
|
|
409
409
|
pushEvidence(mod, 'coverage', `emptyLayers:${emptyL}`);
|
|
410
410
|
markResidual(mod, 'Placement / modularity residual — ungoverned dirs or empty layer globs.', {
|
|
411
411
|
kind: 'skill',
|
|
412
|
-
ref: '/ark-
|
|
412
|
+
ref: '/ark-adopt',
|
|
413
413
|
summary: 'Classify ungoverned paths; fix empty layer patterns.',
|
|
414
414
|
});
|
|
415
415
|
}
|
package/bin/lib/pilot-loop.mjs
CHANGED
|
@@ -115,7 +115,7 @@ export function extractionCardFromBet(bet, preferredFiles) {
|
|
|
115
115
|
reDoctor: 'ark-check --doctor --json',
|
|
116
116
|
rePlan: 'ark-check --plan --json',
|
|
117
117
|
next:
|
|
118
|
-
'/ark-
|
|
118
|
+
'/ark-autopilot (one cluster / one B pilot) | re-doctor after pilot',
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -16,13 +16,13 @@ export const POST_GREEN_PRIMARY_SKILL = '/ark-explore';
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Canonical human / agent next-action string (single door).
|
|
19
|
-
* Chained: explore shape-focus then autopilot
|
|
19
|
+
* Chained: explore shape-focus then autopilot applies one B pilot.
|
|
20
20
|
*/
|
|
21
21
|
export const POST_GREEN_PRIMARY_ACTION = POST_GREEN_HUMAN;
|
|
22
22
|
|
|
23
23
|
/** Short label for tables / metrics. */
|
|
24
24
|
export const POST_GREEN_PRIMARY_SHORT =
|
|
25
|
-
'/ark-explore shape-focus → /ark-autopilot (apply B
|
|
25
|
+
'/ark-explore shape-focus → /ark-autopilot (apply one B pilot) # Shape residual';
|
|
26
26
|
|
|
27
27
|
/** Placement coaching while design residual remains (new code only). */
|
|
28
28
|
export const POST_GREEN_PLACEMENT_COACHING =
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from './resolved-candidate-facts.mjs';
|
|
14
14
|
import { effectiveAnalysisConfig } from './analysis-policy.mjs';
|
|
15
15
|
import { isScanExcludedRelative } from '../ark-shared.mjs';
|
|
16
|
+
import { classifyChangeSet, evaluateTeamGate } from './team-parliament.mjs';
|
|
16
17
|
|
|
17
18
|
function candidatePath(value) {
|
|
18
19
|
if (typeof value !== 'string' || value.trim() === '') {
|
|
@@ -102,6 +103,14 @@ export function prepareChangeFromRoot({
|
|
|
102
103
|
const normalizedChanges = normalizeChangeSet(changes);
|
|
103
104
|
const normalizedOverlayChanges =
|
|
104
105
|
overlayChanges === undefined ? normalizedChanges : normalizeChangeSet(overlayChanges);
|
|
106
|
+
const lawGate = evaluateTeamGate({
|
|
107
|
+
changeSet: classifyChangeSet(normalizedChanges.map((change) => change.path)),
|
|
108
|
+
contractSession:
|
|
109
|
+
process.env.ARK_CONTRACT_SESSION === '1' || process.env.ARK_CONTRACT_SESSION === 'true',
|
|
110
|
+
});
|
|
111
|
+
if (lawGate.deny && lawGate.reasonId === 'mixed-law-and-product') {
|
|
112
|
+
throw new Error(lawGate.message);
|
|
113
|
+
}
|
|
105
114
|
const effectiveConfig = effectiveAnalysisConfig(config, manifest);
|
|
106
115
|
for (const change of normalizedChanges) {
|
|
107
116
|
assertInsideProject(root, change.path);
|
package/bin/lib/product-copy.mjs
CHANGED
|
@@ -23,7 +23,7 @@ export function operatingModeTitle(mode, leftoverDesign) {
|
|
|
23
23
|
export const LEFTOVER_DESIGN_BADGE = LEFTOVER_DESIGN_LABEL;
|
|
24
24
|
|
|
25
25
|
export const POST_GREEN_HUMAN =
|
|
26
|
-
'Imports check out, but the design is still messy. Map leftover work with /ark-explore shape-focus, then apply one small refactor via /ark-autopilot
|
|
26
|
+
'Imports check out, but the design is still messy. Map leftover work with /ark-explore shape-focus, then apply one small refactor via /ark-autopilot. A clean import check is not done; pattern bets are never auto-applied.';
|
|
27
27
|
|
|
28
28
|
export const POST_GREEN_LEDE =
|
|
29
29
|
'Import rules are clean, but leftover design work remains. That does not fail the check — it only means “done” is still wrong until you tidy shape.';
|
|
@@ -25,6 +25,7 @@ import { detectActiveAgentHost } from './skill-install.mjs';
|
|
|
25
25
|
import { readBaseline } from './violations.mjs';
|
|
26
26
|
import { reportsDir, readJsonSafe } from './html-report.mjs';
|
|
27
27
|
import { summarizeRulesUnderContract } from './rules-under-contract.mjs';
|
|
28
|
+
import { collectVsBaseFacts, discoverTeamBaseRef } from './team-parliament-io.mjs';
|
|
28
29
|
|
|
29
30
|
function sha256Hex(value) {
|
|
30
31
|
return createHash('sha256').update(value, 'utf8').digest('hex');
|
|
@@ -382,6 +383,17 @@ export function collectStatusFacts(options = {}) {
|
|
|
382
383
|
? 0
|
|
383
384
|
: null,
|
|
384
385
|
improvementCompass,
|
|
386
|
+
vsBase: (() => {
|
|
387
|
+
const vsRef = typeof options.vs === 'string' ? options.vs.trim() : '';
|
|
388
|
+
if (!vsRef) return null;
|
|
389
|
+
const baseRef = discoverTeamBaseRef(resolvedRoot, vsRef);
|
|
390
|
+
if (!baseRef) return null;
|
|
391
|
+
return collectVsBaseFacts({
|
|
392
|
+
root: resolvedRoot,
|
|
393
|
+
baseRef,
|
|
394
|
+
configRel: path.basename(configPath),
|
|
395
|
+
});
|
|
396
|
+
})(),
|
|
385
397
|
};
|
|
386
398
|
}
|
|
387
399
|
|
|
@@ -423,6 +435,7 @@ export function runStatusCommand(args = {}) {
|
|
|
423
435
|
expectedProjectId: args.expectedProjectId,
|
|
424
436
|
host: args.host,
|
|
425
437
|
arkgateVersion: args.arkgateVersion,
|
|
438
|
+
vs: args.vs,
|
|
426
439
|
});
|
|
427
440
|
|
|
428
441
|
if (asJson || args.json) {
|
|
@@ -471,6 +484,7 @@ export function runStatusCommand(args = {}) {
|
|
|
471
484
|
' · not a score'
|
|
472
485
|
);
|
|
473
486
|
}
|
|
487
|
+
if (manifest.vsBase?.line) write(` ${manifest.vsBase.line}`);
|
|
474
488
|
write(` next: [${manifest.nextAction.id}] ${manifest.nextAction.summary}`);
|
|
475
489
|
}
|
|
476
490
|
|
|
@@ -311,6 +311,9 @@ export function buildStatusManifest(facts) {
|
|
|
311
311
|
const compass = normalizeStatusImprovementCompass(facts.improvementCompass);
|
|
312
312
|
if (compass)
|
|
313
313
|
status.improvementCompass = compass;
|
|
314
|
+
if (facts.vsBase && typeof facts.vsBase.baseRef === 'string' && facts.vsBase.baseRef.length > 0) {
|
|
315
|
+
status.vsBase = facts.vsBase;
|
|
316
|
+
}
|
|
314
317
|
return status;
|
|
315
318
|
}
|
|
316
319
|
const STATUS_COMPASS_MODE_SET = new Set(STATUS_COMPASS_MODES);
|
|
@@ -576,5 +579,19 @@ export const ARK_STATUS_MANIFEST_SCHEMA = {
|
|
|
576
579
|
contractHash: { type: 'string', minLength: 1 },
|
|
577
580
|
},
|
|
578
581
|
},
|
|
582
|
+
vsBase: {
|
|
583
|
+
type: 'object',
|
|
584
|
+
description: 'Checkout vs a git base ref: pin, contract identity, baseline grow. Advisory honesty only — never a gate input.',
|
|
585
|
+
additionalProperties: false,
|
|
586
|
+
required: ['baseRef', 'line', 'pinLocal', 'pinBase', 'contractEqual', 'baselineGrew'],
|
|
587
|
+
properties: {
|
|
588
|
+
baseRef: { type: 'string', minLength: 1 },
|
|
589
|
+
line: { type: 'string', minLength: 1 },
|
|
590
|
+
pinLocal: { anyOf: [{ type: 'string', minLength: 1 }, { type: 'null' }] },
|
|
591
|
+
pinBase: { anyOf: [{ type: 'string', minLength: 1 }, { type: 'null' }] },
|
|
592
|
+
contractEqual: { type: 'boolean' },
|
|
593
|
+
baselineGrew: { type: 'boolean' },
|
|
594
|
+
},
|
|
595
|
+
},
|
|
579
596
|
},
|
|
580
597
|
};
|