| /** | ||
| * Doctor adapter for the Domain improvement compass (notAScore projection). | ||
| * Keeps doctor-plan.mjs inside its module budget; pure assembly only. | ||
| */ | ||
| import { | ||
| buildImprovementCompass, | ||
| formatImprovementCompassDoctorLines, | ||
| primaryImprovementCompassNextAction, | ||
| } from './improvement-compass.mjs'; | ||
| /** | ||
| * @param {{ | ||
| * designSmells?: object[], | ||
| * violations?: object[], | ||
| * designWeak?: boolean, | ||
| * physicalCohesion?: { findings?: object[] } | null, | ||
| * rulesUnderContract?: object | null, | ||
| * baselineExists?: boolean, | ||
| * baselineStale?: number | null, | ||
| * frozenResidual?: number | null, | ||
| * dirtyBaselineRisk?: boolean, | ||
| * ungovernedDirCount?: number, | ||
| * emptyLayerCount?: number, | ||
| * goldenPatternPresent?: boolean, | ||
| * arkRulesLoaded?: boolean, | ||
| * }} input | ||
| */ | ||
| export function buildDoctorImprovementCompass(input = {}) { | ||
| const violations = Array.isArray(input.violations) ? input.violations : []; | ||
| const ruleId = (v) => String(v?.ruleId ?? v?.code ?? ''); | ||
| let cycleCount = 0; | ||
| let peerIsolationCount = 0; | ||
| let pureOrCapabilityResidual = 0; | ||
| let forbiddenGlobalResidual = 0; | ||
| let arkRulesStructureResidual = 0; | ||
| for (const v of violations) { | ||
| const id = ruleId(v).toUpperCase(); | ||
| if (!id) continue; | ||
| if (id.includes('CYCLE') || id === 'CIRCULAR_DEPENDENCY') cycleCount += 1; | ||
| if (id.includes('PEER_ISOLATION')) peerIsolationCount += 1; | ||
| if (id === 'CAPABILITY_VIOLATION') pureOrCapabilityResidual += 1; | ||
| if (id === 'FORBIDDEN_GLOBAL' || id.startsWith('FORBIDDEN_')) forbiddenGlobalResidual += 1; | ||
| if (id.startsWith('ARKRULE_') || id === 'INVARIANT_UNCOVERED') arkRulesStructureResidual += 1; | ||
| } | ||
| const pcFindings = input.physicalCohesion?.findings; | ||
| const physicalCohesionFindingCount = Array.isArray(pcFindings) ? pcFindings.length : 0; | ||
| const arkRulesLoaded = | ||
| input.arkRulesLoaded === true || | ||
| input.rulesUnderContract?.active === true || | ||
| (typeof input.rulesUnderContract?.structureRules === 'number' && | ||
| input.rulesUnderContract.structureRules > 0); | ||
| return buildImprovementCompass({ | ||
| designSmells: Array.isArray(input.designSmells) ? input.designSmells : [], | ||
| violations: violations.map((v) => ({ | ||
| ruleId: ruleId(v) || undefined, | ||
| message: typeof v?.message === 'string' ? v.message : undefined, | ||
| file: typeof v?.file === 'string' ? v.file : typeof v?.path === 'string' ? v.path : undefined, | ||
| fromLayer: v?.fromLayer, | ||
| toLayer: v?.toLayer, | ||
| failsStrict: v?.failsStrict, | ||
| typeOnly: v?.typeOnly === true || v?.namedBindingsTypeOnly === true || undefined, | ||
| })), | ||
| cycleCount, | ||
| peerIsolationCount, | ||
| physicalCohesionFindingCount, | ||
| arkRulesLoaded, | ||
| arkRulesStructureResidual, | ||
| designWeak: input.designWeak === true, | ||
| baselineExists: input.baselineExists === true, | ||
| baselineStale: input.baselineStale ?? null, | ||
| frozenResidual: input.frozenResidual ?? null, | ||
| dirtyBaselineRisk: input.dirtyBaselineRisk === true, | ||
| pureOrCapabilityResidual, | ||
| forbiddenGlobalResidual, | ||
| ungovernedDirCount: Number(input.ungovernedDirCount) || 0, | ||
| emptyLayerCount: Number(input.emptyLayerCount) || 0, | ||
| goldenPatternPresent: input.goldenPatternPresent === true, | ||
| // Doctor path is TypeScript-oriented (ArkGate product surface). | ||
| stackKind: 'typescript', | ||
| }); | ||
| } | ||
| export { | ||
| formatImprovementCompassDoctorLines, | ||
| primaryImprovementCompassNextAction, | ||
| }; | ||
| /** | ||
| * Human doctor section (never a score bar). | ||
| * @param {import('./improvement-compass.mjs').ImprovementCompass} compass | ||
| * @param {{ line: Function, warn: string, ok: string, color: { bold: Function } }} io | ||
| */ | ||
| export function printImprovementCompassSection(compass, io) { | ||
| const { line, warn, ok, color } = io; | ||
| console.log(''); | ||
| console.log(color.bold('Improvement compass (not a score)')); | ||
| const mark = compass.topResidual.length > 0 ? warn : ok; | ||
| for (const text of formatImprovementCompassDoctorLines(compass)) { | ||
| line(mark, text); | ||
| } | ||
| } |
| /** | ||
| * GENERATED FILE — do not edit by hand. | ||
| * | ||
| * Canonical algorithm: src/domain/improvementCompass.ts | ||
| * Regenerate: node scripts/generate-cli-pure.mjs | ||
| * Drift check: node scripts/generate-cli-pure.mjs --check | ||
| * | ||
| * Pure CLI helper (bin/lib/improvement-compass.mjs). Zero Node I/O. | ||
| */ | ||
| export const ARK_IMPROVEMENT_COMPASS_SCHEMA_VERSION = '1.0'; | ||
| /** Closed 15 lens ids (stable order for projection). */ | ||
| export const IMPROVEMENT_LENS_IDS = [ | ||
| 'soc', | ||
| 'cohesion', | ||
| 'coupling', | ||
| 'srp', | ||
| 'dip', | ||
| 'ocp', | ||
| 'encapsulation', | ||
| 'modularity', | ||
| 'scalability', | ||
| 'resilience', | ||
| 'security', | ||
| 'maintainability', | ||
| 'testability', | ||
| 'domain', | ||
| 'stack', | ||
| ]; | ||
| /** Cap for topResidual — short, agent-legible list (not a ranking score). */ | ||
| export const IMPROVEMENT_COMPASS_TOP_RESIDUAL_CAP = 5; | ||
| /** Locked out-of-scope — never become residual from missing sensors. */ | ||
| export const IMPROVEMENT_COMPASS_OUT_OF_SCOPE_LENSES = [ | ||
| 'scalability', | ||
| 'resilience', | ||
| 'security', | ||
| ]; | ||
| const OUT_OF_SCOPE_SET = new Set(IMPROVEMENT_COMPASS_OUT_OF_SCOPE_LENSES); | ||
| /** | ||
| * Residual sort priority (lower = earlier in topResidual). Product relevance, | ||
| * not a health score. Ties break by id. | ||
| */ | ||
| const RESIDUAL_SORT_PRIORITY = { | ||
| soc: 10, | ||
| coupling: 20, | ||
| dip: 30, | ||
| domain: 40, | ||
| srp: 50, | ||
| cohesion: 60, | ||
| encapsulation: 70, | ||
| modularity: 80, | ||
| testability: 90, | ||
| maintainability: 100, | ||
| ocp: 110, | ||
| stack: 120, | ||
| scalability: 200, | ||
| resilience: 200, | ||
| security: 200, | ||
| }; | ||
| const LENS_LABELS = { | ||
| soc: 'Separation of concerns', | ||
| cohesion: 'High cohesion', | ||
| coupling: 'Low coupling', | ||
| srp: 'Single responsibility (architecture)', | ||
| dip: 'Dependency inversion', | ||
| ocp: 'Open/closed', | ||
| encapsulation: 'Encapsulation', | ||
| modularity: 'Modularity', | ||
| scalability: 'Scalability / performance', | ||
| resilience: 'Resilience / fault tolerance', | ||
| security: 'Security by design', | ||
| maintainability: 'Maintainability', | ||
| testability: 'Testability', | ||
| domain: 'Domain alignment', | ||
| stack: 'Stack-specific practices', | ||
| }; | ||
| const OUT_OF_SCOPE_SUMMARIES = { | ||
| scalability: 'ArkGate does not measure performance or horizontal scale. Use load tests and APM outside Ark.', | ||
| resilience: 'ArkGate does not measure app resilience or chaos readiness. Structural boundaries and optional experimental runtime are not a resilience score.', | ||
| security: 'ArkGate does not run SAST or app-security tooling. Structural least-privilege of effects is partial only — not a security rating.', | ||
| }; | ||
| function smellIdOf(smell) { | ||
| const raw = smell.id ?? smell.smellId ?? ''; | ||
| return typeof raw === 'string' ? raw.trim() : ''; | ||
| } | ||
| function violationRuleId(v) { | ||
| const raw = v.ruleId ?? v.code ?? ''; | ||
| return typeof raw === 'string' ? raw.trim() : ''; | ||
| } | ||
| function pushEvidence(lens, source, ref, detail) { | ||
| if (!ref) | ||
| return; | ||
| // Dedup by source+ref for deterministic stability. | ||
| if (lens.evidence.some((e) => e.source === source && e.ref === ref)) | ||
| return; | ||
| const entry = { source, ref }; | ||
| if (detail && detail.trim()) | ||
| entry.detail = detail.trim().slice(0, 240); | ||
| lens.evidence.push(entry); | ||
| } | ||
| function markResidual(lens, summary, nextAction) { | ||
| if (OUT_OF_SCOPE_SET.has(lens.id)) | ||
| return; | ||
| lens.status = 'residual'; | ||
| lens.summary = summary; | ||
| if (nextAction) | ||
| lens.nextAction = nextAction; | ||
| } | ||
| function defaultOkSummary(id) { | ||
| switch (id) { | ||
| case 'soc': | ||
| return 'No separation-of-concerns residual detected from current sensors.'; | ||
| case 'cohesion': | ||
| return 'No cohesion residual (god-module / physical cohesion) from current sensors.'; | ||
| case 'coupling': | ||
| return 'No coupling residual (import edges, cycles, peer isolation) from current sensors.'; | ||
| case 'srp': | ||
| return 'No single-responsibility residual from current sensors.'; | ||
| case 'dip': | ||
| return 'No dependency-inversion residual (pure / capability / forbidden walls) from current sensors.'; | ||
| case 'ocp': | ||
| return 'Open/closed is not strongly instrumented — no switch-chain sensor.'; | ||
| case 'encapsulation': | ||
| return 'No encapsulation residual from ArkRules structure sensors.'; | ||
| case 'modularity': | ||
| return 'No modularity / placement residual from current sensors.'; | ||
| case 'maintainability': | ||
| return 'No maintainability residual (design-weak / baseline honesty) from current sensors.'; | ||
| case 'testability': | ||
| return 'No testability residual (impure domain / capability walls) from current sensors.'; | ||
| case 'domain': | ||
| return 'No domain-alignment residual from current sensors.'; | ||
| case 'stack': | ||
| return 'Stack practices are only partially instrumented (TypeScript / host / Ark idioms).'; | ||
| default: | ||
| return `${LENS_LABELS[id]} — no residual from current sensors.`; | ||
| } | ||
| } | ||
| function initLenses() { | ||
| return IMPROVEMENT_LENS_IDS.map((id) => { | ||
| if (OUT_OF_SCOPE_SET.has(id)) { | ||
| const key = id; | ||
| return { | ||
| id, | ||
| status: 'out-of-scope', | ||
| summary: OUT_OF_SCOPE_SUMMARIES[key], | ||
| evidence: [], | ||
| nextAction: { | ||
| kind: 'docs', | ||
| ref: 'docs/use.md#improvement-compass', | ||
| summary: 'Out of scope for ArkGate — use dedicated tooling outside the gate.', | ||
| }, | ||
| }; | ||
| } | ||
| if (id === 'ocp') { | ||
| return { | ||
| id, | ||
| status: 'not-instrumented', | ||
| summary: defaultOkSummary(id), | ||
| evidence: [], | ||
| }; | ||
| } | ||
| return { | ||
| id, | ||
| status: 'ok', | ||
| summary: defaultOkSummary(id), | ||
| evidence: [], | ||
| }; | ||
| }); | ||
| } | ||
| function mapDesignSmells(byId, smells) { | ||
| for (const smell of smells) { | ||
| const id = smellIdOf(smell); | ||
| if (!id) | ||
| continue; | ||
| const detail = smell.outcome || smell.message || undefined; | ||
| const evidencePaths = Array.isArray(smell.evidence) ? smell.evidence : []; | ||
| const pathHint = evidencePaths[0]; | ||
| const attach = (lensId, summary, action) => { | ||
| const lens = byId.get(lensId); | ||
| if (!lens || OUT_OF_SCOPE_SET.has(lensId)) | ||
| return; | ||
| pushEvidence(lens, 'designSmells', id, detail); | ||
| if (pathHint) | ||
| pushEvidence(lens, 'designSmells', pathHint, id); | ||
| markResidual(lens, summary, action); | ||
| }; | ||
| const shapeAction = { | ||
| kind: 'skill', | ||
| ref: '/ark-explore', | ||
| summary: 'Map Shape residual (shape-focus), then one extraction pilot with user OK.', | ||
| }; | ||
| const dipAction = { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Inject a port/adapter for I/O; keep domain pure.', | ||
| }; | ||
| switch (id) { | ||
| case 'domain-logic-in-ui': | ||
| attach('soc', 'Business rules still mix with UI or presentation surfaces.', shapeAction); | ||
| attach('domain', 'Domain logic lives outside Domain — align rules with Domain ownership.', shapeAction); | ||
| break; | ||
| case 'facade-sql-in-routes': | ||
| attach('soc', 'Routes/controllers own SQL or ORM access — concerns are mixed.', shapeAction); | ||
| attach('dip', 'Transport depends on concrete persistence instead of a port.', dipAction); | ||
| break; | ||
| case 'io-under-application': | ||
| attach('soc', 'Application/business code reaches I/O directly — separation is weak.', shapeAction); | ||
| attach('dip', 'I/O is not inverted behind ports/adapters.', dipAction); | ||
| attach('testability', 'Direct I/O under application code hurts pure unit testing.', dipAction); | ||
| break; | ||
| case 'handler-in-persistence': | ||
| attach('soc', 'HTTP/transport handlers live under persistence folders.', shapeAction); | ||
| break; | ||
| case 'god-module': | ||
| attach('cohesion', 'Large multi-responsibility modules reduce cohesion.', shapeAction); | ||
| attach('srp', 'God modules own too many responsibilities — split by concern (one pilot).', { | ||
| kind: 'skill', | ||
| ref: '/ark-autopilot', | ||
| summary: 'One Shape pilot with user OK — never multi-pilot batch.', | ||
| }); | ||
| break; | ||
| case 'mixed-pattern-cluster': | ||
| attach('modularity', 'Multiple layout styles coexist — placement is unclear for the next AI turn.', { | ||
| kind: 'skill', | ||
| ref: '/ark-explore', | ||
| summary: 'Pick a golden pattern and migrate one pilot cluster on touch.', | ||
| }); | ||
| attach('cohesion', 'Mixed layout styles scatter the same concern across patterns.', shapeAction); | ||
| break; | ||
| case 'soft-contract': | ||
| attach('maintainability', 'Soft contract walls (layers without deny rules) hide maintainability debt.', { | ||
| kind: 'skill', | ||
| ref: '/ark-contract', | ||
| summary: 'Add real layer rules so the AI has hard walls.', | ||
| }); | ||
| attach('coupling', 'Layers with files but almost no deny rules allow free peer coupling.', { | ||
| kind: 'skill', | ||
| ref: '/ark-contract', | ||
| summary: 'Tighten inter-layer allows/denies without weakening enforcement.', | ||
| }); | ||
| break; | ||
| default: | ||
| // Unknown smell ids still feed maintainability residual (honest residual, | ||
| // not out-of-scope invention). | ||
| attach('maintainability', 'Design residual remains under an unrecognized smell id — review evidence.', shapeAction); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| function isTypeOnlyPlacementDebt(v) { | ||
| // Product voice: type-only edges are placement debt (failsStrict:false), not runtime coupling. | ||
| if (v.failsStrict === false) | ||
| return true; | ||
| if (v.typeOnly === true) | ||
| return true; | ||
| return false; | ||
| } | ||
| function mapViolations(byId, violations) { | ||
| for (const v of violations) { | ||
| const ruleId = violationRuleId(v); | ||
| if (!ruleId) | ||
| continue; | ||
| const detail = v.message; | ||
| const upper = ruleId.toUpperCase(); | ||
| const attach = (lensId, summary, action) => { | ||
| const lens = byId.get(lensId); | ||
| if (!lens || OUT_OF_SCOPE_SET.has(lensId)) | ||
| return; | ||
| pushEvidence(lens, 'violations', ruleId, detail); | ||
| if (v.file) | ||
| pushEvidence(lens, 'violations', v.file, ruleId); | ||
| markResidual(lens, summary, action); | ||
| }; | ||
| // Type-only / non-blocking placement debt → modularity only (never coupling / DIP residual). | ||
| if (isTypeOnlyPlacementDebt(v)) { | ||
| attach('modularity', 'Type-only placement debt remains — prefer SharedTypes / owning layer (not runtime coupling).', { | ||
| kind: 'skill', | ||
| ref: '/ark-place', | ||
| summary: 'Place shared types in a layer both sides may import; type-only debt is not a value edge.', | ||
| }); | ||
| continue; | ||
| } | ||
| const edgeAction = { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Clear the active edge residual, then re-doctor.', | ||
| }; | ||
| if (upper === 'LAYER_IMPORT_VIOLATION' || | ||
| upper.includes('LAYER_IMPORT') || | ||
| upper === 'DYNAMIC_IMPORT_VIOLATION') { | ||
| attach('coupling', 'Import graph edges violate the layer contract.', edgeAction); | ||
| continue; | ||
| } | ||
| if (upper.includes('CYCLE') || upper === 'CIRCULAR_DEPENDENCY') { | ||
| attach('coupling', 'Import cycles couple modules tightly.', edgeAction); | ||
| continue; | ||
| } | ||
| if (upper.includes('PEER_ISOLATION') || upper === 'PEER_ISOLATION_VIOLATION') { | ||
| attach('coupling', 'Peer isolation residual — slices import each other freely.', { | ||
| kind: 'skill', | ||
| ref: '/ark-loop', | ||
| summary: 'Peer isolation fixes are judgment-class — one cluster at a time.', | ||
| }); | ||
| continue; | ||
| } | ||
| if (upper === 'FORBIDDEN_GLOBAL' || upper.startsWith('FORBIDDEN_')) { | ||
| attach('dip', 'Forbidden globals / effect surfaces break dependency inversion.', { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Inject a port instead of the forbidden global.', | ||
| }); | ||
| attach('testability', 'Forbidden ambient effects reduce pure-domain testability.', { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Replace ambient effects with injectable ports.', | ||
| }); | ||
| continue; | ||
| } | ||
| if (upper === 'CAPABILITY_VIOLATION') { | ||
| attach('dip', 'Denied capability use — invert through an allowed adapter/port.', { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Capability walls require port injection (judgment, not mechanical-safe).', | ||
| }); | ||
| attach('testability', 'Capability violations couple domain code to I/O — harder to unit-test.', { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Keep pure layers free of denied capabilities.', | ||
| }); | ||
| continue; | ||
| } | ||
| if (upper.startsWith('ARKRULE_') || upper === 'INVARIANT_UNCOVERED') { | ||
| attach('encapsulation', 'ArkRules structure / invariant residual inside a layer.', { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Label [ArkRules]; structure fixes are judgment — never invent mechanical-safe.', | ||
| }); | ||
| attach('domain', 'Intra-layer domain structure or invariant coverage residual.', { | ||
| kind: 'skill', | ||
| ref: '/ark-explore', | ||
| summary: 'Inventory candidates → one ArkRules pilot with coverage evidence.', | ||
| }); | ||
| continue; | ||
| } | ||
| } | ||
| } | ||
| function mapCountsAndFlags(byId, facts) { | ||
| const cycleCount = Number(facts.cycleCount) || 0; | ||
| if (cycleCount > 0) { | ||
| const lens = byId.get('coupling'); | ||
| pushEvidence(lens, 'cycles', `count:${cycleCount}`); | ||
| markResidual(lens, 'Import cycles couple modules tightly.', { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Break cycles with a judgment extraction — one pilot.', | ||
| }); | ||
| } | ||
| const peer = typeof facts.peerIsolationCount === 'boolean' | ||
| ? facts.peerIsolationCount | ||
| ? 1 | ||
| : 0 | ||
| : Number(facts.peerIsolationCount) || 0; | ||
| if (peer > 0) { | ||
| const lens = byId.get('coupling'); | ||
| pushEvidence(lens, 'peerIsolation', `count:${peer}`); | ||
| markResidual(lens, 'Peer isolation residual remains.', { | ||
| kind: 'skill', | ||
| ref: '/ark-loop', | ||
| summary: 'Peer isolation is judgment-class residual.', | ||
| }); | ||
| } | ||
| const pc = Number(facts.physicalCohesionFindingCount) || 0; | ||
| if (pc > 0) { | ||
| const cohesion = byId.get('cohesion'); | ||
| pushEvidence(cohesion, 'physicalCohesion', `findings:${pc}`); | ||
| markResidual(cohesion, 'Physical cohesion residual — mirrored concept clusters across anchors.', { | ||
| kind: 'skill', | ||
| ref: '/ark-explore', | ||
| summary: 'Review reshape pilot; one decision-aware pilot at a time.', | ||
| }); | ||
| const srp = byId.get('srp'); | ||
| pushEvidence(srp, 'physicalCohesion', `findings:${pc}`); | ||
| markResidual(srp, 'Mirrored clusters suggest split-by-concern residual (architecture SRP).', { | ||
| kind: 'skill', | ||
| ref: '/ark-autopilot', | ||
| summary: 'One reshape/extraction pilot with user OK.', | ||
| }); | ||
| } | ||
| const pureN = Number(facts.pureOrCapabilityResidual) || 0; | ||
| const fgN = Number(facts.forbiddenGlobalResidual) || 0; | ||
| if (pureN > 0 || fgN > 0) { | ||
| const dip = byId.get('dip'); | ||
| if (pureN > 0) | ||
| pushEvidence(dip, 'capability', `residual:${pureN}`); | ||
| if (fgN > 0) | ||
| pushEvidence(dip, 'forbiddenGlobals', `residual:${fgN}`); | ||
| markResidual(dip, 'Pure / capability / forbidden residual weakens dependency inversion.', { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Inject ports; keep pure layers free of effects.', | ||
| }); | ||
| const test = byId.get('testability'); | ||
| if (pureN > 0) | ||
| pushEvidence(test, 'capability', `residual:${pureN}`); | ||
| if (fgN > 0) | ||
| pushEvidence(test, 'forbiddenGlobals', `residual:${fgN}`); | ||
| markResidual(test, 'Impure domain or capability residual reduces testability.', { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Prefer ports over concrete I/O in pure/domain modules.', | ||
| }); | ||
| } | ||
| const arkN = Number(facts.arkRulesStructureResidual) || 0; | ||
| if (arkN > 0) { | ||
| const enc = byId.get('encapsulation'); | ||
| pushEvidence(enc, 'arkRules', `structureResidual:${arkN}`); | ||
| markResidual(enc, 'ArkRules structure residual — encapsulation inside the layer.', { | ||
| kind: 'skill', | ||
| ref: '/ark-fix', | ||
| summary: 'Fix structure sensors under [ArkRules] without inventing mechanical-safe.', | ||
| }); | ||
| const domain = byId.get('domain'); | ||
| pushEvidence(domain, 'arkRules', `structureResidual:${arkN}`); | ||
| markResidual(domain, 'ArkRules residual may mean domain shape is not yet under contract.', { | ||
| kind: 'skill', | ||
| ref: '/ark-explore', | ||
| summary: 'Map inventory candidates; one pilot rule at a time.', | ||
| }); | ||
| } | ||
| else if (facts.arkRulesLoaded === false || facts.arkRulesLoaded == null) { | ||
| // No ArkRules → encapsulation stays ok (absence is valid), not residual. | ||
| // Domain remains ok unless other evidence marked it. | ||
| } | ||
| if (facts.designWeak === true) { | ||
| const m = byId.get('maintainability'); | ||
| pushEvidence(m, 'designFitness', 'design-weak'); | ||
| markResidual(m, 'Design-weak: checked edges may be clean, but design residual remains — not finished.', { | ||
| kind: 'skill', | ||
| ref: '/ark-explore', | ||
| summary: 'Shape door: explore shape-focus → dual-plan B → one pilot with OK.', | ||
| }); | ||
| } | ||
| if (facts.dirtyBaselineRisk === true || (Number(facts.baselineStale) || 0) > 0) { | ||
| const m = byId.get('maintainability'); | ||
| if (facts.dirtyBaselineRisk === true) { | ||
| pushEvidence(m, 'baseline', 'dirty-freeze-risk'); | ||
| } | ||
| if ((Number(facts.baselineStale) || 0) > 0) { | ||
| pushEvidence(m, 'baseline', `stale:${facts.baselineStale}`); | ||
| } | ||
| markResidual(m, 'Baseline honesty residual — frozen debt or stale keys need review.', { | ||
| kind: 'command', | ||
| ref: 'ark-check --doctor', | ||
| summary: 'Review baseline freeze honesty; do not freeze new wrong debt.', | ||
| }); | ||
| } | ||
| // Large frozen residual (baseline exists with many freezes) is maintainability debt — | ||
| // only when there is already a residual signal or a substantial freeze surface. | ||
| const frozenN = Number(facts.frozenResidual) || 0; | ||
| if (facts.baselineExists === true && frozenN >= 10 && byId.get('maintainability').status !== 'residual') { | ||
| const m = byId.get('maintainability'); | ||
| pushEvidence(m, 'baseline', `frozen:${frozenN}`); | ||
| markResidual(m, 'Substantial frozen residual remains under the baseline — review debt honestly.', { | ||
| kind: 'command', | ||
| ref: 'ark-check --doctor', | ||
| summary: 'Review freezes; do not freeze new wrong debt to clear residual.', | ||
| }); | ||
| } | ||
| const ungov = Number(facts.ungovernedDirCount) || 0; | ||
| const emptyL = Number(facts.emptyLayerCount) || 0; | ||
| if (ungov > 0 || emptyL > 0) { | ||
| const mod = byId.get('modularity'); | ||
| if (ungov > 0) | ||
| pushEvidence(mod, 'coverage', `ungovernedDirs:${ungov}`); | ||
| if (emptyL > 0) | ||
| pushEvidence(mod, 'coverage', `emptyLayers:${emptyL}`); | ||
| markResidual(mod, 'Placement / modularity residual — ungoverned dirs or empty layer globs.', { | ||
| kind: 'skill', | ||
| ref: '/ark-contract', | ||
| summary: 'Classify ungoverned paths; fix empty layer patterns.', | ||
| }); | ||
| } | ||
| // Missing golden pattern under design-weak → modularity residual (AI placement cue). | ||
| if (facts.designWeak === true && facts.goldenPatternPresent === false) { | ||
| const mod = byId.get('modularity'); | ||
| pushEvidence(mod, 'goldenPattern', 'absent'); | ||
| markResidual(mod, 'Design-weak without a golden pattern — new code lacks a placement norm for the AI.', { | ||
| kind: 'skill', | ||
| ref: '/ark-place', | ||
| summary: 'Record an advisory golden pattern for new code (does not clear design-weak).', | ||
| }); | ||
| } | ||
| // Stack: TypeScript host partially instrumented; unknown → not-instrumented. | ||
| const stack = byId.get('stack'); | ||
| const kind = facts.stackKind ?? null; | ||
| if (kind === 'typescript') { | ||
| // Partial instrumentation is still honest `ok` when no residual evidence. | ||
| if (stack.status === 'ok') { | ||
| stack.summary = | ||
| 'Stack practices are partially instrumented for TypeScript / host / Ark idioms only — not a full framework checklist.'; | ||
| } | ||
| } | ||
| else { | ||
| stack.status = 'not-instrumented'; | ||
| stack.summary = | ||
| 'Stack-specific best practices outside TypeScript/host/Ark idioms are not instrumented.'; | ||
| stack.evidence = []; | ||
| stack.nextAction = { | ||
| kind: 'docs', | ||
| ref: 'docs/use.md#improvement-compass', | ||
| summary: 'Ark does not score non-TS stack idioms.', | ||
| }; | ||
| } | ||
| } | ||
| function finalizeTopResidual(lenses) { | ||
| const residual = lenses | ||
| .filter((l) => l.status === 'residual' && !OUT_OF_SCOPE_SET.has(l.id)) | ||
| .slice() | ||
| .sort((a, b) => { | ||
| const pa = RESIDUAL_SORT_PRIORITY[a.id] ?? 150; | ||
| const pb = RESIDUAL_SORT_PRIORITY[b.id] ?? 150; | ||
| if (pa !== pb) | ||
| return pa - pb; | ||
| return a.id.localeCompare(b.id); | ||
| }); | ||
| return residual.slice(0, IMPROVEMENT_COMPASS_TOP_RESIDUAL_CAP).map((l) => l.id); | ||
| } | ||
| function humanLabel(id) { | ||
| return LENS_LABELS[id] ?? id; | ||
| } | ||
| /** | ||
| * Build a deterministic improvement compass from supplied doctor-side facts. | ||
| * Always returns all 15 lenses; always `notAScore: true`. | ||
| */ | ||
| export function buildImprovementCompass(facts = {}) { | ||
| const lenses = initLenses(); | ||
| const byId = new Map(lenses.map((l) => [l.id, l])); | ||
| if (Array.isArray(facts.designSmells) && facts.designSmells.length > 0) { | ||
| // Sort by smell id so projection is input-order independent. | ||
| const smells = [...facts.designSmells].sort((a, b) => smellIdOf(a).localeCompare(smellIdOf(b))); | ||
| mapDesignSmells(byId, smells); | ||
| } | ||
| if (Array.isArray(facts.violations) && facts.violations.length > 0) { | ||
| const violations = [...facts.violations].sort((a, b) => { | ||
| const ra = violationRuleId(a).localeCompare(violationRuleId(b)); | ||
| if (ra !== 0) | ||
| return ra; | ||
| return String(a.file ?? '').localeCompare(String(b.file ?? '')); | ||
| }); | ||
| mapViolations(byId, violations); | ||
| } | ||
| mapCountsAndFlags(byId, facts); | ||
| // Hard lock: out-of-scope can never be residual, even if bad facts arrive. | ||
| for (const id of IMPROVEMENT_COMPASS_OUT_OF_SCOPE_LENSES) { | ||
| const lens = byId.get(id); | ||
| lens.status = 'out-of-scope'; | ||
| lens.summary = OUT_OF_SCOPE_SUMMARIES[id]; | ||
| lens.evidence = []; | ||
| lens.nextAction = { | ||
| kind: 'docs', | ||
| ref: 'docs/use.md#improvement-compass', | ||
| summary: 'Out of scope for ArkGate — use dedicated tooling outside the gate.', | ||
| }; | ||
| } | ||
| // Stable evidence order per lens (source then ref). | ||
| for (const lens of lenses) { | ||
| lens.evidence.sort((a, b) => { | ||
| const s = a.source.localeCompare(b.source); | ||
| if (s !== 0) | ||
| return s; | ||
| return a.ref.localeCompare(b.ref); | ||
| }); | ||
| } | ||
| const topResidual = finalizeTopResidual(lenses); | ||
| return { | ||
| schemaVersion: ARK_IMPROVEMENT_COMPASS_SCHEMA_VERSION, | ||
| notAScore: true, | ||
| lenses: lenses.map((l) => { | ||
| const out = { | ||
| id: l.id, | ||
| status: l.status, | ||
| summary: l.summary, | ||
| evidence: l.evidence.map((e) => ({ ...e })), | ||
| }; | ||
| if (l.nextAction) { | ||
| out.nextAction = { ...l.nextAction }; | ||
| } | ||
| return out; | ||
| }), | ||
| topResidual, | ||
| }; | ||
| } | ||
| /** | ||
| * Plain residual lens names for human doctor / compact router (never a score). | ||
| */ | ||
| export function formatImprovementCompassResidualLabels(compass) { | ||
| return compass.topResidual.map((id) => humanLabel(id)); | ||
| } | ||
| /** | ||
| * Primary next action from the first residual lens that carries one. | ||
| */ | ||
| export function primaryImprovementCompassNextAction(compass) { | ||
| for (const id of compass.topResidual) { | ||
| const lens = compass.lenses.find((l) => l.id === id); | ||
| if (lens?.nextAction) | ||
| return { ...lens.nextAction }; | ||
| } | ||
| return null; | ||
| } | ||
| /** | ||
| * Human doctor lines (no score bar). Caller prefixes section header. | ||
| */ | ||
| export function formatImprovementCompassDoctorLines(compass) { | ||
| const residual = formatImprovementCompassResidualLabels(compass); | ||
| const outOfScope = IMPROVEMENT_COMPASS_OUT_OF_SCOPE_LENSES.map((id) => humanLabel(id)); | ||
| const next = primaryImprovementCompassNextAction(compass); | ||
| const lines = []; | ||
| if (residual.length > 0) { | ||
| lines.push(`Residual: ${residual.join(' · ')}`); | ||
| } | ||
| else { | ||
| lines.push('Residual: none on instrumented lenses (not a score — green edges ≠ finished design).'); | ||
| } | ||
| lines.push(`Out of scope (honest): ${outOfScope.join(' · ')}`); | ||
| if (next) { | ||
| lines.push(`Next: ${next.ref} — ${next.summary}`); | ||
| } | ||
| return lines; | ||
| } |
@@ -151,3 +151,3 @@ /** | ||
| if (profile === 'compact') { | ||
| lines.push('### Primary path', '', '1. Call `ark_identity` with `project.expectedRoot` at the exact project root; reuse root + `projectId` on Ark MCP calls.', '2. Read the contract with `ark_manifest` (same expectation). `ark://manifest` is compatibility-only / unverified.', '3. Place files inside configured layers; validate; run the check command above on violations — fix architecture, do not weaken the gate.', '', '### Contract layers (summary)', '', formatAgentProjectionLayers(layers), ''); | ||
| lines.push('### Primary path', '', '1. Run doctor (`ark-check --doctor`) — status light + primary next action.', '2. Read the improvement compass (not a score). Name residual lenses in plain language; never “done” on green edges alone while residual remains.', '3. Call `ark_identity` with `project.expectedRoot` at the exact project root; reuse root + `projectId` on Ark MCP calls.', '4. Read the contract with `ark_manifest` (same expectation). `ark://manifest` is compatibility-only / unverified.', '5. Place files inside configured layers; validate; run the check command above on violations — fix architecture, do not weaken the gate.', '6. Single door: edges debt → fix; design-weak / residual shape lenses → map then guided apply with user OK.', '', '### Contract layers (summary)', '', formatAgentProjectionLayers(layers), ''); | ||
| } | ||
@@ -154,0 +154,0 @@ else { |
@@ -406,7 +406,13 @@ /** | ||
| 1. Status anytime: \`${doctorCmd}\` — one status light, one next action (control plane). | ||
| 2. Before trusting MCP evidence: call \`ark_identity\` with \`project.expectedRoot\` set to this project's exact absolute root, then reuse that root plus the returned \`projectIdentity.projectId\` on every Ark MCP call. A descendant path is authoritative only with that matching id. Missing tool, non-\`matched\` binding, or wrong root means the process is stale: restart the host and use the local CLI meanwhile. | ||
| 3. Day to day: call \`ark_manifest\` with the same project expectation; place new files with \`ark_place\`; validate after edits; run \`${checkCmd}\`. The \`ark://manifest\` resource is compatibility-only and always unverified/non-authoritative. On a gate deny, fix the architecture — do not weaken the contract. | ||
| 4. If MCP is unavailable: inspect \`ark.config.json\` and run \`${checkCmd}\`. | ||
| 1. Status anytime: \`${doctorCmd}\` — one status light, one primary next action (control plane). | ||
| 2. Read the **Improvement compass** section (not a score). Name residual lenses in plain language when present (SoC, DIP, domain, …). Out-of-scope lenses (performance, app security tooling, full resilience) stay honest — do not invent Ark enforcement for them. | ||
| 3. Before trusting MCP evidence: call \`ark_identity\` with \`project.expectedRoot\` set to this project's exact absolute root, then reuse that root plus the returned \`projectIdentity.projectId\` on every Ark MCP call. A descendant path is authoritative only with that matching id. Missing tool, non-\`matched\` binding, or wrong root means the process is stale: restart the host and use the local CLI meanwhile. | ||
| 4. Day to day: call \`ark_manifest\` with the same project expectation; place new files with \`ark_place\`; validate after edits; run \`${checkCmd}\`. The \`ark://manifest\` resource is compatibility-only and always unverified/non-authoritative. On a gate deny, fix the architecture — do not weaken the contract. | ||
| 5. If MCP is unavailable: inspect \`ark.config.json\` and run \`${checkCmd}\`. | ||
| **Single door when residual remains:** | ||
| - **Edges debt** (import/capability violations) → fix with the gate / plan; skill pack only if doctor names a skill. | ||
| - **Design-weak / residual shape lenses** (compass residual while edges may look green) → map first, then guided apply with user OK — never “you’re done” on green edges alone. | ||
| - Empty plan A + residual lenses / design-weak → **not finished**. | ||
| The selected host is \`${selectedHost}\`. Host registration and CI are installed with this file. | ||
@@ -418,3 +424,3 @@ This compact router is enough for normal feature work. | ||
| Full \`/ark-*\` skills (including guided end-to-end \`/ark-autopilot\`) are **not** the default | ||
| curriculum. Install them only when doctor top action #1 or a STOP handoff names a skill: | ||
| curriculum. Install them only when doctor top action #1, residual compass, or a STOP handoff names a skill: | ||
@@ -421,0 +427,0 @@ \`${installSkills}\` |
@@ -65,2 +65,6 @@ /** Coverage, plan, and doctor CLI surfaces (roadmap #11). */ | ||
| import { enforcementDoctorLines } from './enforcement-state.mjs'; | ||
| import { | ||
| buildDoctorImprovementCompass, | ||
| printImprovementCompassSection, | ||
| } from './improvement-compass-doctor.mjs'; | ||
@@ -644,2 +648,19 @@ const color = { | ||
| // Improvement compass: projection only — never feeds ok/valid/goal.met. | ||
| const improvementCompass = buildDoctorImprovementCompass({ | ||
| designSmells, | ||
| violations, | ||
| designWeak: designFitness.designWeak === true, | ||
| physicalCohesion: doctorAdvisories.physicalCohesion, | ||
| rulesUnderContract, | ||
| baselineExists: baseline.exists, | ||
| baselineStale: analysisComplete ? staleBaseline : null, | ||
| frozenResidual: baseline.exists ? baseline.keys.size : null, | ||
| dirtyBaselineRisk: productHonesty?.reasonIds?.includes?.('dirty-baseline') === true, | ||
| ungovernedDirCount: cov.suggestions?.length ?? 0, | ||
| emptyLayerCount: cov.emptyLayers?.length ?? 0, | ||
| goldenPatternPresent: goldenPattern.present === true, | ||
| arkRulesLoaded: rulesUnderContract?.active === true, | ||
| }); | ||
| if (asJson) { | ||
@@ -659,2 +680,4 @@ (options.writeJson ?? console.log)( | ||
| designSmells, | ||
| // Improvement compass (lenses; notAScore; never a gate input). | ||
| improvementCompass, | ||
| ...(options.designDelta ? { designDelta: options.designDelta } : {}), | ||
@@ -852,2 +875,4 @@ // Q01: primary next action when Shape residual dominates (null if not design-weak). | ||
| printImprovementCompassSection(improvementCompass, { line, warn, ok, color }); | ||
| console.log(''); | ||
@@ -854,0 +879,0 @@ console.log(color.bold('Design fitness')); |
@@ -13,2 +13,3 @@ /** | ||
| import { formatRulesUnderContractHtml } from './rules-under-contract.mjs'; | ||
| import { primaryImprovementCompassNextAction } from './improvement-compass.mjs'; | ||
@@ -251,2 +252,33 @@ // htmlEscape is injected by the caller (html-report.mjs) — importing it back | ||
| /** Improvement compass — advisory lenses only; never a score bar or gate input. */ | ||
| function improvementCompassHtml(compass) { | ||
| if (!compass || compass.notAScore !== true || !Array.isArray(compass.lenses)) return ''; | ||
| const residual = Array.isArray(compass.topResidual) ? compass.topResidual : []; | ||
| const residualLine = | ||
| residual.length === 0 | ||
| ? '<p class="muted">Residual: none on instrumented lenses (not a score — green edges ≠ finished design).</p>' | ||
| : `<p><span class="tag warn">residual</span> ${residual | ||
| .map((id) => { | ||
| const lens = compass.lenses.find((l) => l.id === id); | ||
| return `<code>${esc(id)}</code>${lens?.summary ? ` — ${esc(lens.summary)}` : ''}`; | ||
| }) | ||
| .join('<br/>')}</p>`; | ||
| const oos = compass.lenses | ||
| .filter((l) => l && l.status === 'out-of-scope') | ||
| .map((l) => `<code>${esc(l.id)}</code>`) | ||
| .join(' · '); | ||
| // Same primary next as doctor human: severity-ordered topResidual, not lens-id order. | ||
| const next = primaryImprovementCompassNextAction(compass); | ||
| const nextLine = next | ||
| ? `<p class="muted">Next: <code>${esc(next.ref)}</code> — ${esc(next.summary)}</p>` | ||
| : ''; | ||
| return ` | ||
| <section class="section card" data-advisory="improvementCompass"> | ||
| <h2>Improvement compass <span class="muted">(not a score — projection only; never changes the verdict)</span></h2> | ||
| ${residualLine} | ||
| <p class="muted">Out of scope (honest): ${oos || 'scalability · resilience · security'}</p> | ||
| ${nextLine} | ||
| </section>`; | ||
| } | ||
| export function renderAdvisorySections(advisories, escape) { | ||
@@ -256,2 +288,3 @@ if (!advisories || typeof advisories !== 'object') return ''; | ||
| return [ | ||
| improvementCompassHtml(advisories.improvementCompass), | ||
| contractHealthHtml(advisories.contractHealth), | ||
@@ -258,0 +291,0 @@ ambientStateHtml(advisories.ambientState), |
@@ -24,2 +24,4 @@ /** | ||
| import { describePackageVersionDualTruth } from './field-install.mjs'; | ||
| import { buildDoctorImprovementCompass } from './improvement-compass-doctor.mjs'; | ||
| import { computePhysicalCohesion } from './physical-cohesion.mjs'; | ||
@@ -47,2 +49,3 @@ function esc(value) { | ||
| * activeBlockingCount?: number, | ||
| * baselineStale?: number | null, | ||
| * }} [baselineSplit] same numbers doctor uses (do not recompute from active-only list) | ||
@@ -160,2 +163,22 @@ */ | ||
| }); | ||
| // Doctor parity: same physical-cohesion + baseline stale facts as runDoctor. | ||
| const physicalCohesion = computePhysicalCohesion(root, files); | ||
| const baselineStale = | ||
| typeof baselineSplit.baselineStale === 'number' ? baselineSplit.baselineStale : null; | ||
| // Improvement compass — same projection as doctor; notAScore; never a gate input. | ||
| const improvementCompass = buildDoctorImprovementCompass({ | ||
| designSmells, | ||
| violations: activeViolations, | ||
| designWeak: designFitness.designWeak === true, | ||
| physicalCohesion, | ||
| rulesUnderContract, | ||
| baselineExists: baseline.exists || frozenKeys > 0, | ||
| baselineStale, | ||
| frozenResidual: frozenKeys, | ||
| dirtyBaselineRisk: productHonesty?.reasonIds?.includes?.('dirty-baseline') === true, | ||
| ungovernedDirCount: coverage?.suggestions?.length ?? 0, | ||
| emptyLayerCount: coverage?.emptyLayers?.length ?? 0, | ||
| goldenPatternPresent: goldenPattern.present === true, | ||
| arkRulesLoaded: rulesUnderContract?.active === true, | ||
| }); | ||
| return { | ||
@@ -172,2 +195,3 @@ adoption, | ||
| mergePlanes: rulesUnderContract?.mergePlanes ?? null, | ||
| improvementCompass, | ||
| }, | ||
@@ -174,0 +198,0 @@ }; |
@@ -281,3 +281,3 @@ /** | ||
| }; | ||
| return { | ||
| const status = { | ||
| schemaVersion: ARK_STATUS_MANIFEST_SCHEMA_VERSION, | ||
@@ -293,3 +293,25 @@ arkgateVersion: typeof facts.arkgateVersion === 'string' && facts.arkgateVersion.length > 0 | ||
| }; | ||
| const compass = normalizeStatusImprovementCompass(facts.improvementCompass); | ||
| if (compass) | ||
| status.improvementCompass = compass; | ||
| return status; | ||
| } | ||
| function normalizeStatusImprovementCompass(value) { | ||
| if (value == null || typeof value !== 'object') | ||
| return null; | ||
| if (value.notAScore !== true) | ||
| return null; | ||
| if (value.schemaVersion !== '1.0') | ||
| return null; | ||
| if (!Array.isArray(value.topResidual)) | ||
| return null; | ||
| const topResidual = value.topResidual | ||
| .filter((id) => typeof id === 'string' && id.length > 0) | ||
| .slice(0, 15); | ||
| return { | ||
| schemaVersion: '1.0', | ||
| notAScore: true, | ||
| topResidual, | ||
| }; | ||
| } | ||
| function numberOrNull(value) { | ||
@@ -395,3 +417,18 @@ if (value == null) | ||
| }, | ||
| improvementCompass: { | ||
| type: 'object', | ||
| description: 'Optional thin improvement-compass residual ids (notAScore). Never a gate input; full lenses on doctor JSON.', | ||
| additionalProperties: false, | ||
| required: ['schemaVersion', 'notAScore', 'topResidual'], | ||
| properties: { | ||
| schemaVersion: { const: '1.0' }, | ||
| notAScore: { const: true }, | ||
| topResidual: { | ||
| type: 'array', | ||
| items: { type: 'string', minLength: 1 }, | ||
| maxItems: 15, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }; |
+20
-4
@@ -62,4 +62,19 @@ # ArkGate — Agent Integration Guide | ||
| ### Unified status snapshot (4.3 / ACS03) | ||
| ### Improvement compass (doctor) | ||
| `ark-check --doctor` (human + `--json`) projects residual architecture work as a closed set of | ||
| **lenses** (`doctor.improvementCompass`). Always `notAScore: true`. Never feeds `valid`, | ||
| strict-merge exit, or plan `goal.met`. Out-of-scope lenses (scalability, app security tooling, | ||
| full resilience) stay honest. Product path: [use.md — Improvement compass](use.md#improvement-compass-not-a-score). | ||
| Package surface row: [package-surface.md](package-surface.md). | ||
| **Status snapshot:** the status schema may carry a thin optional residual-id slice when Tooling | ||
| passes it through, but **`ark status --json` does not compute the compass yet** — use doctor for | ||
| residual lenses. Residual never changes status `nextAction` by itself. | ||
| Compact router and skills read residual lenses in plain language; green edges alone are never | ||
| “architecture finished” while residual remains. | ||
| ### Unified status snapshot (4.3) | ||
| For one machine-readable session/project manifest (identity binding, honest write-path activation, | ||
@@ -79,3 +94,3 @@ last-check summary, rules residual counts, primary next action) use: | ||
| **Stable finding refs (4.3 / ACS06):** every factory-emitted diagnostic on CLI JSON, MCP analysis | ||
| **Stable finding refs (4.3):** every factory-emitted diagnostic on CLI JSON, MCP analysis | ||
| envelopes, and opt-in hook repair payloads (`ARK_REPAIR_JSON`) carries: | ||
@@ -93,3 +108,3 @@ | ||
| **Version-matched agent projection (4.3 / ACS04):** install/upgrade embeds a managed AGENTS.md | ||
| **Version-matched agent projection (4.3):** install/upgrade embeds a managed AGENTS.md | ||
| block stamped with the installed `arkgate` version plus a compact contract summary (layers + | ||
@@ -110,6 +125,7 @@ diagnostic short list). Regenerate after package upgrade without clobbering customized regions | ||
| **Agent Skills packaging (4.3 / ACS05):** the same frozen **13** skill names are also shipped as | ||
| **Agent Skills packaging (4.3):** the same frozen **13** skill names are also shipped as | ||
| an Agent Skills–compatible package under `templates/agent-skills/<name>/SKILL.md` for hosts that | ||
| install via `npx skills` (in addition to Ark `--install-agent-gates`). See | ||
| [Install skills — Ark and ecosystem](#install-skills-ark-and-ecosystem). No new skill names. | ||
| Skill bodies coach residual lenses and anti false-done; they never enforce. | ||
@@ -116,0 +132,0 @@ ## Architecture playbook and `ark-check --recommend` |
+6
-3
@@ -103,5 +103,8 @@ # Develop with ArkGate | ||
| npx arkgate-check --coverage | ||
| npx arkgate-check --doctor --json | ||
| npx arkgate-check --doctor --json # improvementCompass (notAScore lenses) + status light | ||
| ``` | ||
| Doctor residual lenses never flip `valid` / strict-merge alone. Product path: | ||
| [use.md — Improvement compass](use.md#improvement-compass-not-a-score). | ||
| Agent reference (tools, skills, dual path): [agent-guide.md](agent-guide.md). | ||
@@ -126,4 +129,4 @@ | ||
| npx arkgate-check --baseline | ||
| npx arkgate status --json # ACS03 session/project snapshot (not a score) | ||
| npx arkgate agents-md # ACS04 preview managed AGENTS block | ||
| npx arkgate status --json # session/project snapshot (not a score) | ||
| npx arkgate agents-md # preview managed AGENTS block | ||
| npx arkgate agents-md --write # embed/refresh projection markers | ||
@@ -130,0 +133,0 @@ npx arkgate preflight --changes changes.json --json |
| # ArkGate diagnostic code catalog | ||
| > **Source of truth:** Domain module `src/domain/diagnosticCatalog.ts` (ACS02). | ||
| > **Source of truth:** Domain module `src/domain/diagnosticCatalog.ts` (public diagnostic catalog). | ||
| > Generated CLI mirror: `bin/lib/diagnostic-catalog.mjs`. Catalog schema `1.0`. | ||
@@ -5,0 +5,0 @@ > Enforcement remains CLI / hooks / CI — this page is documentation only. |
+37
-34
@@ -19,21 +19,22 @@ # ArkGate package surface policy | ||
| |---------|----------------|-----------------| | ||
| | **CLI** | `arkgate` / `arkgate-check` (aliases `ark` / `ark-check`) | Flags and human text may improve; **JSON output shapes** for `--json` (check, doctor, plan, coverage, recommend, **status**, **agents-md**) are stable within a major. Additive fields OK; removals/renames are major. In 4.2, `--require-gates` implies strict config and verifies semantic Ark AGENTS, project-rooted MCP/compact Codex registration, and fail-closed CI rather than file presence alone. `ark status --json` is the ACS03 unified status snapshot. `ark agents-md` is the ACS04 version-matched agent projection (non-authoritative). | | ||
| | **CLI** | `arkgate` / `arkgate-check` (aliases `ark` / `ark-check`) | Flags and human text may improve; **JSON output shapes** for `--json` (check, doctor, plan, coverage, recommend, **status**, **agents-md**) are stable within a major. Additive fields OK; removals/renames are major. From 4.2, `--require-gates` implies strict config and verifies semantic Ark AGENTS, project-rooted MCP/compact Codex registration, and fail-closed CI rather than file presence alone. `ark status --json` is the unified status snapshot. `ark agents-md` is the version-matched agent projection (non-authoritative). | | ||
| | **Programmatic gate API** | `import { analyzeProject, loadContract, createAICodeGate, ... } from 'arkgate'` | The root export is the static gate/config/analysis contract listed below. It intentionally contains no runtime-kernel implementation. | | ||
| | **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`. Y02 extends `handler-in-persistence` to static ES imports/re-exports of framework HTTP surfaces (`next/server`), `defineRoute` calls, and existing handler bodies inside Persistence-role layers or specific persistence paths; `require()` and dynamic `import()` are outside this narrow advisory, and a generic `Infrastructure` role alone is not Persistence. Persistence candidates are filtered and sorted before the bounded content scan so large application prefixes cannot hide the advisory. The detector inspects the first 800 sorted Persistence candidates; later candidates are uninspected, so **absence of a smell is not full-tree proof** above that envelope (incomplete/`partial` analysis also never proves “no smells”). **4.2 feedback hardening:** mode labels preserve the observed SUGGEST/ADAPT/ENFORCE state; a local permission/UI-state `canEdit` name alone is not a domain smell; real UI business rules route Domain → Application → UI; seed/fixture/demo/migration/generated files are not god-module pilots. Each smell has `evidence[]`, `fix`, technical `message`, and plain-language **`outcome`** (Q02). Does **not** fail the gate by itself. | | ||
| | **Post-green path (Q01)** | `doctor.postGreenPath`, `doctor.primaryNextAction`, `doctor.healthyFinishedForbidden` | Additive when `designFitness.designWeak`. Single Shape door (`id: clarify-for-ai`): explore shape-focus → dual-plan B → autopilot only with OK. Never empty plan A = healthy finished. | | ||
| | **Golden pattern (Q03)** | Optional `.ark/golden-pattern.json`; doctor JSON `doctor.goldenPattern`; MCP `ark_place` / `ark_prepare_write` → `goldenPattern` | Additive, **advisory for NEW code only**. Required fields: `name`, `norm`; optional `newCodeHome`, `examplePath`, `schemaVersion`. **Absent is normal** (no claim). Never ENFORCE; never clears design-weak. Malformed → `invalid: true`, not silent guidance. | | ||
| | **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. | | ||
| | **Pilot loop (Q04)** | `plan.pilotLoop` / `doctor.pilotLoop` | Additive. When design-weak: `active`, `oneAtATime`, `neverMechanicalSafe`, **`nextPilot`** extraction-card fields (`pilotTarget`, `smellId`, `move`, `successSignal`, `killSwitch`, `doNot[]`). **One pilot → re-doctor**; never multi-pilot batch; never mechanical-safe. | | ||
| | **AI-velocity eval (Q05)** | Repository-only evidence: `npm run eval:ai-velocity` → `eval/ai-velocity-report.json` | Fixture-measured (no live LLM). Same feature scenario on design-weak vs golden-path arms; metric **`placementTurns`** (agent-equivalent). Golden must be strictly better. Method string lives next to the number. Does not weaken the gate. | | ||
| | **Contract health (W01)** | `ark-check --doctor --json` → `doctor.contractHealth`; optional `.ark/contract-smell-acks.json` | Additive, **advisory only** — meta-lint of the contract itself (layer-name heuristics; imprecision costs a warning line, never a verdict); never changes the verdict, `designFitness`, or `patternBets`. Stable smell ids: `contract-bidirectional-allow`, `contract-peripheral-depends-core`, `contract-lateral-adapter-allow`, `contract-dead-rule`; each smell has `severity`, `evidence[]` (sorted, honest `…(+N more)` truncation), `fix`, `message`, plain-language `outcome`, and `acknowledgedEdges` (acks applied to that id). **X03/X06**: the lateral smell does not fire on an adapter reaching its **own family's infra base** — the target reads `<Family><InfraWords…>` (**every** remaining target token an infra word: `Infra(structure)`/`Base`/`Core`/`Shared`/`Common`/`Kernel`/`Platform`/`Foundation`) and the source carries the family token **anywhere** in its name (X06, field: `HoursPersistenceAdapters -> PersistenceInfrastructure` — mid-name families). `PaymentsCoreAdapters` is still a sibling; cross-family edges, non-infra siblings, and the reverse (base → member) still fire. Acknowledgments live in the bounded sidecar (`{ acks: [{ id, edge, reason, reviewBy? }] }`, ≤64 KB / ≤200 entries; bidirectional edges order-insensitive, exact two segments); `contractHealth.acknowledged` counts **applied** acks only (stale acks count 0). **X02 ack lifecycle**: optional `reviewBy` (`YYYY-MM-DD`, strict round-trip validation — `2026-02-30` is malformed) — past the date the ack **stops applying** and the smell returns with `(ack expired …)` annotated evidence; among dated entries a fresh re-ack wins over a dead one, but once ANY dated ack exists for an edge the dated entries govern — a leftover undated duplicate cannot resurrect an expired exception. `detectContractSmells` defaults `today` to the real clock (pass `null` to disable expiry); `analyzeContractSmells` stays pure (clock injected). `contractHealth.ackLifecycle` reports `{ undated, malformed, expiredCount, expired[], staleCount, stale[] (lists capped at 12) }`; undated acks apply (backward compatible) but surface in doctor, report, and the fossilization note even when every smell is suppressed. **X05**: an ack matching **no detected edge** (orphaned by a fixed contract or quieted heuristic, unknown id, or typo'd edge) is `stale` — it suppresses nothing and doctor/report list the exact entries to fix or delete, even at zero visible smells. Malformed `reviewBy` never applies (fail-loud, like a sloppy edge); non-string `reviewBy` → whole file `invalid`. **Absent is normal**; malformed file or edge grammar → ignored + `ackFile.invalid` where applicable, never silent suppression. | | ||
| | **Effect capabilities (U03/Y08)** | Public root API: `analyzeProject(...).ir.capabilityUses`; the CLI/hook adapters add symbol-aware ambient evidence internally | Additive within IR `1.0`. Seven **closed** ids: `network`, `filesystem`, `clock`, `randomness`, `environment`, `process`, `persistence` (ADR 0009). `collectCapabilityUses` and the Domain vocabulary are internal implementation exports, **not** exports from `arkgate`; the related public low-level helper is `collectForbiddenCapabilityUses`. Direct evidence only — transitive inference never detects. The symbol-aware adapter path covers ambient globals (shadowing/type-only/globalThis-alias precision from the S05/C04 machinery) plus imports; the compiler-free IR engine carries **import-based** uses only (exact module or subpath match, never substring; textual `import type`/`export type` erasure and all-type named lists (`import { type A }`) are type-only there; mixed `{ type A, B }` stays a value import; template-literal bodies are skipped entirely (specifiers inside `${…}` are the symbol path's job); package `require(…)` counts as capability evidence only, while relative `require(…)` also emits a pure-path graph edge). **U04 walls are opt-in:** per-layer `capabilities: { deny: [...] }` or the dual-depth sugar `pure: true` (denies all seven); absence changes no verdict. `CAPABILITY_VIOLATION` is judgment-class (never mechanical-safe) with a port-injection `nextAction`; D7 dedup — evidence already owned by the layer's `forbiddenGlobals` reports only `FORBIDDEN_GLOBAL`. Y08 adds one deliberately narrow import dual: `forbiddenGlobals: ["process"]` owns exact value imports of `process` and `node:process`, but not subpaths or `child_process`; statement-level `import type` / `export type` remains erased on every path (pure-IR residual envelope: mixed `{ type A, B }`, default+named type lists, and comment-interrupted forms stay value imports; symbol path owns full precision). Atomic preflight blocks denied capabilities and that exact dual across a complete multi-file candidate (import-based on the pure path; other ambient evidence adds on the symbol-aware CLI/hook path). T01 policy-delta classifies the surface on **coverage atoms** (`ambient:<entry>` prefix-expanded, narrow `import-exact:<specifier>` duals, and `import:<capability>` for a complete wall): any lost atom is weakening (`fetch`→`XMLHttpRequest`, `Date`→`Date.now`, wall→fg all weaken; finding path `$.layers[name].capabilities`); fg → equivalent-or-stronger wall never needs an acknowledgment; unlowerable custom globals keep raw key comparison. | | ||
| | **Ambient state (U05)** | `ark-check --doctor --json` → `doctor.ambientState`; optional `.ark/ambient-state-acks.json` | Additive, **advisory only and opt-in**: only layers declared `pure: true` are scanned; the MVP shape is module-scope `let`/`var`. Findings carry `file`/`line`/`name`/`kind` (sorted, capped with honest `truncated` count). Acknowledgments live in the bounded sidecar (`{ acks: [{ file, name, reason }] }`, ≤64 KB / ≤200 entries); `acknowledged` counts applied acks; malformed file suppresses nothing. When TypeScript is unavailable the sensor reports `available: false` instead of guessing. **No strict mode exists** — A5: strictness requires a completed corpus and an explicit later decision. | | ||
| | **Parse health + analysis completeness (Y03/Z02)** | `ark-check --doctor --json` → `doctor.parseHealth` + `doctor.completeness`; check JSON → `completeness`; report section `data-advisory="parseHealth"` | The resolved candidate facts contribute only `parseDiagnosticCount` per governed file (no raw diagnostics, second parser pass, or `tsc`). Z04's correctness path ignores legacy v9 caches and parses the complete candidate on every invocation; Z07 owns any future identity-keyed warm snapshot. Doctor remains diagnostic: parse health adds no architecture violation and does not change `designFitness` or `patternBets`. Verdict surfaces consume the evidence fail-closed: affected governed files mean `partial`, plan `goal.met: false`, normal JSON `valid:false`/`ok:false`, and strict merge exit `1`; the non-strict process exit remains advisory for compatibility. No usable host means `unavailable`, plan false, and CLI exit `2`. JSON reports `scannedFiles`, `affectedFiles`, `diagnosticCount`, deterministic top-12 `{ file, diagnosticCount }` entries, and honest `truncated`/`overflow`; missing/unsafe evidence never becomes a clean claim. | | ||
| | **Physical cohesion + reshape pilot (X04/Y01)** | `ark-check --doctor --json` → `doctor.physicalCohesion` (`reshapePilot`, `reshapeDecisions`); optional `.ark/reshape-decisions.json`; report section `data-advisory="physicalCohesion"` | Additive, **advisory only** — `notAScore`; never feeds the verdict, `designFitness`, or `patternBets`. Signal is **concentration, not volume**: concept clusters per anchor directory (deterministic path/name tokenization; framework filenames like `route.ts` take the topmost meaningful path segment — ADR 0010 D2). Fixed corpus-calibrated thresholds (`maxCluster ≥ 40` OR ≥2 anchors ≥ 20, ADR 0010 D3); findings ranked and capped (top 5, honest `truncated`). Anchors under `app/`/`pages/` are `fixedByConvention` and never move (D7). `reshapePilot` is **proposed, never applied** (`neverMechanicalSafe`): one Q04-style pilot card at a time targeting the smallest convention-free anchor, with `moveSample`/`movesTotal`, `successSignal`, `killSwitch`, `doNot[]`; real moves run only through the write gate + atomic preflight via `/ark-loop`; merges are `/ark-architect` judgment cards, never a codemod (D6). **Y01 verdict memory:** bounded sidecar `{ schemaVersion?: "1", decisions: [{ concept, anchors, verdict: "accepted"|"deferred"|"rejected", reason, reviewBy? }] }` (≤64 KiB / ≤200 unique targets). Identity is concept + complete sorted anchor set, never counts/change-map evidence. Current rejected/deferred records suppress pilot pressure only; accepted keeps the existing path. Expired/malformed/stale/invalid records suppress nothing; lifecycle and decisions render in doctor/report. Explicit only — golden-pattern prose never infers a verdict. | | ||
| | **Capability walls, every adapter (U04+U06)** | CLI scan, pure IR engine, atomic preflight, `ark-mcp --hook` / MCP gate (`capabilityWalls`), ESLint `ark/no-denied-capabilities` | The same opt-in deny set enforces across every surface: hook/MCP and CLI cover ambient + import evidence (symbol-aware); the pure engine, preflight, and ESLint cover the import dimension (documented envelope). Dual depth everywhere: plain port hint (`FIX_HINTS`/`suggestion`) + stable JSON (`ruleId`, `capability`, `fixClass: inject-port`, deterministic `nextAction`). | | ||
| | **Hook-path budgets (U06)** | Repository-only evidence: `npm run bench:hook-path`; `eval/performance/hook-budgets.v1.json`; CI job "Hook-path end-to-end budgets" | Measures the COMPLETE pre-tool paths as fresh child processes (hook cold/warm, doctor cold) at 1k/10k. D5 method locked: ceilings are Linux-baseline p95 + fixed headroom, set once per cycle, never ratcheted; scenarios without a recorded baseline stay in RECORDING mode and cannot fail CI. | | ||
| | **Governance weight (W02)** | `ark-check --doctor --json` → `doctor.contractHealth.governanceWeight` | Additive, **advisory only** — raw facts (`declaredLayers`, `populatedLayers`, `governedFiles`, `rules`, `deniedEdges`, `allowedEdges`, `filesPerLayer`, `rulesPerLayer`) plus a fixed comparative band `weight: heavy | typical | light | unknown` and its fixed `note`. Fixed deterministic thresholds: **heavy** = fewer than 25 governed files per declared layer AND (6+ layers OR 4+ well-formed rules per layer); **light** = at most 2 layers over 150+ governed files; **unknown** = no layers or no governed files; everything else is **typical** (banding uses raw ratios; the reported ratios are rounded for display). `notAScore: true` is explicit: never a composite score, ranking, or gate input; the heavy note asks to justify NEW layers/rules and never suggests deleting working ones. Human doctor prints a line only for `heavy`/`light`. | | ||
| | **Report parity and snapshot evidence (X01/4.2)** | `ark-check --report` → advisory sections (`data-advisory="contractHealth\|ambientState\|parseHealth"`, nested `governanceWeight`) + layer wall badges; `.ark/reports/*.json` | The report is a rendering of doctor truth. **Standing rule:** every doctor advisory ships with its report section — enforced by the `reportParity` guard, which enumerates the doctor's advisory keys and fails on any missing section. Snapshots add best-effort Git `HEAD`/branch/dirty provenance without a shell; unavailable Git is explicit. Evolution renders the Ark score delta only when both snapshots name the same ArkGate version, while retaining raw facts across versions. | | ||
| | **Improvement compass (4.4)** | `ark-check --doctor --json` → `doctor.improvementCompass`; human doctor section **Improvement compass (not a score)**; HTML report `data-advisory="improvementCompass"`. Status schema accepts an optional thin `improvementCompass` residual-id slice for Tooling pass-through — **`ark status` does not compute lenses yet**; agents should read doctor for residual. | Additive schema `1.0`. Closed **15** lens ids (`soc`, `cohesion`, `coupling`, `srp`, `dip`, `ocp`, `encapsulation`, `modularity`, `scalability`, `resilience`, `security`, `maintainability`, `testability`, `domain`, `stack`) with status `ok` \| `residual` \| `not-instrumented` \| `out-of-scope`, evidence refs, optional `nextAction`, capped `topResidual`, always **`notAScore: true`**. Projection from existing smells / walls / cohesion / ArkRules / design-weak only — **never** a gate input (`valid` / strict-merge / `goal.met` unchanged). Out-of-scope locked for scalability, resilience, and app security (no residual invent from missing SAST/APM). Root API: `buildImprovementCompass` / `IMPROVEMENT_LENS_IDS`. | | ||
| | **Doctor design fitness** | `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`. `handler-in-persistence` covers static ES imports/re-exports of framework HTTP surfaces (`next/server`), `defineRoute` calls, and existing handler bodies inside Persistence-role layers or specific persistence paths; `require()` and dynamic `import()` are outside this narrow advisory, and a generic `Infrastructure` role alone is not Persistence. Persistence candidates are filtered and sorted before the bounded content scan so large application prefixes cannot hide the advisory. The detector inspects the first 800 sorted Persistence candidates; later candidates are uninspected, so **absence of a smell is not full-tree proof** above that envelope (incomplete/`partial` analysis also never proves “no smells”). **4.2 feedback hardening:** mode labels preserve the observed SUGGEST/ADAPT/ENFORCE state; a local permission/UI-state `canEdit` name alone is not a domain smell; real UI business rules route Domain → Application → UI; seed/fixture/demo/migration/generated files are not god-module pilots. Each smell has `evidence[]`, `fix`, technical `message`, and plain-language **`outcome`**. Does **not** fail the gate by itself. | | ||
| | **Post-green Shape door** | `doctor.postGreenPath`, `doctor.primaryNextAction`, `doctor.healthyFinishedForbidden` | Additive when `designFitness.designWeak`. Single Shape door (`id: clarify-for-ai`): explore shape-focus → dual-plan B → autopilot only with OK. Never empty plan A = healthy finished. | | ||
| | **Golden pattern (new code)** | Optional `.ark/golden-pattern.json`; doctor JSON `doctor.goldenPattern`; MCP `ark_place` / `ark_prepare_write` → `goldenPattern` | Additive, **advisory for NEW code only**. Required fields: `name`, `norm`; optional `newCodeHome`, `examplePath`, `schemaVersion`. **Absent is normal** (no claim). Never ENFORCE; never clears design-weak. Malformed → `invalid: true`, not silent guidance. | | ||
| | **Plan pattern B (Shape bets)** | `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. | | ||
| | **Pilot loop (one at a time)** | `plan.pilotLoop` / `doctor.pilotLoop` | Additive. When design-weak: `active`, `oneAtATime`, `neverMechanicalSafe`, **`nextPilot`** extraction-card fields (`pilotTarget`, `smellId`, `move`, `successSignal`, `killSwitch`, `doNot[]`). **One pilot → re-doctor**; never multi-pilot batch; never mechanical-safe. | | ||
| | **AI-velocity eval (maintainer)** | Repository-only evidence: `npm run eval:ai-velocity` → `eval/ai-velocity-report.json` | Fixture-measured (no live LLM). Same feature scenario on design-weak vs golden-path arms; metric **`placementTurns`** (agent-equivalent). Golden must be strictly better. Method string lives next to the number. Does not weaken the gate. | | ||
| | **Contract health** | `ark-check --doctor --json` → `doctor.contractHealth`; optional `.ark/contract-smell-acks.json` | Additive, **advisory only** — meta-lint of the contract itself (layer-name heuristics; imprecision costs a warning line, never a verdict); never changes the verdict, `designFitness`, or `patternBets`. Stable smell ids: `contract-bidirectional-allow`, `contract-peripheral-depends-core`, `contract-lateral-adapter-allow`, `contract-dead-rule`; each smell has `severity`, `evidence[]` (sorted, honest `…(+N more)` truncation), `fix`, `message`, plain-language `outcome`, and `acknowledgedEdges` (acks applied to that id). **X03/X06**: the lateral smell does not fire on an adapter reaching its **own family's infra base** — the target reads `<Family><InfraWords…>` (**every** remaining target token an infra word: `Infra(structure)`/`Base`/`Core`/`Shared`/`Common`/`Kernel`/`Platform`/`Foundation`) and the source carries the family token **anywhere** in its name (X06, field: `HoursPersistenceAdapters -> PersistenceInfrastructure` — mid-name families). `PaymentsCoreAdapters` is still a sibling; cross-family edges, non-infra siblings, and the reverse (base → member) still fire. Acknowledgments live in the bounded sidecar (`{ acks: [{ id, edge, reason, reviewBy? }] }`, ≤64 KB / ≤200 entries; bidirectional edges order-insensitive, exact two segments); `contractHealth.acknowledged` counts **applied** acks only (stale acks count 0). **X02 ack lifecycle**: optional `reviewBy` (`YYYY-MM-DD`, strict round-trip validation — `2026-02-30` is malformed) — past the date the ack **stops applying** and the smell returns with `(ack expired …)` annotated evidence; among dated entries a fresh re-ack wins over a dead one, but once ANY dated ack exists for an edge the dated entries govern — a leftover undated duplicate cannot resurrect an expired exception. `detectContractSmells` defaults `today` to the real clock (pass `null` to disable expiry); `analyzeContractSmells` stays pure (clock injected). `contractHealth.ackLifecycle` reports `{ undated, malformed, expiredCount, expired[], staleCount, stale[] (lists capped at 12) }`; undated acks apply (backward compatible) but surface in doctor, report, and the fossilization note even when every smell is suppressed. **X05**: an ack matching **no detected edge** (orphaned by a fixed contract or quieted heuristic, unknown id, or typo'd edge) is `stale` — it suppresses nothing and doctor/report list the exact entries to fix or delete, even at zero visible smells. Malformed `reviewBy` never applies (fail-loud, like a sloppy edge); non-string `reviewBy` → whole file `invalid`. **Absent is normal**; malformed file or edge grammar → ignored + `ackFile.invalid` where applicable, never silent suppression. | | ||
| | **Effect capabilities** | Public root API: `analyzeProject(...).ir.capabilityUses`; the CLI/hook adapters add symbol-aware ambient evidence internally | Additive within IR `1.0`. Seven **closed** ids: `network`, `filesystem`, `clock`, `randomness`, `environment`, `process`, `persistence` (ADR 0009). `collectCapabilityUses` and the Domain vocabulary are internal implementation exports, **not** exports from `arkgate`; the related public low-level helper is `collectForbiddenCapabilityUses`. Direct evidence only — transitive inference never detects. The symbol-aware adapter path covers ambient globals (shadowing/type-only/globalThis-alias precision from the S05/C04 machinery) plus imports; the compiler-free IR engine carries **import-based** uses only (exact module or subpath match, never substring; textual `import type`/`export type` erasure and all-type named lists (`import { type A }`) are type-only there; mixed `{ type A, B }` stays a value import; template-literal bodies are skipped entirely (specifiers inside `${…}` are the symbol path's job); package `require(…)` counts as capability evidence only, while relative `require(…)` also emits a pure-path graph edge). **U04 walls are opt-in:** per-layer `capabilities: { deny: [...] }` or the dual-depth sugar `pure: true` (denies all seven); absence changes no verdict. `CAPABILITY_VIOLATION` is judgment-class (never mechanical-safe) with a port-injection `nextAction`; D7 dedup — evidence already owned by the layer's `forbiddenGlobals` reports only `FORBIDDEN_GLOBAL`. Y08 adds one deliberately narrow import dual: `forbiddenGlobals: ["process"]` owns exact value imports of `process` and `node:process`, but not subpaths or `child_process`; statement-level `import type` / `export type` remains erased on every path (pure-IR residual envelope: mixed `{ type A, B }`, default+named type lists, and comment-interrupted forms stay value imports; symbol path owns full precision). Atomic preflight blocks denied capabilities and that exact dual across a complete multi-file candidate (import-based on the pure path; other ambient evidence adds on the symbol-aware CLI/hook path). T01 policy-delta classifies the surface on **coverage atoms** (`ambient:<entry>` prefix-expanded, narrow `import-exact:<specifier>` duals, and `import:<capability>` for a complete wall): any lost atom is weakening (`fetch`→`XMLHttpRequest`, `Date`→`Date.now`, wall→fg all weaken; finding path `$.layers[name].capabilities`); fg → equivalent-or-stronger wall never needs an acknowledgment; unlowerable custom globals keep raw key comparison. | | ||
| | **Ambient state (pure layers)** | `ark-check --doctor --json` → `doctor.ambientState`; optional `.ark/ambient-state-acks.json` | Additive, **advisory only and opt-in**: only layers declared `pure: true` are scanned; the MVP shape is module-scope `let`/`var`. Findings carry `file`/`line`/`name`/`kind` (sorted, capped with honest `truncated` count). Acknowledgments live in the bounded sidecar (`{ acks: [{ file, name, reason }] }`, ≤64 KB / ≤200 entries); `acknowledged` counts applied acks; malformed file suppresses nothing. When TypeScript is unavailable the sensor reports `available: false` instead of guessing. **No strict mode exists** — A5: strictness requires a completed corpus and an explicit later decision. | | ||
| | **Parse health + analysis completeness** | `ark-check --doctor --json` → `doctor.parseHealth` + `doctor.completeness`; check JSON → `completeness`; report section `data-advisory="parseHealth"` | The resolved candidate facts contribute only `parseDiagnosticCount` per governed file (no raw diagnostics, second parser pass, or `tsc`). Z04's correctness path ignores legacy v9 caches and parses the complete candidate on every invocation; Z07 owns any future identity-keyed warm snapshot. Doctor remains diagnostic: parse health adds no architecture violation and does not change `designFitness` or `patternBets`. Verdict surfaces consume the evidence fail-closed: affected governed files mean `partial`, plan `goal.met: false`, normal JSON `valid:false`/`ok:false`, and strict merge exit `1`; the non-strict process exit remains advisory for compatibility. No usable host means `unavailable`, plan false, and CLI exit `2`. JSON reports `scannedFiles`, `affectedFiles`, `diagnosticCount`, deterministic top-12 `{ file, diagnosticCount }` entries, and honest `truncated`/`overflow`; missing/unsafe evidence never becomes a clean claim. | | ||
| | **Physical cohesion + reshape pilot** | `ark-check --doctor --json` → `doctor.physicalCohesion` (`reshapePilot`, `reshapeDecisions`); optional `.ark/reshape-decisions.json`; report section `data-advisory="physicalCohesion"` | Additive, **advisory only** — `notAScore`; never feeds the verdict, `designFitness`, or `patternBets`. Signal is **concentration, not volume**: concept clusters per anchor directory (deterministic path/name tokenization; framework filenames like `route.ts` take the topmost meaningful path segment — ADR 0010 D2). Fixed corpus-calibrated thresholds (`maxCluster ≥ 40` OR ≥2 anchors ≥ 20, ADR 0010 D3); findings ranked and capped (top 5, honest `truncated`). Anchors under `app/`/`pages/` are `fixedByConvention` and never move (D7). `reshapePilot` is **proposed, never applied** (`neverMechanicalSafe`): one Q04-style pilot card at a time targeting the smallest convention-free anchor, with `moveSample`/`movesTotal`, `successSignal`, `killSwitch`, `doNot[]`; real moves run only through the write gate + atomic preflight via `/ark-loop`; merges are `/ark-architect` judgment cards, never a codemod (D6). **Y01 verdict memory:** bounded sidecar `{ schemaVersion?: "1", decisions: [{ concept, anchors, verdict: "accepted"|"deferred"|"rejected", reason, reviewBy? }] }` (≤64 KiB / ≤200 unique targets). Identity is concept + complete sorted anchor set, never counts/change-map evidence. Current rejected/deferred records suppress pilot pressure only; accepted keeps the existing path. Expired/malformed/stale/invalid records suppress nothing; lifecycle and decisions render in doctor/report. Explicit only — golden-pattern prose never infers a verdict. | | ||
| | **Capability walls, every adapter** | CLI scan, pure IR engine, atomic preflight, `ark-mcp --hook` / MCP gate (`capabilityWalls`), ESLint `ark/no-denied-capabilities` | The same opt-in deny set enforces across every surface: hook/MCP and CLI cover ambient + import evidence (symbol-aware); the pure engine, preflight, and ESLint cover the import dimension (documented envelope). Dual depth everywhere: plain port hint (`FIX_HINTS`/`suggestion`) + stable JSON (`ruleId`, `capability`, `fixClass: inject-port`, deterministic `nextAction`). | | ||
| | **Hook-path budgets (maintainer)** | Repository-only evidence: `npm run bench:hook-path`; `eval/performance/hook-budgets.v1.json`; CI job "Hook-path end-to-end budgets" | Measures the COMPLETE pre-tool paths as fresh child processes (hook cold/warm, doctor cold) at 1k/10k. D5 method locked: ceilings are Linux-baseline p95 + fixed headroom, set once per cycle, never ratcheted; scenarios without a recorded baseline stay in RECORDING mode and cannot fail CI. | | ||
| | **Governance weight** | `ark-check --doctor --json` → `doctor.contractHealth.governanceWeight` | Additive, **advisory only** — raw facts (`declaredLayers`, `populatedLayers`, `governedFiles`, `rules`, `deniedEdges`, `allowedEdges`, `filesPerLayer`, `rulesPerLayer`) plus a fixed comparative band `weight: heavy | typical | light | unknown` and its fixed `note`. Fixed deterministic thresholds: **heavy** = fewer than 25 governed files per declared layer AND (6+ layers OR 4+ well-formed rules per layer); **light** = at most 2 layers over 150+ governed files; **unknown** = no layers or no governed files; everything else is **typical** (banding uses raw ratios; the reported ratios are rounded for display). `notAScore: true` is explicit: never a composite score, ranking, or gate input; the heavy note asks to justify NEW layers/rules and never suggests deleting working ones. Human doctor prints a line only for `heavy`/`light`. | | ||
| | **Report parity and snapshot evidence (4.2)** | `ark-check --report` → advisory sections (`data-advisory="contractHealth\|ambientState\|parseHealth"`, nested `governanceWeight`) + layer wall badges; `.ark/reports/*.json` | The report is a rendering of doctor truth. **Standing rule:** every doctor advisory ships with its report section — enforced by the `reportParity` guard, which enumerates the doctor's advisory keys and fails on any missing section. Snapshots add best-effort Git `HEAD`/branch/dirty provenance without a shell; unavailable Git is explicit. Evolution renders the Ark score delta only when both snapshots name the same ArkGate version, while retaining raw facts across versions. | | ||
| | **MCP project identity (4.2)** | `ark_identity`; `arkgate/schema/project-identity` or `arkgate/schema/ark.project-identity.schema.json`; root API constants/helpers/types | Schema `1.0`. `projectId` hashes canonical root + config path and stays stable across contract edits/restarts; runtime id/start time are separate. Every project-bound tool result and error carries `projectIdentity`, `binding` (`matched` / `unverified` / `mismatch`), and `authoritative`. Canonical out-of-root config/file evidence fails before project data. | | ||
| | **MCP tools and compatibility resource** | `arkgate-mcp`; `ark_manifest`; `ark_status`; `ark://manifest` | Tool names and primary argument shapes are stable within a major. Every tool accepts additive `project.expectedRoot` / optional `expectedProjectId`. The initial handshake requires the exact project root; a contained descendant is authoritative only together with the matching project id. Legacy tool calls remain callable but `unverified` and non-authoritative. `ark_manifest` is the authoritative contract surface after binding. **`ark_status`** returns the ACS03 status manifest envelope (parity with `ark status --json`). Standard `resources/read` cannot portably carry the expectation, so `ark://manifest` remains compatibility-only and always unverified/non-authoritative. The server never retargets from input. | | ||
| | **MCP tools and compatibility resource** | `arkgate-mcp`; `ark_manifest`; `ark_status`; `ark://manifest` | Tool names and primary argument shapes are stable within a major. Every tool accepts additive `project.expectedRoot` / optional `expectedProjectId`. The initial handshake requires the exact project root; a contained descendant is authoritative only together with the matching project id. Legacy tool calls remain callable but `unverified` and non-authoritative. `ark_manifest` is the authoritative contract surface after binding. **`ark_status`** returns the status manifest envelope (parity with `ark status --json`). Standard `resources/read` cannot portably carry the expectation, so `ark://manifest` remains compatibility-only and always unverified/non-authoritative. The server never retargets from input. | | ||
| | **`ark.config.json`** | Layer globs, rules, include/exclude, forbiddenGlobals, intent prefixes, `peerIsolation`, `dynamicImportAllowlist`, `safety` thresholds; optional **`arkRules`** map (schema `1.1+`) | Versioned by `schemaVersion`; unknown fields fail closed and migrations preserve the previous supported major. Absence of `arkRules` is byte-for-byte silent on inter-layer verdicts. | | ||
@@ -43,20 +44,20 @@ | **ArkRules inventory / under-contract (4.0; layer context 4.2)** | `ark-check --rules-inventory [--json]`; doctor `rulesUnderContract`; MCP `ark_rules_inventory` | Additive. Honest counts (inventoried / under-contract / frozen) — **never a score**. When configured layer evidence exists it overrides filename role guesses: a Domain file named `handler` is not a controller candidate. Test/fixture/seed/migration/exclusion surfaces plus narrow development-identity, PostgreSQL OID, and technical I/O constants are silent. Without layer evidence, backward-compatible path/content heuristics remain. Structure/invariant diagnostics use adapter `1.4` provenance. | | ||
| | **Package pin dual-truth (4.0)** | doctor JSON `packageVersionTruth`; upgrade JSON/human note when pin behind CLI | Additive, advisory. Surfaces after `upgrade --no-install` when managed CLI is ahead of package.json. | | ||
| | **Product honesty readiness split (4.1.1 EH)** | doctor JSON `productHonesty` | Additive. `unfinished` / `headline` / `primaryNextAction` / `reasonIds` remain; EH adds `contractReadiness` (`ready`\|`partial`\|`not-ready`), `localWriteBoundary` (`advisory`\|`hard`\|`unverified`\|`unknown`), `architectureReasonIds`, `environmentResidualIds` / `environmentResiduals`. Soft-write hosts stay in evidence without alone forcing global **Not finished**. `notAScore: true` always. | | ||
| | **Policy transition analysis (T01, 3.1.0)** | `analyzePolicyDelta(...)`; MCP `ark_policy_delta`; CLI `--policy-base` / `--policy-base-ref` / `--policy-ack`; check JSON `policyDelta` | Additive schema `1.0`. Classifications and finding ids are deterministic. Weakening/judgment requires an acknowledgement bound to both policy hashes and the exact blocking finding set. | | ||
| | **Atomic change preflight (T02, 3.1.0)** | `preflightChange(...)`; CLI `ark preflight --changes <file> --json`; MCP `ark_prepare_change` | Additive schema `1.0`. One complete governed production-source `{path,content}` / `{path,delete:true}` batch; read-only; returns operation, content/tree/policy/compiler fingerprints and stable graph findings. MCP availability alone is advisory. | | ||
| | **Architecture change map (T03, 3.1.0)** | `arkgate/schema/change-map` or `arkgate/schema/ark.change-map.schema.json`; CLI `ark preflight --change-map <file>`; MCP `ark_prepare_change.changeMap` | Optional strict schema `1.0`. Canonical planned paths + operations + resolved Ark layers + dependencies between planned files. Preflight returns `changeMapHash`; absence is normal and adds no project file. Structural intent only, never behavioral completion. | | ||
| | **Structural convergence (T04, 3.1.0)** | `analyzeArchitectureConvergence(...)`; map-enabled `preflightChange(...)`; existing CLI/MCP preflight adapters | Additive `convergence` result with stable `satisfied`, `missing`, `contradictory`, and `unplanned` findings. Uses the supplied/current project tree as base and the explicit complete change set as candidate; no implicit Git or LLM input. `readOnly: true`; `behavioralCompletion: "not-evaluated"`. Structural mismatch makes preflight invalid. | | ||
| | **Enforcement ladder + fixed journey (T05, 3.1.0)** | `doctor.writePath.enforcementLadder`; hook repair `enforcement`; `npm run eval:change-integrity` | Additive schema `1.0` separates supported/installed/active/bypassable state and evidence. Hard is operation-scoped only for a supported covered hook; MCP is advisory; required CI status stays unverified locally. Fixed no-context fixture proves CLI/MCP/hook/final parity, one casual denial, acceptance behavior, and strict Ark. | | ||
| | **Enforcement state (Z06/Z10)** | `doctor.writePath.enforcementState`; schema/type | Schema `1.1`: runtime observation, operation coverage, and operation-scoped `hard`. Only fresh covered active-host evidence permits `hard:true`; unverified assets and MCP remain non-hard. | | ||
| | **Design delta (Z10)** | `--fail-on-new-smells --base-ref <ref>`; hook/MCP; schema/types | Schema `1.0`: identities, touched paths, stable evidence/verdict. Missing base fails closed; only new/worsened `domain-logic-in-ui` blocks; global doctor smells stay advisory. | | ||
| | **`arkgate/schema/analysis-result`** or **`arkgate/schema/ark.analysis-result.schema.json`** | Public CLI/MCP/hook diagnostic envelope (`schemaVersion`, `mode`, `valid`, `completeness`, `completenessReasons`, `diagnostics`, resolved identities) | Schema **`1.5`** (ACS06) adds optional stable finding refs on diagnostics: `findingRef` (`fnv1a-` + hex), `targetKey` (baseline-compatible freeze identity), `docsCodePath` (`docs/diagnostics.md#RULE_ID`). Factory-emitted diagnostics always include them; consumer-owned 1.0–1.4 values remain valid without them. `1.4` added optional `evidence.arkruleId` / `evidence.arkruleSource` for ArkRules; `1.3` distinguished `resolved-candidate-facts` from `lexical-compatibility`; partial/unavailable analysis is always non-green, and resolved complete/partial results require policy/resolver/facts/tree identities. `1.2` added completeness and remains accepted alongside consumer-owned 1.0/1.1 values. | | ||
| | **Stable finding refs (ACS06 / 4.3)** | Root API `adapterFindingTargetKey` / `adapterFindingRefFromTargetKey` / `toAdapterDiagnostic` / `createAdapterResult`; CLI/MCP/repair envelopes via analysis-result diagnostics | Multi-turn re-address without fuzzy message match. `targetKey` **is** the baseline (occurrence) key so freeze identity is never orphaned; `findingRef` is a compact FNV-1a of that key. Line/message drift does not change the ref. Multi-turn fixture: `tests/fixtures/finding-refs/multi-turn-stability.json`. | | ||
| | **Diagnostic code catalog (ACS02)** | Root API `DIAGNOSTIC_CATALOG` / `getDiagnosticCatalogEntry` / `diagnosticDocsPath`; docs [diagnostics.md](diagnostics.md) (`#RULE_ID` anchors) | Closed vocabulary of public `ruleId`s with why/fix anchors. Cataloguing only — no new rule semantics. Remediation parity is test-guarded. Docs ship in the npm tarball. | | ||
| | **Status manifest (ACS03)** | CLI `ark status [--json]`; MCP `ark_status`; `arkgate/schema/status-manifest`; root API `buildStatusManifest` / `ARK_STATUS_MANIFEST_SCHEMA` | Schema `1.0`. One session/project snapshot: identity binding, honest write-path activation (`hard`\|`advisory`\|`unavailable`), last-check summary, rules residual counts, primary next action. **Not a score.** Never prompts (`CI=1` forces JSON). Optional `--expected-root` / `--expected-project-id` (MCP `project`) for matched vs stale identity. | | ||
| | **Agent contract projection (ACS04)** | CLI `ark agents-md [--write] [--check] [--stdout] [--json]`; install/upgrade AGENTS templates; root API `buildAgentProjectionBlock` / `mergeAgentProjectionDocument` | Schema `1.0` (projection markers). Version-stamped managed block (`arkgateVersion` + contract summary + diagnostic short list). **Non-authoritative** — not a gate input; enforcement is ark-check / hooks / CI. Content-identity merge preserves customized regions outside markers. Drift: `--check` vs package version. | | ||
| | **Agent Skills packaging (ACS05)** | `templates/agent-skills/<name>/SKILL.md` (+ package README); root API `ARK_SKILL_NAMES` / `validateAgentSkillsPackage`; `npm run check:agent-skills` | Schema `1.0` (package contract). Same **13** skill names as flat templates; Agent Skills–compatible layout for `npx skills add`. No new skill names. Layout is generated 1:1 from `templates/skills/*.md`. | | ||
| | **Product honesty readiness split (4.1.1)** | doctor JSON `productHonesty` | Additive. `unfinished` / `headline` / `primaryNextAction` / `reasonIds` remain; EH adds `contractReadiness` (`ready`\|`partial`\|`not-ready`), `localWriteBoundary` (`advisory`\|`hard`\|`unverified`\|`unknown`), `architectureReasonIds`, `environmentResidualIds` / `environmentResiduals`. Soft-write hosts stay in evidence without alone forcing global **Not finished**. `notAScore: true` always. | | ||
| | **Policy transition analysis (3.1.0)** | `analyzePolicyDelta(...)`; MCP `ark_policy_delta`; CLI `--policy-base` / `--policy-base-ref` / `--policy-ack`; check JSON `policyDelta` | Additive schema `1.0`. Classifications and finding ids are deterministic. Weakening/judgment requires an acknowledgement bound to both policy hashes and the exact blocking finding set. | | ||
| | **Atomic change preflight (3.1.0)** | `preflightChange(...)`; CLI `ark preflight --changes <file> --json`; MCP `ark_prepare_change` | Additive schema `1.0`. One complete governed production-source `{path,content}` / `{path,delete:true}` batch; read-only; returns operation, content/tree/policy/compiler fingerprints and stable graph findings. MCP availability alone is advisory. | | ||
| | **Architecture change map (3.1.0)** | `arkgate/schema/change-map` or `arkgate/schema/ark.change-map.schema.json`; CLI `ark preflight --change-map <file>`; MCP `ark_prepare_change.changeMap` | Optional strict schema `1.0`. Canonical planned paths + operations + resolved Ark layers + dependencies between planned files. Preflight returns `changeMapHash`; absence is normal and adds no project file. Structural intent only, never behavioral completion. | | ||
| | **Structural convergence (3.1.0)** | `analyzeArchitectureConvergence(...)`; map-enabled `preflightChange(...)`; existing CLI/MCP preflight adapters | Additive `convergence` result with stable `satisfied`, `missing`, `contradictory`, and `unplanned` findings. Uses the supplied/current project tree as base and the explicit complete change set as candidate; no implicit Git or LLM input. `readOnly: true`; `behavioralCompletion: "not-evaluated"`. Structural mismatch makes preflight invalid. | | ||
| | **Enforcement ladder + fixed journey (3.1.0)** | `doctor.writePath.enforcementLadder`; hook repair `enforcement`; `npm run eval:change-integrity` | Additive schema `1.0` separates supported/installed/active/bypassable state and evidence. Hard is operation-scoped only for a supported covered hook; MCP is advisory; required CI status stays unverified locally. Fixed no-context fixture proves CLI/MCP/hook/final parity, one casual denial, acceptance behavior, and strict Ark. | | ||
| | **Enforcement state** | `doctor.writePath.enforcementState`; schema/type | Schema `1.1`: runtime observation, operation coverage, and operation-scoped `hard`. Only fresh covered active-host evidence permits `hard:true`; unverified assets and MCP remain non-hard. | | ||
| | **Design delta (opt-in ratchet)** | `--fail-on-new-smells --base-ref <ref>`; hook/MCP; schema/types | Schema `1.0`: identities, touched paths, stable evidence/verdict. Missing base fails closed; only new/worsened `domain-logic-in-ui` blocks; global doctor smells stay advisory. | | ||
| | **`arkgate/schema/analysis-result`** or **`arkgate/schema/ark.analysis-result.schema.json`** | Public CLI/MCP/hook diagnostic envelope (`schemaVersion`, `mode`, `valid`, `completeness`, `completenessReasons`, `diagnostics`, resolved identities) | Schema **`1.5`** adds optional stable finding refs on diagnostics: `findingRef` (`fnv1a-` + hex), `targetKey` (baseline-compatible freeze identity), `docsCodePath` (`docs/diagnostics.md#RULE_ID`). Factory-emitted diagnostics always include them; consumer-owned 1.0–1.4 values remain valid without them. `1.4` added optional `evidence.arkruleId` / `evidence.arkruleSource` for ArkRules; `1.3` distinguished `resolved-candidate-facts` from `lexical-compatibility`; partial/unavailable analysis is always non-green, and resolved complete/partial results require policy/resolver/facts/tree identities. `1.2` added completeness and remains accepted alongside consumer-owned 1.0/1.1 values. | | ||
| | **Stable finding refs (4.3)** | Root API `adapterFindingTargetKey` / `adapterFindingRefFromTargetKey` / `toAdapterDiagnostic` / `createAdapterResult`; CLI/MCP/repair envelopes via analysis-result diagnostics | Multi-turn re-address without fuzzy message match. `targetKey` **is** the baseline (occurrence) key so freeze identity is never orphaned; `findingRef` is a compact FNV-1a of that key. Line/message drift does not change the ref. Multi-turn fixture: `tests/fixtures/finding-refs/multi-turn-stability.json`. | | ||
| | **Diagnostic code catalog** | Root API `DIAGNOSTIC_CATALOG` / `getDiagnosticCatalogEntry` / `diagnosticDocsPath`; docs [diagnostics.md](diagnostics.md) (`#RULE_ID` anchors) | Closed vocabulary of public `ruleId`s with why/fix anchors. Cataloguing only — no new rule semantics. Remediation parity is test-guarded. Docs ship in the npm tarball. | | ||
| | **Status manifest** | CLI `ark status [--json]`; MCP `ark_status`; `arkgate/schema/status-manifest`; root API `buildStatusManifest` / `ARK_STATUS_MANIFEST_SCHEMA` | Schema `1.0`. One session/project snapshot: identity binding, honest write-path activation (`hard`\|`advisory`\|`unavailable`), last-check summary, rules residual counts, primary next action. Optional thin `improvementCompass` residual ids when Tooling supplies them. **Not a score.** Never prompts (`CI=1` forces JSON). Optional `--expected-root` / `--expected-project-id` (MCP `project`) for matched vs stale identity. | | ||
| | **Agent contract projection** | CLI `ark agents-md [--write] [--check] [--stdout] [--json]`; install/upgrade AGENTS templates; root API `buildAgentProjectionBlock` / `mergeAgentProjectionDocument` | Schema `1.0` (projection markers). Version-stamped managed block (`arkgateVersion` + contract summary + diagnostic short list). **Non-authoritative** — not a gate input; enforcement is ark-check / hooks / CI. Content-identity merge preserves customized regions outside markers. Drift: `--check` vs package version. | | ||
| | **Agent Skills packaging** | `templates/agent-skills/<name>/SKILL.md` (+ package README); root API `ARK_SKILL_NAMES` / `validateAgentSkillsPackage`; `npm run check:agent-skills` | Schema `1.0` (package contract). Same **13** skill names as flat templates; Agent Skills–compatible layout for `npx skills add`. No new skill names. Layout is generated 1:1 from `templates/skills/*.md`. | | ||
| | **`arkgate/schema/arkrules`** or **`arkgate/schema/ark.arkrules.schema.json`** | Per-layer structure sensors + invariant catalog (ADR 0012) | Schema `1.0`. Opt-in via root `arkRules` map (`ark.config` schema `1.1`). | | ||
| | **`arkgate/schema/resolved-candidate-facts`** or **`arkgate/schema/ark.resolved-candidate-facts.schema.json`** | Versioned parity-capable input for `analyzeResolvedProject` / `preflightResolvedChange` | Schema `1.0` is serializable and deterministic. Tooling owns filesystem/compiler resolution; Domain/Kernel validate and evaluate supplied facts without importing those effects. Facts name resolver/compiler inputs, governed files, dependency evidence, completeness reasons, and candidate tree/facts hashes. | | ||
| | **Config JSON Schema** | `arkgate/schema` or `arkgate/schema/ark.config.schema.json` | Stable package resource subpaths for editor completion and contract tooling. | | ||
| | **Agent skills** | `/ark-*` templates; install via `--install-agent-gates` (often `--skills-only` on top of compact) **or** Agent Skills ecosystem path | **Day zero** is the compact router from `ark start` / `start --apply` + doctor control plane — not the full skill pack. Skill *names* (frozen **13**) and the guided expert path (`/ark-autopilot` after pack install) are stable; internal skill prose may evolve. **4.0:** all skills except experimental `/ark-runtime` integrate **layers + ArkRules** and must label residual `[Layer]` vs `[ArkRules]`. **4.2:** repo catalogs are content-idempotent; the optional shared Codex home catalog is monotonic across 4.2.0+ installers. Pre-4.2 writers are outside that protocol and must be upgraded first. A durable pending-catalog journal preserves the floor across an interrupted install and is cleared only by its owning same/newer recovery. **4.3 / ACS05:** Agent Skills–compatible layout at `templates/agent-skills/<name>/SKILL.md` (1:1 with flat `templates/skills/*.md`); install via `npx skills add ./node_modules/arkgate/templates/agent-skills` (or the GitHub tree). Domain `ARK_SKILL_NAMES` + `validateAgentSkillsPackage`; drift `npm run check:agent-skills`. Skills never enforce. | | ||
| | **Agent skills** | `/ark-*` templates; install via `--install-agent-gates` (often `--skills-only` on top of compact) **or** Agent Skills ecosystem path | **Day zero** is the compact router from `ark start` / `start --apply` + doctor control plane — not the full skill pack. Skill *names* (frozen **13**) and the guided expert path (`/ark-autopilot` after pack install) are stable; internal skill prose may evolve. **4.0:** all skills except experimental `/ark-runtime` integrate **layers + ArkRules** and must label residual `[Layer]` vs `[ArkRules]`. **4.2:** repo catalogs are content-idempotent; the optional shared Codex home catalog is monotonic across 4.2.0+ installers. Pre-4.2 writers are outside that protocol and must be upgraded first. A durable pending-catalog journal preserves the floor across an interrupted install and is cleared only by its owning same/newer recovery. **4.3:** Agent Skills–compatible layout at `templates/agent-skills/<name>/SKILL.md` (1:1 with flat `templates/skills/*.md`); install via `npx skills add ./node_modules/arkgate/templates/agent-skills` (or the GitHub tree). Domain `ARK_SKILL_NAMES` + `validateAgentSkillsPackage`; drift `npm run check:agent-skills`. Skills never enforce. | | ||
| | **ESLint subpath** | `arkgate/eslint` | Config-driven layer/import rules; loads consumer `ark.config.json`. | | ||
@@ -208,4 +209,6 @@ | **GitHub Action** | `pedroknigge/arkgate` (see `action.yml`) | The `uses:` tag/SHA selects the checker source; `version` remains an optional exact npm compatibility override. | | ||
| Ship notes for a version live under [releases/](https://github.com/pedroknigge/arkgate/tree/main/docs/releases) | ||
| (prepared candidate: [4.3.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.3.0.md); | ||
| current published: [4.2.1.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.2.1.md); | ||
| (current published: [4.3.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.3.0.md); | ||
| next prepare: [4.4.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.4.0.md); | ||
| prior published: [4.2.1.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.2.1.md); | ||
| previous: [4.2.0.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.2.0.md), | ||
@@ -212,0 +215,0 @@ [4.1.1.md](https://github.com/pedroknigge/arkgate/blob/main/docs/releases/4.1.1.md), |
@@ -27,2 +27,7 @@ # ArkGate product voice | ||
| pass/fail gate. | ||
| - **Improvement compass (4.4.0):** residual architecture work is named as **lenses** (SoC, DIP, | ||
| domain alignment, …) projected from existing sensors — **never** a 0–10 score or Excellent/Good | ||
| rank. Out-of-scope lenses (perf, app security tooling, full resilience) stay honest. | ||
| - **Vibe-coder dual depth:** human doctor and skills lead with plain outcomes and one next move; | ||
| experts keep full JSON. Full-AI workflows get the same single door — not a skill menu exam. | ||
| - **False done is forbidden:** Enforce ≠ elegant design. `design-weak` / residual must not | ||
@@ -97,3 +102,24 @@ read as “healthy finished.” Empty ArkRules inventory is not a score. MCP configuration on | ||
| | **status snapshot** | One machine-readable project/session manifest (`ark status --json` shape): identity, activation honesty, last check, residual counts — not a numeric score | | ||
| | **improvement compass** | Closed projection of residual architecture work across fixed **lenses** (aligned to 15 common principles). Always `notAScore`. Never a gate input. | | ||
| | **lens** | One named principle dimension (`soc`, `dip`, `domain`, …) with status `ok` / `residual` / `not-instrumented` / `out-of-scope` and evidence refs from existing sensors | | ||
| | **topResidual** | Deterministic short list of residual lens ids — what to improve next, not a ranking score | | ||
| | **out-of-scope lens** | Principle Ark does not instrument (e.g. scalability APM, SAST) — say so; do not invent residual | | ||
| | **AI-easy architecture** | Small, pure, placeable modules and a golden pattern so the next agent turn stays ordered under the contract | | ||
| ## Public docs are product-only (from 4.4.0) | ||
| Consumer-facing prose (README, use/develop/agent-guide, skills, compact router, doctor/CLI human | ||
| lines, CHANGELOG user bullets, release notes bodies) explains **what ArkGate does and how to use | ||
| it**. It does **not** explain features by roadmap item codes, phase numbers, or internal queue | ||
| jargon (`IC02`, `ACS08`, `Z09`, `RB-11`, “Phase X shipped…”). | ||
| | Put here | Not here (for consumers) | | ||
| |----------|---------------------------| | ||
| | Commands, lenses, gates, skills, honest limits | Roadmap ids as the story | | ||
| | Stable API names (`ruleId`, JSON fields) | Ticket dumps in CHANGELOG | | ||
| | `ROADMAP.md` / `docs/plans/` / archive (maintainers) | Required reading of epic codes to use the product | | ||
| Historical maintainer files may keep engineering ids. **Do not regress** public lanes with new | ||
| id-heavy narrative after 4.4.0. | ||
| ## Scan vs process (dual depth) | ||
@@ -100,0 +126,0 @@ |
+6
-5
@@ -22,6 +22,6 @@ # ArkGate documentation | ||
| |-----|------------| | ||
| | [use.md](use.md) | One flow: install → doctor → day-to-day | | ||
| | [use.md](use.md) | One flow: install → doctor (+ improvement compass) → day-to-day | | ||
| | [enthusiast/](enthusiast/README.md) | Tutorials and plain-language track | | ||
| | [demos/](demos/) | Short end-to-end demos | | ||
| | [product-voice.md](product-voice.md) | How ArkGate should sound in English UI | | ||
| | [product-voice.md](product-voice.md) | How ArkGate should sound in English UI (compass = lenses, not scores) | | ||
@@ -57,3 +57,3 @@ ### Develop (integrate) | ||
| | Release notes (by version) | [releases/](releases/) · [CHANGELOG.md](../CHANGELOG.md) | | ||
| | Epic plans (seeded + shipped) | [plans/](plans/) · [agent contract surface 4.3](plans/agent-contract-surface-4.3/README.md) (Phase ACS → **4.3.0 prepared**; product voice: [guardrail catalog + scan/process](product-voice.md#scan-vs-process-dual-depth)); prior: [workspace identity](plans/workspace-identity-activation-truth/README.md) (WI / **4.2.0**; npm **4.2.1**) | | ||
| | Epic plans (seeded + shipped) | [plans/](plans/) — maintainer seeds (e.g. improvement compass for **4.4.0**, agent contract surface for **4.3.0**). Product how-to stays in use/develop/agent-guide; plans are not required reading to use the package. | | ||
| | Claims audit | [audit/claims-matrix.md](audit/claims-matrix.md) | | ||
@@ -63,4 +63,5 @@ | Field adoption kit (scaffolding, not closed) | [field/](field/) | | ||
| Prepared candidate: [releases/4.3.0.md](releases/4.3.0.md) (`arkgate@4.3.0`, not published yet). | ||
| Current published: [releases/4.2.1.md](releases/4.2.1.md) (`arkgate@4.2.1` on npm `latest`). | ||
| Current published: [releases/4.3.0.md](releases/4.3.0.md) (`arkgate@4.3.0` on npm `latest`). | ||
| Next prepare: [releases/4.4.0.md](releases/4.4.0.md) (Status: prepared — not on npm until publish verify). | ||
| Prior: [releases/4.2.1.md](releases/4.2.1.md) (`arkgate@4.2.1`). | ||
| Previous: [releases/4.2.0.md](releases/4.2.0.md) (`arkgate@4.2.0`) · [releases/4.1.1.md](releases/4.1.1.md) (`arkgate@4.1.1`). | ||
@@ -67,0 +68,0 @@ Previous major: [releases/4.0.0.md](releases/4.0.0.md) (`arkgate@4.0.0`). |
+37
-1
@@ -96,3 +96,3 @@ # Use ArkGate | ||
| 1. Doctor confirms design-weak | ||
| 1. Doctor confirms design-weak (and residual lenses on the improvement compass) | ||
| 2. Guided map / dual plan (skill pack: `/ark-explore` then `/ark-autopilot` with your OK) | ||
@@ -109,2 +109,37 @@ 3. One pilot at a time · re-run doctor | ||
| ## Improvement compass (not a score) | ||
| Doctor shows an **improvement compass**: a closed set of architecture **lenses** (separation of | ||
| concerns, dependency inversion, domain alignment, …) projected from existing sensors. | ||
| ```text | ||
| Improvement compass (not a score) | ||
| Residual: Separation of concerns · Dependency inversion · Domain alignment | ||
| Out of scope (honest): Scalability · App security tooling · Full resilience patterns | ||
| Next: /ark-explore — one pilot at a time after map | ||
| ``` | ||
| | Fact | Meaning | | ||
| |------|---------| | ||
| | Always `notAScore` | No 0–10, no Excellent/Good ranks, no averages | | ||
| | Residual lenses | What still matters for cleaner, AI-easy code | | ||
| | Out of scope | Performance/APM, SAST, full resilience — use other tools | | ||
| | Never a gate input | Residual alone does **not** fail CI or flip `valid` | | ||
| JSON: `ark-check --doctor --json` → `doctor.improvementCompass` (full lenses + `topResidual`). | ||
| Human doctor prints the short section above. | ||
| ### Align → Stabilize → Shape | ||
| | Phase | Goal | Done when (plain English) | | ||
| |-------|------|---------------------------| | ||
| | **Align** | Contract matches the tree | Include/layers honest; no false-green freeze | | ||
| | **Stabilize** | Edges under Enforce | Real debt only in baseline; write path + CI honest | | ||
| | **Shape** | One golden pattern + pilots | Residual lenses shrink pilot by pilot — never silent multi-pilot | | ||
| Green edges under **Enforce · design-weak** mean Align/Stabilize may be fine while Shape remains open. | ||
| Empty plan A is **not** “architecture finished.” | ||
| --- | ||
| ## Tutorials and demos | ||
@@ -123,2 +158,3 @@ | ||
| | Hosts, CI, MCP, brownfield, power CLI | [develop.md](develop.md) | | ||
| | Agent/CLI/MCP reference (status, skills, compass JSON) | [agent-guide.md](agent-guide.md) | | ||
| | Wire a specific agent host | [ai-gates.md](ai-gates.md) | | ||
@@ -125,0 +161,0 @@ | Improve the library | [CONTRIBUTING.md](../CONTRIBUTING.md) | |
+1
-1
| { | ||
| "name": "arkgate", | ||
| "version": "4.3.0", | ||
| "version": "4.4.0", | ||
| "description": "ArkGate — architecture co-pilot for AI TypeScript (write gate, CI gate, plan/loop; optional ArkRules)", | ||
@@ -5,0 +5,0 @@ "type": "module", |
+10
-7
@@ -19,5 +19,4 @@ <div align="center"> | ||
| > **ArkGate 4.3.0** is prepared (agent contract surface: catalog, status, projection, skills packaging, finding refs); | ||
| > **4.2.1** remains on npm `latest` until publication. | ||
| > [4.3.0 candidate](docs/releases/4.3.0.md) · [4.2.1](docs/releases/4.2.1.md) · [4.2.0](docs/releases/4.2.0.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md) | ||
| > **ArkGate 4.3.0** is on npm `latest`. Tree is preparing **4.4.0** (improvement compass) — see [4.4.0 notes](docs/releases/4.4.0.md) (Status: prepared until publish). | ||
| > [4.4.0 notes](docs/releases/4.4.0.md) · [4.3.0](docs/releases/4.3.0.md) · [4.2.1](docs/releases/4.2.1.md) · [Docs hub](docs/README.md) · [Product voice](docs/product-voice.md) | ||
@@ -48,6 +47,9 @@ --- | ||
| That is the product. Doctor is the control plane — when stuck, do **primary next action #1**. | ||
| Doctor also shows an **improvement compass** (architecture lenses such as separation of concerns and | ||
| dependency inversion — **not a score**). Residual lenses mean Shape work may remain even when edges | ||
| are green. Details: [use.md — Improvement compass](docs/use.md#improvement-compass-not-a-score). | ||
| ```text | ||
| start → doctor → day-to-day (place + gate) | ||
| ↘ optional /ark-autopilot after skill pack | ||
| start → doctor (+ compass) → day-to-day (place + gate) | ||
| ↘ optional /ark-autopilot after skill pack | ||
| ``` | ||
@@ -211,4 +213,5 @@ | ||
| | Security | [SECURITY.md](SECURITY.md) | | ||
| | Prepared candidate (4.3.0) | [docs/releases/4.3.0.md](docs/releases/4.3.0.md) · [CHANGELOG](CHANGELOG.md) | | ||
| | Current published (4.2.1) | [docs/releases/4.2.1.md](docs/releases/4.2.1.md) | | ||
| | Current release (4.3.0 on npm `latest`) | [docs/releases/4.3.0.md](docs/releases/4.3.0.md) · [CHANGELOG](CHANGELOG.md) | | ||
| | Next prepare (4.4.0) | [docs/releases/4.4.0.md](docs/releases/4.4.0.md) (prepared — not published until npm verify) | | ||
| | Prior (4.2.1) | [docs/releases/4.2.1.md](docs/releases/4.2.1.md) | | ||
| | Previous (4.2.0) | [docs/releases/4.2.0.md](docs/releases/4.2.0.md) | | ||
@@ -215,0 +218,0 @@ | Previous (4.1.1) | [docs/releases/4.1.1.md](docs/releases/4.1.1.md) | |
@@ -242,4 +242,30 @@ { | ||
| } | ||
| }, | ||
| "improvementCompass": { | ||
| "type": "object", | ||
| "description": "Optional thin improvement-compass residual ids (notAScore). Never a gate input; full lenses on doctor JSON.", | ||
| "additionalProperties": false, | ||
| "required": [ | ||
| "schemaVersion", | ||
| "notAScore", | ||
| "topResidual" | ||
| ], | ||
| "properties": { | ||
| "schemaVersion": { | ||
| "const": "1.0" | ||
| }, | ||
| "notAScore": { | ||
| "const": true | ||
| }, | ||
| "topResidual": { | ||
| "type": "array", | ||
| "items": { | ||
| "type": "string", | ||
| "minLength": 1 | ||
| }, | ||
| "maxItems": 15 | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
+2
-2
@@ -9,3 +9,3 @@ { | ||
| }, | ||
| "version": "4.3.0", | ||
| "version": "4.4.0", | ||
| "packages": [ | ||
@@ -15,3 +15,3 @@ { | ||
| "identifier": "arkgate", | ||
| "version": "4.3.0", | ||
| "version": "4.4.0", | ||
| "runtimeHint": "npx", | ||
@@ -18,0 +18,0 @@ "transport": { |
@@ -15,2 +15,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Spaghetti → honest contract.** SoC/DIP false-green STOP paths in plain language; residual lenses stay Incomplete until mapped. | ||
| ## When / not when | ||
@@ -168,2 +187,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -170,0 +190,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -8,2 +8,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Greenfield that is AI-easy day one:** golden norm + thin layers so the next agent turn stays ordered. | ||
| ## When / not when | ||
@@ -148,3 +167,3 @@ | ||
| ## Merge cards (X04 reshape — judgment only) | ||
| ## Merge cards (physical cohesion reshape — judgment only) | ||
@@ -173,2 +192,3 @@ When `doctor.physicalCohesion` reports a mirrored concept and the user asks whether files | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -175,0 +195,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -19,2 +19,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Guided vibe path:** phase 0 = doctor + compass residual. Shape only with user OK. Never script “done” while residual lenses remain. | ||
| ## When / not when | ||
@@ -27,6 +46,6 @@ | ||
| | User wants A + B planned and A executed | Single edge fix → `/ark-fix`; plan A only → `/ark-loop` | | ||
| | **Apply half of Q01 post-green path** (after explore map / when user wants full apply) | Skipping explore when doctor primary is Shape map-first | | ||
| | **Apply half of post-green Shape path** (after explore map / when user wants full apply) | Skipping explore when doctor primary is Shape map-first | | ||
| | Spaghetti under ENFORCE: Shape work with user ok on B | Contract false-green first → `/ark-adopt` / `/ark-contract` STOP paths | | ||
| **Q01:** doctor’s single door is `/ark-explore` shape-focus → dual-plan B, **then** this skill only | ||
| **Post-green door:** doctor’s single door is `/ark-explore` shape-focus → dual-plan B, **then** this skill only | ||
| to apply B with OK. Prefer that order when `postGreenPath` / design-weak is the primary residual. | ||
@@ -59,6 +78,6 @@ | ||
| 6. Apply A → re-run ark-check → rollback on regression. **Never auto-apply B** as mechanical-safe. | ||
| 7. **Q04 pilot loop for B:** when design-weak, take **`pilotLoop.nextPilot`** (one extraction card) | ||
| 7. **One-pilot loop for B:** when design-weak, take **`pilotLoop.nextPilot`** (one extraction card) | ||
| → apply **only** that pilot with user OK → **re-doctor**. Never multi-pilot batch B; residual | ||
| outside the pilot may remain and must not be called “healthy finished.” | ||
| 8. **Y01 reshape verdicts:** read `doctor.physicalCohesion.reshapeDecisions` before acting on | ||
| 8. **Reshape decision memory:** read `doctor.physicalCohesion.reshapeDecisions` before acting on | ||
| mirror facts. Outcome first: a current rejected/deferred verdict means “intentional/deferred | ||
@@ -205,3 +224,3 @@ layout — no pilot”; never reconstruct that dead card from `findings`. When the user accepts, | ||
| ## Mechanical-edit hygiene (Y04 — outcome gate) | ||
| ## Mechanical-edit hygiene (outcome gate) | ||
@@ -242,2 +261,3 @@ - Header injection must **merge into the existing doc comment**; the kept result has one `/**`, not stacked headers. | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -244,0 +264,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -8,2 +8,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Contract edits are last resort.** Policy-delta honesty; do not weaken rules to clear compass residual. | ||
| ## When / not when | ||
@@ -133,2 +152,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -135,0 +155,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -14,2 +14,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Fitness numbers + handoff** when residual lenses are non-empty — never call coverage “done architecture.” | ||
| ## When / not when | ||
@@ -164,2 +183,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -166,0 +186,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -10,2 +10,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Tour by lenses** (teach, not score). Prefer showcase HTML + doctor compass section when explaining residual. | ||
| ## When / not when | ||
@@ -204,2 +223,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -206,0 +226,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -18,2 +18,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Map residual lenses → dual-plan B seeds.** Plain Align / Stabilize / Shape from compass + design-weak — not a scorecard. | ||
| ## When / not when | ||
@@ -24,3 +43,3 @@ | ||
| | Map / “what next?” / residual after ENFORCE | User wants edits applied → `/ark-autopilot` or `/ark-fix` | | ||
| | **Primary post-green door (Q01):** messy / spaghetti / design-weak / “clarify for AI” | Skill-shopping coverage or think for the same residual | | ||
| | **Primary post-green door:** messy / spaghetti / design-weak / “clarify for AI” | Skill-shopping coverage or think for the same residual | | ||
| | Spaghetti brownfield: patterns concurrent, design-weak under green check | Only “governed% + gates installed?” numbers → `/ark-coverage` | | ||
@@ -30,3 +49,3 @@ | Dual-plan **seed** (A remediation + B pattern bets) without applying | One design trade-off between 2–3 options already mapped → `/ark-think` | | ||
| **Q01 single path:** when doctor `postGreenPath` / ENFORCE · design-weak is active, **this skill | ||
| **Post-green single path:** when doctor `postGreenPath` / ENFORCE · design-weak is active, **this skill | ||
| (shape-focus / dual-plan seed) is the map half of the one door** — then `/ark-autopilot` only | ||
@@ -284,3 +303,3 @@ to apply B with user OK. Do not send the user to coverage or think as equal first choices. | ||
| **Q04 pilot loop:** when doctor/plan JSON is available, use **`pilotLoop.nextPilot`** as the | ||
| **One-pilot loop:** when doctor/plan JSON is available, use **`pilotLoop.nextPilot`** as the | ||
| **single** next extraction card (one pilot at a time → re-doctor). Do not open five B bets | ||
@@ -377,2 +396,3 @@ in parallel. When `pilotLoop.queuedBets > 0`, those bets stay **queued**, not concurrent. | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -379,0 +399,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -12,2 +12,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Name residual lenses** on each cluster (SoC, DIP, coupling, …). Still no weaken-gate to clear a lens. | ||
| ## When / not when | ||
@@ -151,3 +170,3 @@ | ||
| ## Mechanical-edit hygiene (Y04 — outcome gate) | ||
| ## Mechanical-edit hygiene (outcome gate) | ||
@@ -159,3 +178,3 @@ - Header injection must **merge into the existing doc comment**; the kept result has one `/**`, not stacked headers. | ||
| ## Reshape findings (X04 — never mechanical) | ||
| ## Reshape findings (physical cohesion — never mechanical) | ||
@@ -184,2 +203,3 @@ If `doctor.physicalCohesion` fires while you fix: do **not** fold reshape moves into your fix | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -186,0 +206,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -15,2 +15,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Lens language on each cluster** while looping edges; residual shape lenses hand off to explore/autopilot. | ||
| ## When / not when | ||
@@ -117,3 +136,3 @@ | ||
| ## Mechanical-edit hygiene (Y04 — outcome gate) | ||
| ## Mechanical-edit hygiene (outcome gate) | ||
@@ -125,3 +144,3 @@ - Header injection must **merge into the existing doc comment**; the kept result has one `/**`, not stacked headers. | ||
| ## Reshape pilots (X04 — physical cohesion, advisory) | ||
| ## Reshape pilots (physical cohesion — physical cohesion, advisory) | ||
@@ -179,2 +198,3 @@ When `ark-check --doctor --json` carries `doctor.physicalCohesion.reshapePilot.nextPilot`, | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -181,0 +201,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -8,2 +8,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Where so the AI doesn’t mess up next time** — golden pattern + layer home before the write. | ||
| ## When / not when | ||
@@ -159,2 +178,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -161,0 +181,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -18,2 +18,8 @@ --- | ||
| ## Improvement compass note | ||
| This skill is **experimental runtime** only. Do **not** treat runtime adoption as residual on the | ||
| resilience lens unless the user explicitly opts into the experimental kernel. Prefer doctor compass | ||
| for static architecture residual; hand static residual to `/ark-explore` / `/ark-fix`. | ||
| ## Dual engine (mandatory) | ||
@@ -117,2 +123,3 @@ | ||
| - **Result:** one-line outcome | ||
| - **Compass:** `n/a` (runtime skill; static residual → explore/fix) | top residual if doctor was run | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -119,0 +126,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -12,2 +12,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **2–3 options labeled by lens impact** (what residual improves / what stays out-of-scope). | ||
| ## When / not when | ||
@@ -130,2 +149,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -132,0 +152,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -16,2 +16,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **After upgrade:** refresh projection; re-doctor; compass residual still drives process, not scores. | ||
| ## Dual engine (mandatory) | ||
@@ -215,2 +234,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…`, CLI action, or `none` | ||
@@ -217,0 +237,0 @@ - **Incomplete?** `no` or `yes — <missing work>` |
| # ArkGate Agent Skills package | ||
| > **Generated layout (ACS05).** Do not edit SKILL.md files here by hand. | ||
| > **Generated layout (Agent Skills packaging).** Do not edit SKILL.md files here by hand. | ||
| > Author skill bodies in `templates/skills/<name>.md`, then run | ||
@@ -10,3 +10,3 @@ > `npm run generate:agent-skills`. Drift: `npm run check:agent-skills`. | ||
| Package version when last generated context: **arkgate@4.2.1** | ||
| Package version when last generated context: **arkgate@4.3.0** | ||
| Schema: agent-skills package contract `1.0` | ||
@@ -13,0 +13,0 @@ |
@@ -15,2 +15,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Spaghetti → honest contract.** SoC/DIP false-green STOP paths in plain language; residual lenses stay Incomplete until mapped. | ||
| ## When / not when | ||
@@ -168,2 +187,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -170,0 +190,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -8,2 +8,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Greenfield that is AI-easy day one:** golden norm + thin layers so the next agent turn stays ordered. | ||
| ## When / not when | ||
@@ -148,3 +167,3 @@ | ||
| ## Merge cards (X04 reshape — judgment only) | ||
| ## Merge cards (physical cohesion reshape — judgment only) | ||
@@ -173,2 +192,3 @@ When `doctor.physicalCohesion` reports a mirrored concept and the user asks whether files | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -175,0 +195,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -19,2 +19,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Guided vibe path:** phase 0 = doctor + compass residual. Shape only with user OK. Never script “done” while residual lenses remain. | ||
| ## When / not when | ||
@@ -27,6 +46,6 @@ | ||
| | User wants A + B planned and A executed | Single edge fix → `/ark-fix`; plan A only → `/ark-loop` | | ||
| | **Apply half of Q01 post-green path** (after explore map / when user wants full apply) | Skipping explore when doctor primary is Shape map-first | | ||
| | **Apply half of post-green Shape path** (after explore map / when user wants full apply) | Skipping explore when doctor primary is Shape map-first | | ||
| | Spaghetti under ENFORCE: Shape work with user ok on B | Contract false-green first → `/ark-adopt` / `/ark-contract` STOP paths | | ||
| **Q01:** doctor’s single door is `/ark-explore` shape-focus → dual-plan B, **then** this skill only | ||
| **Post-green door:** doctor’s single door is `/ark-explore` shape-focus → dual-plan B, **then** this skill only | ||
| to apply B with OK. Prefer that order when `postGreenPath` / design-weak is the primary residual. | ||
@@ -59,6 +78,6 @@ | ||
| 6. Apply A → re-run ark-check → rollback on regression. **Never auto-apply B** as mechanical-safe. | ||
| 7. **Q04 pilot loop for B:** when design-weak, take **`pilotLoop.nextPilot`** (one extraction card) | ||
| 7. **One-pilot loop for B:** when design-weak, take **`pilotLoop.nextPilot`** (one extraction card) | ||
| → apply **only** that pilot with user OK → **re-doctor**. Never multi-pilot batch B; residual | ||
| outside the pilot may remain and must not be called “healthy finished.” | ||
| 8. **Y01 reshape verdicts:** read `doctor.physicalCohesion.reshapeDecisions` before acting on | ||
| 8. **Reshape decision memory:** read `doctor.physicalCohesion.reshapeDecisions` before acting on | ||
| mirror facts. Outcome first: a current rejected/deferred verdict means “intentional/deferred | ||
@@ -205,3 +224,3 @@ layout — no pilot”; never reconstruct that dead card from `findings`. When the user accepts, | ||
| ## Mechanical-edit hygiene (Y04 — outcome gate) | ||
| ## Mechanical-edit hygiene (outcome gate) | ||
@@ -242,2 +261,3 @@ - Header injection must **merge into the existing doc comment**; the kept result has one `/**`, not stacked headers. | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -244,0 +264,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -8,2 +8,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Contract edits are last resort.** Policy-delta honesty; do not weaken rules to clear compass residual. | ||
| ## When / not when | ||
@@ -133,2 +152,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -135,0 +155,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -14,2 +14,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Fitness numbers + handoff** when residual lenses are non-empty — never call coverage “done architecture.” | ||
| ## When / not when | ||
@@ -164,2 +183,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -166,0 +186,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -10,2 +10,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Tour by lenses** (teach, not score). Prefer showcase HTML + doctor compass section when explaining residual. | ||
| ## When / not when | ||
@@ -204,2 +223,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -206,0 +226,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -18,2 +18,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Map residual lenses → dual-plan B seeds.** Plain Align / Stabilize / Shape from compass + design-weak — not a scorecard. | ||
| ## When / not when | ||
@@ -24,3 +43,3 @@ | ||
| | Map / “what next?” / residual after ENFORCE | User wants edits applied → `/ark-autopilot` or `/ark-fix` | | ||
| | **Primary post-green door (Q01):** messy / spaghetti / design-weak / “clarify for AI” | Skill-shopping coverage or think for the same residual | | ||
| | **Primary post-green door:** messy / spaghetti / design-weak / “clarify for AI” | Skill-shopping coverage or think for the same residual | | ||
| | Spaghetti brownfield: patterns concurrent, design-weak under green check | Only “governed% + gates installed?” numbers → `/ark-coverage` | | ||
@@ -30,3 +49,3 @@ | Dual-plan **seed** (A remediation + B pattern bets) without applying | One design trade-off between 2–3 options already mapped → `/ark-think` | | ||
| **Q01 single path:** when doctor `postGreenPath` / ENFORCE · design-weak is active, **this skill | ||
| **Post-green single path:** when doctor `postGreenPath` / ENFORCE · design-weak is active, **this skill | ||
| (shape-focus / dual-plan seed) is the map half of the one door** — then `/ark-autopilot` only | ||
@@ -284,3 +303,3 @@ to apply B with user OK. Do not send the user to coverage or think as equal first choices. | ||
| **Q04 pilot loop:** when doctor/plan JSON is available, use **`pilotLoop.nextPilot`** as the | ||
| **One-pilot loop:** when doctor/plan JSON is available, use **`pilotLoop.nextPilot`** as the | ||
| **single** next extraction card (one pilot at a time → re-doctor). Do not open five B bets | ||
@@ -377,2 +396,3 @@ in parallel. When `pilotLoop.queuedBets > 0`, those bets stay **queued**, not concurrent. | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -379,0 +399,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -12,2 +12,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Name residual lenses** on each cluster (SoC, DIP, coupling, …). Still no weaken-gate to clear a lens. | ||
| ## When / not when | ||
@@ -151,3 +170,3 @@ | ||
| ## Mechanical-edit hygiene (Y04 — outcome gate) | ||
| ## Mechanical-edit hygiene (outcome gate) | ||
@@ -159,3 +178,3 @@ - Header injection must **merge into the existing doc comment**; the kept result has one `/**`, not stacked headers. | ||
| ## Reshape findings (X04 — never mechanical) | ||
| ## Reshape findings (physical cohesion — never mechanical) | ||
@@ -184,2 +203,3 @@ If `doctor.physicalCohesion` fires while you fix: do **not** fold reshape moves into your fix | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -186,0 +206,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -15,2 +15,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Lens language on each cluster** while looping edges; residual shape lenses hand off to explore/autopilot. | ||
| ## When / not when | ||
@@ -117,3 +136,3 @@ | ||
| ## Mechanical-edit hygiene (Y04 — outcome gate) | ||
| ## Mechanical-edit hygiene (outcome gate) | ||
@@ -125,3 +144,3 @@ - Header injection must **merge into the existing doc comment**; the kept result has one `/**`, not stacked headers. | ||
| ## Reshape pilots (X04 — physical cohesion, advisory) | ||
| ## Reshape pilots (physical cohesion — physical cohesion, advisory) | ||
@@ -179,2 +198,3 @@ When `ark-check --doctor --json` carries `doctor.physicalCohesion.reshapePilot.nextPilot`, | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -181,0 +201,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -8,2 +8,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **Where so the AI doesn’t mess up next time** — golden pattern + layer home before the write. | ||
| ## When / not when | ||
@@ -159,2 +178,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -161,0 +181,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -18,2 +18,8 @@ --- | ||
| ## Improvement compass note | ||
| This skill is **experimental runtime** only. Do **not** treat runtime adoption as residual on the | ||
| resilience lens unless the user explicitly opts into the experimental kernel. Prefer doctor compass | ||
| for static architecture residual; hand static residual to `/ark-explore` / `/ark-fix`. | ||
| ## Dual engine (mandatory) | ||
@@ -117,2 +123,3 @@ | ||
| - **Result:** one-line outcome | ||
| - **Compass:** `n/a` (runtime skill; static residual → explore/fix) | top residual if doctor was run | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -119,0 +126,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -12,2 +12,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **2–3 options labeled by lens impact** (what residual improves / what stays out-of-scope). | ||
| ## When / not when | ||
@@ -130,2 +149,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…` / CLI / `none` | ||
@@ -132,0 +152,0 @@ - **Incomplete?** `no` | `yes — <what is missing>` |
@@ -16,2 +16,21 @@ --- | ||
| ## Improvement compass (process preflight) | ||
| When doctor is available, read `doctor.improvementCompass` (or the human **Improvement compass** section). | ||
| Name 1–3 **residual** lenses in plain language before skill-shopping. Always `notAScore` — never invent | ||
| 0–10 scores or Excellent/Good ranks. | ||
| **What the user should feel next:** fewer blocked AI writes, clearer folders, safer domain — then jargon. | ||
| **Anti false-done:** empty plan A + residual lenses / design-weak → **Incomplete? yes**. Green edges alone | ||
| are not “architecture finished.” | ||
| **AI-easy architecture:** ports over concrete I/O in domain; one concern per module; golden pattern for | ||
| new files; place before write (`/ark-place` / prepare-write). | ||
| **Out of scope (honest):** scalability/performance, full app-security tooling (SAST), and full resilience | ||
| patterns are **out-of-scope** lenses — say so; do not invent Ark enforcement for them. | ||
| **After upgrade:** refresh projection; re-doctor; compass residual still drives process, not scores. | ||
| ## Dual engine (mandatory) | ||
@@ -215,2 +234,3 @@ | ||
| - **Planes:** one-line split of residual **[Layer]** vs **[ArkRules]** (or `n/a` if unused) | ||
| - **Compass:** top residual lenses | `n/a` | ||
| - **Handoff:** `/ark-…`, CLI action, or `none` | ||
@@ -217,0 +237,0 @@ - **Incomplete?** `no` or `yes — <missing work>` |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
3022396
3.86%192
1.05%44671
2.67%241
1.26%