arkgate 3.7.0 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -1145
- package/README.md +59 -19
- package/bin/ark-check-runtime.mjs +1598 -0
- package/bin/ark-check.mjs +32 -1565
- package/bin/ark-mcp-runtime.mjs +1976 -0
- package/bin/ark-mcp.mjs +84 -1495
- package/bin/ark-shared.mjs +34 -38
- package/bin/ark.mjs +33 -66
- package/bin/lib/adapter-contract.mjs +161 -9
- package/bin/lib/agent-gates.mjs +1 -0
- package/bin/lib/analysis-completeness.mjs +28 -0
- package/bin/lib/analysis-engine.mjs +8 -8
- package/bin/lib/analysis-policy.mjs +27 -0
- package/bin/lib/architecture-scan.mjs +70 -357
- package/bin/lib/auto-patch.mjs +76 -8
- package/bin/lib/ci-and-commands.mjs +1 -1
- package/bin/lib/codex-home.mjs +43 -16
- package/bin/lib/design-delta.mjs +4 -0
- package/bin/lib/doctor-advisories.mjs +4 -3
- package/bin/lib/doctor-plan.mjs +40 -41
- package/bin/lib/enforcement-state.mjs +2 -0
- package/bin/lib/github-enforcement.mjs +443 -0
- package/bin/lib/hook-templates.mjs +12 -148
- package/bin/lib/html-report-advisories.mjs +1 -1
- package/bin/lib/html-report-depth.mjs +9 -0
- package/bin/lib/html-report.mjs +5 -5
- package/bin/lib/install-migrate.mjs +83 -79
- package/bin/lib/managed-upgrade.mjs +622 -0
- package/bin/lib/mcp-adoption.mjs +3 -1
- package/bin/lib/parse-health.mjs +6 -5
- package/bin/lib/port-proof.mjs +2 -2
- package/bin/lib/prepare-change.mjs +68 -38
- package/bin/lib/prepare-write.mjs +7 -1
- package/bin/lib/resident-doctor-client.mjs +55 -0
- package/bin/lib/resident-hook.mjs +247 -0
- package/bin/lib/resolved-candidate-facts.mjs +1160 -0
- package/bin/lib/scan-files.mjs +19 -6
- package/bin/lib/snippet-analysis.mjs +119 -0
- package/bin/lib/source-policy.mjs +24 -0
- package/bin/lib/typescript-host.mjs +15 -18
- package/bin/lib/unavailable-analysis.mjs +76 -0
- package/bin/lib/upgrade-command.mjs +115 -0
- package/bin/lib/weakest-link.mjs +21 -179
- package/bin/lib/write-path-capabilities.mjs +167 -16
- package/bin/lib/write-path-detect.mjs +3 -2
- package/dist/eslint/index.cjs +3 -3
- package/dist/eslint/index.d.ts +3 -0
- package/dist/eslint/index.js +3 -3
- package/dist/index.cjs +7 -7
- package/dist/index.d.ts +1073 -141
- package/dist/index.js +7 -7
- package/docs/agent-guide.md +103 -59
- package/docs/ai-gates.md +97 -16
- package/docs/demos/01-write-gate-self-correction.md +2 -2
- package/docs/enthusiast/README.md +10 -10
- package/docs/enthusiast/how-to-gallery-starter.md +2 -2
- package/docs/enthusiast/reference-commands.md +18 -1
- package/docs/enthusiast/tutorial-first-project.md +2 -2
- package/docs/package-surface.md +98 -12
- package/docs/typescript-support.md +109 -37
- package/package.json +32 -4
- package/schemas/ark.analysis-result.schema.json +159 -2
- package/schemas/ark.design-delta.schema.json +1 -0
- package/schemas/ark.enforcement-state.schema.json +84 -0
- package/schemas/ark.resolved-candidate-facts.schema.json +1 -0
- package/server.json +2 -2
- package/templates/skills/ark-explore.md +5 -5
- package/templates/skills/ark-fix.md +1 -1
- package/templates/skills/ark-runtime.md +15 -8
- package/templates/skills/ark-upgrade.md +122 -182
- package/bin/lib/ai-velocity.mjs +0 -293
- package/bin/lib/graph-cycles.mjs +0 -6
- package/bin/lib/safety-diagnostics.mjs +0 -284
- package/bin/lib/ts-resolve.mjs +0 -228
- package/dist/configTypes-DAPvBqK6.d.cts +0 -61
- package/dist/eslint/index.d.cts +0 -146
- package/dist/index.d.cts +0 -986
|
@@ -1,200 +1,140 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ark-upgrade
|
|
3
|
-
description:
|
|
3
|
+
description: Upgrade ArkGate through a content-identity preview, preserve customized files, and verify the active host and architecture contract.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# /ark-upgrade —
|
|
6
|
+
# /ark-upgrade — managed ArkGate upgrade
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
Upgrade the published `arkgate` package and its managed gates without treating a
|
|
9
|
+
filename, package version, or similar-looking file as proof of ownership. The
|
|
10
|
+
preview is the source of truth: inspect it before applying anything.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
npm uninstall ark-runtime-kernel && npm install -D arkgate
|
|
16
|
-
npx arkgate-check --install-agent-gates --force
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Guide: `docs/migrate-from-ark-runtime-kernel.md` in the package (or on GitHub).
|
|
20
|
-
|
|
21
|
-
**TypeScript 7 projects:** ArkGate falls back to a nested JS-API TypeScript when the
|
|
22
|
-
project's `typescript` main export is version-only (TS 7.0). After upgrade, point users at
|
|
23
|
-
`docs/typescript-support.md` if the gate or `ARK_DEBUG_TS=1` mentions fallback. Dual install
|
|
24
|
-
(TS6 JS API + TS7 CLI) is optional for tooling that still needs classic `tsc` APIs.
|
|
25
|
-
|
|
26
|
-
**MCP double-bin check (identity cutover):** after upgrade, open `.mcp.json` and
|
|
27
|
-
`.cursor/mcp.json`. `args` must contain **exactly one** of `arkgate-mcp` / `ark-mcp`
|
|
28
|
-
(prefer `arkgate-mcp`), never both. If both appear, run:
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
npx arkgate-check --install-agent-gates --migrate-commands
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
`ark upgrade` already runs migrate-commands; re-run it if an older 2.x left dual names.
|
|
35
|
-
|
|
36
|
-
**Adoption completeness:** run `npx arkgate-check --doctor` (or `--doctor --json`) and
|
|
37
|
-
read the **Adoption** section — host gaps, Codex home temp paths, optional-but-populated
|
|
38
|
-
core layers, missing origin snapshot, baseline policy. Fix commands are printed per gap.
|
|
39
|
-
HTML reports include the same Adoption card (separate from the 0–100 fitness score).
|
|
40
|
-
|
|
41
|
-
**Active host vs deferred hosts:** green the **session host** (Grok, Claude, Cursor, …)
|
|
42
|
-
and repo gates first. Codex home (`$CODEX_HOME` prompts + `config.toml` MCP multi-project)
|
|
43
|
-
is **deferred** unless this session is Codex or the user asked to fix Codex. Doctor marks
|
|
44
|
-
those gaps `deferred` / info and does not put them in Top actions. A temp/upgrade MCP
|
|
45
|
-
`--root` stays urgent (fail-closed rewrite). Never set **Incomplete?** because of deferred
|
|
46
|
-
Codex debt.
|
|
12
|
+
For greenfield onboarding, start with `/ark-architect` (or
|
|
13
|
+
`ark-check --recommend`); for a brownfield repository, use `/ark-adopt` before
|
|
14
|
+
this upgrade flow.
|
|
47
15
|
|
|
48
16
|
## Dual engine (mandatory)
|
|
49
17
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
18
|
+
Use the semantic sensor (`ark-check --doctor --json` plus the strict contract
|
|
19
|
+
check) and direct inspection of every managed file the preview will change.
|
|
20
|
+
Neither signal replaces the other.
|
|
21
|
+
|
|
22
|
+
## Safety contract
|
|
23
|
+
|
|
24
|
+
- `ark upgrade` is read-only. It reports the selected profile and hosts, every
|
|
25
|
+
managed asset, its content state, and the exact next command.
|
|
26
|
+
- The first `ark upgrade --apply` updates the dependency and lockfile, then runs
|
|
27
|
+
the newly installed CLI to produce another read-only preview. It does **not**
|
|
28
|
+
apply that preview's gate or skill changes.
|
|
29
|
+
- The post-update/no-install preview's `nextCommand` includes
|
|
30
|
+
`--plan-digest <sha256:…>` and applies only that exact candidate. A changed file
|
|
31
|
+
or selection invalidates the digest instead of being overwritten.
|
|
32
|
+
- Missing or conflicted assets previously recorded as managed require explicit
|
|
33
|
+
`--accept-conflicts`. Stop and obtain user consent before using it.
|
|
34
|
+
- Customized files are preserved. Unrelated source files and similar filenames
|
|
35
|
+
are never adopted. The command never writes a Codex home or another global
|
|
36
|
+
directory implicitly.
|
|
37
|
+
- Do not combine this flow with legacy `--force`, `--migrate-commands`, or
|
|
38
|
+
`--codex-home` repair commands. Diagnose any older adoption debt separately.
|
|
39
|
+
|
|
40
|
+
## Read the states
|
|
41
|
+
|
|
42
|
+
| State | Meaning | Action |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `current` | Content identity matches the candidate. | Record/adopt safely; metadata-only stamps may refresh. |
|
|
45
|
+
| `stale` | Recorded managed content still matches its old identity. | Safe candidate replacement. |
|
|
46
|
+
| `missing` | Candidate is absent. | Create if new; require consent if a recorded asset was deleted. |
|
|
47
|
+
| `customized` | User content diverged without a competing managed base. | Preserve it. |
|
|
48
|
+
| `conflicted` | Both managed base and user content diverged. | Preserve and require explicit consent. |
|
|
49
|
+
| `retired` | A recorded asset is no longer selected by the candidate. | Preserve its file and manifest identity; take no action. |
|
|
50
|
+
|
|
51
|
+
## Procedure
|
|
52
|
+
|
|
53
|
+
1. **Establish versions and context.** Read the installed
|
|
54
|
+
`node_modules/arkgate/package.json`, query `npm view arkgate version`, identify
|
|
55
|
+
the repository package manager, and open the intervening entries in the
|
|
56
|
+
shipped `CHANGELOG.md` (fall back to registry or release notes and name that
|
|
57
|
+
source). Do not infer “latest” from `node_modules` alone.
|
|
58
|
+
|
|
59
|
+
2. **Preview managed content.** Run:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
ark upgrade --json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Pass `--root <path>` and `--tools <active-host>` when selection would otherwise
|
|
66
|
+
be ambiguous. Open the reported files that matter to this repository. Confirm
|
|
67
|
+
that customized files remain non-applying and that any deletion/conflict is
|
|
68
|
+
blocked.
|
|
69
|
+
|
|
70
|
+
3. **Update and re-preview.** If the registry is newer, run:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
ark upgrade --apply
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This updates through the detected package manager and hands control to the new
|
|
77
|
+
package for a fresh preview. Review that new preview; do not assume the old
|
|
78
|
+
candidate and new candidate are identical. If already on the latest package,
|
|
79
|
+
retain the current read-only preview.
|
|
80
|
+
|
|
81
|
+
For pnpm repositories with `minimumReleaseAge`, use the repository's existing
|
|
82
|
+
trusted first-party exception mechanism when the new release is still cooling
|
|
83
|
+
off, and prove `pnpm install --frozen-lockfile` succeeds.
|
|
84
|
+
|
|
85
|
+
4. **Apply only the reviewed candidate.** When there are no blocked assets, run
|
|
86
|
+
the preview's exact `nextCommand`, whose shape is:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
ark upgrade --apply --no-install --plan-digest <preview-digest>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
If recorded deletion/conflict recovery is desired, ask first and then add
|
|
93
|
+
`--accept-conflicts`. Never add it merely to make the run green. Run a second
|
|
94
|
+
preview and require `summary.changed: 0`.
|
|
95
|
+
|
|
96
|
+
5. **Verify enforcement and architecture.** Run `ark-check --doctor --json` and
|
|
97
|
+
the same fail-closed architecture command used by managed apply (normally
|
|
98
|
+
`ark-check --root . --config ark.config.json --strict-merge --json`). Require
|
|
99
|
+
`completeness: "complete"` and `ok: true`. Treat provider-unavailable CI
|
|
100
|
+
required-check evidence as `unverified`, never as proof that merges are
|
|
101
|
+
blocked. If new violations appear, hand off to `/ark-fix` for a small set or
|
|
102
|
+
`/ark-loop` / `/ark-autopilot` for residual debt; do not regenerate a baseline
|
|
103
|
+
without explicit approval.
|
|
104
|
+
|
|
105
|
+
## Active host vs deferred hosts
|
|
106
|
+
|
|
107
|
+
**Active host:** its repo-local gate, skills, MCP/advisory surface, doctor evidence,
|
|
108
|
+
and strict check must be coherent before completion.
|
|
109
|
+
|
|
110
|
+
**Deferred hosts:** inactive hosts may remain untouched and must be named with a
|
|
111
|
+
future repair command when relevant. Deferred hosts never make Incomplete? `yes`
|
|
112
|
+
once the active host and shared repository surfaces are verified. A temporary
|
|
113
|
+
upgrade path or an actively selected host is not deferred.
|
|
114
|
+
|
|
115
|
+
The managed manifest retains the selected host set, so a later preview does not
|
|
116
|
+
silently switch to a different host. Home-level Codex setup is separate and is
|
|
117
|
+
never an implicit side effect of this skill.
|
|
57
118
|
|
|
58
119
|
## Subagent fan-out (optional, host-dependent)
|
|
59
120
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
Parent merges and still emits the **### Completion** contract. Never parallel-write
|
|
63
|
-
the same files or weaken the gate.
|
|
64
|
-
|
|
65
|
-
## Fast path
|
|
66
|
-
|
|
67
|
-
One command does the whole flow — update the package, refresh gates + `/ark-*` skills
|
|
68
|
-
(and best-effort Codex home prompts when `~/.codex` exists), migrate command runners,
|
|
69
|
-
and run the strict check:
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
arkgate upgrade
|
|
73
|
-
# (alias: ark upgrade)
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
Use it when the user just wants the update done. Run the detailed steps below instead when
|
|
77
|
-
you need to inspect the changelog first, handle a pnpm cooling-off window, or the one-liner
|
|
78
|
-
reports a problem to triage. Always refresh skills so agents pick up new `mechanical-safe`
|
|
79
|
-
kinds and TS guidance:
|
|
80
|
-
|
|
81
|
-
```
|
|
82
|
-
npx arkgate-check --install-agent-gates --skills-only --force
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Steps
|
|
86
|
-
|
|
87
|
-
1. **Check the registry, then update.** Compare the installed version
|
|
88
|
-
(`node_modules/arkgate/package.json`) against the latest published:
|
|
89
|
-
`npm view arkgate version`. If a newer version exists, update it —
|
|
90
|
-
`npm install -D arkgate@latest` (or the project's package manager:
|
|
91
|
-
`pnpm add -D` / `yarn add -D`) — so the lockfile moves too; a pinned lockfile
|
|
92
|
-
is exactly why "just re-run install" often stays on the old version. If the
|
|
93
|
-
installed version already equals the latest, say so and still run steps 3-4
|
|
94
|
-
(a prior version may have shipped skills/gates this repo never installed).
|
|
95
|
-
Do NOT report "no update available" from the `node_modules` version alone —
|
|
96
|
-
that reads stale.
|
|
97
|
-
**pnpm cooling-off:** if the repo enforces a pnpm `minimumReleaseAge` and the new
|
|
98
|
-
version was published inside that window (common for a freshly-cut release), a plain
|
|
99
|
-
`pnpm add` in loose mode can leave a lockfile that `pnpm install --frozen-lockfile` (what
|
|
100
|
-
CI runs) then REJECTS. Do it cleanly: add the exact `<pkg>@<version>` to
|
|
101
|
-
`minimumReleaseAgeExclude` in `pnpm-workspace.yaml` FIRST, bump the dependency spec, then
|
|
102
|
-
run a plain `pnpm install`, and verify with `pnpm install --frozen-lockfile` before moving
|
|
103
|
-
on. Only exclude a first-party package you trust.
|
|
104
|
-
2. **Changelog triage** — read `node_modules/arkgate/CHANGELOG.md`
|
|
105
|
-
(shipped in the package) for the versions between old and new, and pick out
|
|
106
|
-
only entries that affect THIS repo (new flags, changed defaults, new gate
|
|
107
|
-
templates, new skills). Summarize each in one sentence with what, if
|
|
108
|
-
anything, the repo must do about it. If the file is absent (older releases
|
|
109
|
-
didn't ship it), fall back to `npm view arkgate@<version> ...` or
|
|
110
|
-
the GitHub release notes — say which source you used.
|
|
111
|
-
3. **Refresh templates** — run `ark-check --install-agent-gates`. Without
|
|
112
|
-
`--force` it only writes missing files (new skills, new tool templates) and
|
|
113
|
-
skips existing ones. To pick up NEW versions of the `/ark-*` skills that a
|
|
114
|
-
package update shipped, run `ark-check --install-agent-gates --skills-only
|
|
115
|
-
--force`: `--skills-only` scopes the overwrite to the canonical skills and
|
|
116
|
-
leaves the gate files alone. Do NOT run a bare `--install-agent-gates --force`
|
|
117
|
-
to refresh skills — it also overwrites `AGENTS.md` (often customized with the
|
|
118
|
-
project's real layer table), `.claude/settings.json` (hooks/permissions), and
|
|
119
|
-
`.github/workflows/ark-check.yml` (CI) with the generic templates, silently
|
|
120
|
-
losing customizations. If the changelog says a GATE file changed, report the
|
|
121
|
-
diff and let the user decide; never rewrite settings/CI/AGENTS.md without
|
|
122
|
-
explicit approval.
|
|
123
|
-
**Active host first.** Refresh skills for the host running this skill (e.g.
|
|
124
|
-
`.grok/skills/`, `.claude/skills/`, `.cursor/commands/`). Repo-local copies for
|
|
125
|
-
other detected hosts are fine to refresh in the same pass when cheap.
|
|
126
|
-
**Codex is deferred when you are not on Codex.** Repo skills live in
|
|
127
|
-
`.agents/skills/<name>/SKILL.md`; optional home skills in
|
|
128
|
-
`$CODEX_HOME/skills/<name>/SKILL.md` (not legacy flat `$CODEX_HOME/prompts`).
|
|
129
|
-
When **on Codex**, refresh **both** repo catalog and home if doctor reports
|
|
130
|
-
missing/stale/legacy-prompts-only parity gaps. `ark upgrade` may best-effort
|
|
131
|
-
refresh home when it exists; still list Codex under **Deferred hosts** when
|
|
132
|
-
not on Codex and do **not** chase MCP multi-project / stale home skills until
|
|
133
|
-
the user is on Codex (or asks). Fix when needed:
|
|
134
|
-
`ark-check --install-agent-gates --skills-only --tools codex --force` and/or
|
|
135
|
-
`ark-check --install-agent-gates --skills-only --codex-home --force`
|
|
136
|
-
(and `--tools codex` / `--force` for primary MCP rebind). Exception: temp or
|
|
137
|
-
`ark-upgrade` MCP `--root` paths — leave fail-closed rewrite to the CLI; do not
|
|
138
|
-
block completion on multi-project noise.
|
|
139
|
-
**Migrate stale command runners.** The package-manager-aware command templates
|
|
140
|
-
(`pnpm exec` / `yarn` / `npx`) only apply to NEWLY written files, so a repo that adopted
|
|
141
|
-
Ark before they shipped keeps a stale `npx` in its EXISTING gate files
|
|
142
|
-
(`.claude/settings.json` hooks, `.mcp.json`, `AGENTS.md`, the `check:architecture` script).
|
|
143
|
-
In a pnpm/yarn repo that means the write gate runs on a command the repo forbids. Run
|
|
144
|
-
`ark-check --install-agent-gates --migrate-commands`: it rewrites ONLY the command runner
|
|
145
|
-
in those files, preserving every customization (no `--force` clobber). A normal `ark-check`
|
|
146
|
-
also flags this when it detects the mismatch.
|
|
147
|
-
4. **Re-verify** — `ark-check --root . --config ark.config.json
|
|
148
|
-
--strict-config` (with `--baseline .ark-baseline.json` if present). A new
|
|
149
|
-
version may detect violations the old one missed: if new violations appear,
|
|
150
|
-
**STOP — do not continue this skill as complete.** **STOP — bulk residual debt: invoke /ark-loop or /ark-autopilot**
|
|
151
|
-
(or `/ark-fix` for a small set). If they are too numerous to fix
|
|
152
|
-
now, freezing them in the baseline (`--update-baseline`) is a valid stopgap
|
|
153
|
-
but it silences NEW violations, so it requires explicit user approval first
|
|
154
|
-
— never regenerate the baseline on your own to get a green check.
|
|
155
|
-
|
|
156
|
-
## Operating rules
|
|
157
|
-
|
|
158
|
-
- **Must green:** the **active session host** (skills + gates that host uses) and
|
|
159
|
-
shared repo surfaces (`.mcp.json` dual-bin, command runners, architecture check).
|
|
160
|
-
- **May defer:** other hosts not used in this session. Always list them under
|
|
161
|
-
**Deferred hosts** with the fix command — do not treat them as Incomplete.
|
|
162
|
-
Codex home (global `$CODEX_HOME`) is the common case on Grok/Claude.
|
|
163
|
-
- **Optional sync:** if other repo-local tool dirs already exist (`.cursor/`,
|
|
164
|
-
`.claude/`, …), refreshing their `/ark-*` skills is good hygiene when cheap;
|
|
165
|
-
it is not a reason to fail the skill when the active host is already current.
|
|
166
|
-
- Never run `--force` blindly; customized files are the user's.
|
|
167
|
-
- Stop only if the changelog documents a breaking config change with two valid
|
|
168
|
-
migration paths — then present both with a recommendation.
|
|
169
|
-
|
|
170
|
-
## Related onboarding
|
|
171
|
-
|
|
172
|
-
- After upgrade, re-run `ark-check --doctor` — `/ark-architect` and `ark-check --recommend` ship
|
|
173
|
-
with the package for **greenfield** shape adoption.
|
|
174
|
-
- **Brownfield** repos: point users to `/ark-adopt` and `docs/brownfield-adoption.md`, not
|
|
175
|
-
`/ark-architect`. Demo: `docs/demos/02-brownfield-baseline-adoption.md`.
|
|
176
|
-
- Refresh gates: `ark-check --install-agent-gates --force --skills-only` if skills are stale.
|
|
177
|
-
|
|
178
|
-
## Verify and report
|
|
179
|
-
|
|
180
|
-
End with a passing check. Report: latest published version, old → new version
|
|
181
|
-
(or "already latest"), changelog entries that mattered here (plain language),
|
|
182
|
-
files written/refreshed for the **active host**, deferred hosts (if any),
|
|
183
|
-
skipped customized files needing a manual look, and the final check status.
|
|
121
|
+
Parallelize independent preview, changelog, and enforcement checks when the
|
|
122
|
+
host supports isolated subagents; otherwise fall back to sequential execution.
|
|
184
123
|
|
|
185
124
|
## Completion contract (skill incomplete if missing)
|
|
186
125
|
|
|
187
|
-
|
|
126
|
+
Skill incomplete if missing any required verification or any field below.
|
|
127
|
+
|
|
128
|
+
End with exactly this structure:
|
|
188
129
|
|
|
189
130
|
### Completion
|
|
190
131
|
- **Sensor:** commands/tools run
|
|
191
|
-
- **Opened:** real
|
|
192
|
-
- **Active host:**
|
|
193
|
-
- **Deferred hosts:** `none`
|
|
194
|
-
- **Result:**
|
|
195
|
-
- **Handoff:** `/ark
|
|
196
|
-
- **Incomplete?** `no`
|
|
197
|
-
|
|
198
|
-
If a
|
|
199
|
-
|
|
200
|
-
**Skill incomplete if missing** any of the bullets above (use `none` for Deferred hosts when empty).
|
|
132
|
+
- **Opened:** real project and changelog paths read
|
|
133
|
+
- **Active host:** host and verified status
|
|
134
|
+
- **Deferred hosts:** `none` or host plus future action
|
|
135
|
+
- **Result:** old → new version and managed-upgrade outcome
|
|
136
|
+
- **Handoff:** `/ark-…`, CLI action, or `none`
|
|
137
|
+
- **Incomplete?** `no` or `yes — <missing work>`
|
|
138
|
+
|
|
139
|
+
If a required verification did not run or a conflict remains blocked, report the
|
|
140
|
+
task incomplete. Deferred hosts (including Codex when inactive) never make Incomplete? yes.
|
package/bin/lib/ai-velocity.mjs
DELETED
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Q05 — AI-velocity evidence (fixture-measured, no live LLM).
|
|
3
|
-
*
|
|
4
|
-
* Same fixed feature scenario on two arms:
|
|
5
|
-
* - design-weak: no golden norm → confused multi-path placement attempts
|
|
6
|
-
* - golden-path: `.ark/golden-pattern.json` newCodeHome → first attempt correct home
|
|
7
|
-
*
|
|
8
|
-
* Metric: **placementTurns** (agent-equivalent steps until a DomainModel landing).
|
|
9
|
-
* Golden must be strictly better (fewer turns). Gate is never weakened.
|
|
10
|
-
*/
|
|
11
|
-
import fs from 'node:fs';
|
|
12
|
-
import path from 'node:path';
|
|
13
|
-
import { layerForFile } from '../ark-shared.mjs';
|
|
14
|
-
import { loadGoldenPattern, summarizeGoldenPattern } from './golden-pattern.mjs';
|
|
15
|
-
import {
|
|
16
|
-
detectDesignSmells,
|
|
17
|
-
buildPatternBetsFromSmells,
|
|
18
|
-
summarizeDesignFitness,
|
|
19
|
-
assertPatternBetsNeverMechanicalSafe,
|
|
20
|
-
} from './design-smells.mjs';
|
|
21
|
-
import { collectGovernedFiles } from './scan-files.mjs';
|
|
22
|
-
|
|
23
|
-
/** Fixed feature prompt + pure-domain snippet (same on both arms). */
|
|
24
|
-
export const FEATURE_SCENARIO = {
|
|
25
|
-
id: 'add-pure-domain-canRefund',
|
|
26
|
-
prompt:
|
|
27
|
-
'Add a pure domain rule canRefund(status: string): boolean for order refund eligibility. No I/O, no ORM.',
|
|
28
|
-
fileName: 'canRefund.ts',
|
|
29
|
-
source:
|
|
30
|
-
"export function canRefund(status: string): boolean {\n return status === 'paid';\n}\n",
|
|
31
|
-
/** Correct layer for this pure rule under the design-weak-enforce contract. */
|
|
32
|
-
correctLayer: 'DomainModel',
|
|
33
|
-
correctPath: 'src/domain/canRefund.ts',
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Agent-equivalent placement order when no golden guides new code (spaghetti confusion).
|
|
38
|
-
* Wrong homes first (presentation / mixed), then domain — measured as friction.
|
|
39
|
-
*/
|
|
40
|
-
export const DESIGN_WEAK_PLACEMENT_CANDIDATES = [
|
|
41
|
-
'src/features/orders/ui/canRefund.ts',
|
|
42
|
-
'src/routes/canRefund.ts',
|
|
43
|
-
'src/services/canRefund.ts',
|
|
44
|
-
FEATURE_SCENARIO.correctPath,
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @param {string} root
|
|
49
|
-
* @param {object} config
|
|
50
|
-
* @param {string} filePath relative
|
|
51
|
-
*/
|
|
52
|
-
export function layerForPlacement(root, config, filePath) {
|
|
53
|
-
const layers = config?.layers || [];
|
|
54
|
-
if (!layers.length) return null;
|
|
55
|
-
return layerForFile(root, filePath, layers) || null;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* A landing is successful when the path is under the correct layer for the scenario.
|
|
60
|
-
* Pure snippet has no imports — we do not invent gate denials; cost is placement friction.
|
|
61
|
-
*
|
|
62
|
-
* @param {string} root
|
|
63
|
-
* @param {object} config
|
|
64
|
-
* @param {string} filePath
|
|
65
|
-
*/
|
|
66
|
-
export function isCorrectLanding(root, config, filePath) {
|
|
67
|
-
const layer = layerForPlacement(root, config, filePath);
|
|
68
|
-
return layer === FEATURE_SCENARIO.correctLayer;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Build ordered placement attempts for an arm.
|
|
73
|
-
* Golden with newCodeHome → single first attempt under that home.
|
|
74
|
-
* Absent golden → design-weak candidate ladder.
|
|
75
|
-
*
|
|
76
|
-
* Accepts loadGoldenPattern result or summarizeGoldenPattern summary.
|
|
77
|
-
* @param {object | null | undefined} golden
|
|
78
|
-
*/
|
|
79
|
-
export function placementAttemptsForArm(golden) {
|
|
80
|
-
if (!golden || typeof golden !== 'object') {
|
|
81
|
-
return { guidedByGolden: false, attempts: [...DESIGN_WEAK_PLACEMENT_CANDIDATES] };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const present = golden.present === true;
|
|
85
|
-
const newCodeHome =
|
|
86
|
-
(typeof golden.newCodeHome === 'string' && golden.newCodeHome) ||
|
|
87
|
-
(typeof golden.golden?.newCodeHome === 'string' && golden.golden.newCodeHome) ||
|
|
88
|
-
null;
|
|
89
|
-
|
|
90
|
-
if (present && typeof newCodeHome === 'string' && newCodeHome.trim()) {
|
|
91
|
-
const home = newCodeHome.replace(/\\/g, '/').replace(/\/?$/, '/');
|
|
92
|
-
const rel = `${home}${FEATURE_SCENARIO.fileName}`.replace(/\/{2,}/g, '/');
|
|
93
|
-
return {
|
|
94
|
-
guidedByGolden: true,
|
|
95
|
-
attempts: [rel.startsWith('src/') || rel.startsWith('.') ? rel : rel.replace(/^\//, '')],
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Golden absent or no newCodeHome → full confused ladder (honest multi-layout friction).
|
|
100
|
-
return {
|
|
101
|
-
guidedByGolden: false,
|
|
102
|
-
attempts: [...DESIGN_WEAK_PLACEMENT_CANDIDATES],
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Measure placement turns for one arm (real layer resolution + golden load).
|
|
108
|
-
*
|
|
109
|
-
* @param {{
|
|
110
|
-
* root: string,
|
|
111
|
-
* config: object,
|
|
112
|
-
* armId: string,
|
|
113
|
-
* files?: string[],
|
|
114
|
-
* }} opts
|
|
115
|
-
*/
|
|
116
|
-
export function measureArmVelocity(opts) {
|
|
117
|
-
const { root, config, armId } = opts;
|
|
118
|
-
const goldenLoad = loadGoldenPattern(root);
|
|
119
|
-
const goldenSummary = summarizeGoldenPattern(goldenLoad);
|
|
120
|
-
const { guidedByGolden, attempts } = placementAttemptsForArm(goldenLoad);
|
|
121
|
-
|
|
122
|
-
const steps = [];
|
|
123
|
-
let placementTurns = 0;
|
|
124
|
-
let landedPath = null;
|
|
125
|
-
let landedLayer = null;
|
|
126
|
-
|
|
127
|
-
for (const candidate of attempts) {
|
|
128
|
-
placementTurns += 1;
|
|
129
|
-
const layer = layerForPlacement(root, config, candidate);
|
|
130
|
-
const ok = isCorrectLanding(root, config, candidate);
|
|
131
|
-
steps.push({
|
|
132
|
-
turn: placementTurns,
|
|
133
|
-
path: candidate,
|
|
134
|
-
layer,
|
|
135
|
-
correctLanding: ok,
|
|
136
|
-
});
|
|
137
|
-
if (ok) {
|
|
138
|
-
landedPath = candidate;
|
|
139
|
-
landedLayer = layer;
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Real design residual sensors (honesty — not used to invent ENFORCE).
|
|
145
|
-
const files = opts.files ?? collectGovernedFiles(root, config);
|
|
146
|
-
const smells = detectDesignSmells(root, config, files, {
|
|
147
|
-
layersWithoutRules: [],
|
|
148
|
-
emptyLayers: [],
|
|
149
|
-
layers: [],
|
|
150
|
-
});
|
|
151
|
-
const patternBets = buildPatternBetsFromSmells(smells);
|
|
152
|
-
const designFitness = summarizeDesignFitness(smells, {
|
|
153
|
-
activeViolations: 0,
|
|
154
|
-
governedPercent: 100,
|
|
155
|
-
totalFiles: files.length,
|
|
156
|
-
});
|
|
157
|
-
const betsHonesty = assertPatternBetsNeverMechanicalSafe(patternBets);
|
|
158
|
-
|
|
159
|
-
return {
|
|
160
|
-
armId,
|
|
161
|
-
scenarioId: FEATURE_SCENARIO.id,
|
|
162
|
-
prompt: FEATURE_SCENARIO.prompt,
|
|
163
|
-
guidedByGolden,
|
|
164
|
-
goldenPattern: goldenSummary,
|
|
165
|
-
placementTurns: landedPath ? placementTurns : attempts.length + 1,
|
|
166
|
-
landed: Boolean(landedPath),
|
|
167
|
-
landedPath,
|
|
168
|
-
landedLayer,
|
|
169
|
-
steps,
|
|
170
|
-
designFitness: {
|
|
171
|
-
designWeak: designFitness.designWeak,
|
|
172
|
-
smellCount: designFitness.smellCount,
|
|
173
|
-
ids: designFitness.ids,
|
|
174
|
-
},
|
|
175
|
-
patternBetCount: patternBets.length,
|
|
176
|
-
patternBetsNeverMechanicalSafe: betsHonesty.ok,
|
|
177
|
-
metric: 'placementTurns',
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Compare two arms: golden must be strictly better on placementTurns.
|
|
183
|
-
*
|
|
184
|
-
* @param {ReturnType<typeof measureArmVelocity>} designWeakArm
|
|
185
|
-
* @param {ReturnType<typeof measureArmVelocity>} goldenArm
|
|
186
|
-
*/
|
|
187
|
-
export function compareVelocityArms(designWeakArm, goldenArm) {
|
|
188
|
-
const dw = designWeakArm.placementTurns;
|
|
189
|
-
const gp = goldenArm.placementTurns;
|
|
190
|
-
const goldenBetter = gp < dw;
|
|
191
|
-
const delta = dw - gp;
|
|
192
|
-
return {
|
|
193
|
-
metric: 'placementTurns',
|
|
194
|
-
designWeakTurns: dw,
|
|
195
|
-
goldenPathTurns: gp,
|
|
196
|
-
goldenStrictlyBetter: goldenBetter,
|
|
197
|
-
deltaTurns: delta,
|
|
198
|
-
relativeReduction: dw > 0 ? delta / dw : null,
|
|
199
|
-
method:
|
|
200
|
-
'Agent-equivalent placement attempts until DomainModel home for fixed pure-rule feature ' +
|
|
201
|
-
`(${FEATURE_SCENARIO.id}). Design-weak arm walks concurrent-layout candidates; ` +
|
|
202
|
-
'golden-path arm uses .ark/golden-pattern.json newCodeHome as first attempt. ' +
|
|
203
|
-
'No live LLM; gate not weakened; design-weak residual may remain on both arms.',
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Run full Q05 report object from two prepared roots (same config shape expected).
|
|
209
|
-
*
|
|
210
|
-
* @param {{
|
|
211
|
-
* designWeakRoot: string,
|
|
212
|
-
* goldenPathRoot: string,
|
|
213
|
-
* config: object,
|
|
214
|
-
* }} opts
|
|
215
|
-
*/
|
|
216
|
-
export function runAiVelocityComparison(opts) {
|
|
217
|
-
const designWeakArm = measureArmVelocity({
|
|
218
|
-
root: opts.designWeakRoot,
|
|
219
|
-
config: opts.config,
|
|
220
|
-
armId: 'design-weak',
|
|
221
|
-
});
|
|
222
|
-
const goldenArm = measureArmVelocity({
|
|
223
|
-
root: opts.goldenPathRoot,
|
|
224
|
-
config: opts.config,
|
|
225
|
-
armId: 'golden-path',
|
|
226
|
-
});
|
|
227
|
-
const comparison = compareVelocityArms(designWeakArm, goldenArm);
|
|
228
|
-
|
|
229
|
-
return {
|
|
230
|
-
schemaVersion: '1',
|
|
231
|
-
id: 'q05-ai-velocity',
|
|
232
|
-
mode: 'fixture-measured',
|
|
233
|
-
scenario: {
|
|
234
|
-
id: FEATURE_SCENARIO.id,
|
|
235
|
-
prompt: FEATURE_SCENARIO.prompt,
|
|
236
|
-
fileName: FEATURE_SCENARIO.fileName,
|
|
237
|
-
correctLayer: FEATURE_SCENARIO.correctLayer,
|
|
238
|
-
correctPath: FEATURE_SCENARIO.correctPath,
|
|
239
|
-
sourceBytes: Buffer.byteLength(FEATURE_SCENARIO.source, 'utf8'),
|
|
240
|
-
},
|
|
241
|
-
arms: {
|
|
242
|
-
'design-weak': designWeakArm,
|
|
243
|
-
'golden-path': goldenArm,
|
|
244
|
-
},
|
|
245
|
-
comparison,
|
|
246
|
-
honesty: {
|
|
247
|
-
designWeakArmStillDesignWeak: designWeakArm.designFitness.designWeak === true,
|
|
248
|
-
goldenDoesNotRequireClearingDesignWeak: true,
|
|
249
|
-
patternBetsNeverMechanicalSafe:
|
|
250
|
-
designWeakArm.patternBetsNeverMechanicalSafe &&
|
|
251
|
-
goldenArm.patternBetsNeverMechanicalSafe,
|
|
252
|
-
gateNotWeakened: true,
|
|
253
|
-
liveLlmRequired: false,
|
|
254
|
-
},
|
|
255
|
-
ok: comparison.goldenStrictlyBetter === true,
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Materialize golden-path arm: copy design-weak tree + write golden pattern.
|
|
261
|
-
* Pure helper for harness / tests (caller owns temp lifecycle).
|
|
262
|
-
*
|
|
263
|
-
* @param {string} designWeakRoot
|
|
264
|
-
* @param {string} destRoot
|
|
265
|
-
* @param {{ name?: string, norm?: string, newCodeHome?: string }} [golden]
|
|
266
|
-
*/
|
|
267
|
-
export function materializeGoldenPathArm(designWeakRoot, destRoot, golden = {}) {
|
|
268
|
-
copyTree(designWeakRoot, destRoot);
|
|
269
|
-
const arkDir = path.join(destRoot, '.ark');
|
|
270
|
-
fs.mkdirSync(arkDir, { recursive: true });
|
|
271
|
-
const body = {
|
|
272
|
-
schemaVersion: '1',
|
|
273
|
-
name: golden.name || 'domain-first pure rules',
|
|
274
|
-
norm:
|
|
275
|
-
golden.norm ||
|
|
276
|
-
'New pure business rules live under src/domain/; adapters and routes never own can*/policy helpers.',
|
|
277
|
-
newCodeHome: golden.newCodeHome || 'src/domain/',
|
|
278
|
-
examplePath: golden.examplePath || 'src/domain/canRefund.ts',
|
|
279
|
-
};
|
|
280
|
-
fs.writeFileSync(path.join(arkDir, 'golden-pattern.json'), JSON.stringify(body, null, 2) + '\n');
|
|
281
|
-
return body;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
function copyTree(src, dst) {
|
|
285
|
-
fs.mkdirSync(dst, { recursive: true });
|
|
286
|
-
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
287
|
-
if (entry.name === 'node_modules' || entry.name === '.git') continue;
|
|
288
|
-
const s = path.join(src, entry.name);
|
|
289
|
-
const d = path.join(dst, entry.name);
|
|
290
|
-
if (entry.isDirectory()) copyTree(s, d);
|
|
291
|
-
else fs.copyFileSync(s, d);
|
|
292
|
-
}
|
|
293
|
-
}
|
package/bin/lib/graph-cycles.mjs
DELETED