create-agent-rig 0.9.1 → 0.10.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 +419 -3
- package/README.md +267 -305
- package/package.json +8 -14
- package/packages/cli/dist/commands/create.js +56 -88
- package/packages/cli/dist/commands/doctor.js +213 -0
- package/packages/cli/dist/commands/init.js +111 -50
- package/packages/cli/dist/commands/integrations.js +468 -0
- package/packages/cli/dist/commands/setup-wizard.js +61 -0
- package/packages/cli/dist/commands/uninstall.js +1223 -0
- package/packages/cli/dist/commands/upgrade.js +472 -90
- package/packages/cli/dist/index.js +651 -46
- package/packages/cli/dist/integrations/declaration.js +158 -0
- package/packages/cli/dist/integrations/doctor-guards.js +126 -0
- package/packages/cli/dist/integrations/doctor-workflow.js +25 -0
- package/packages/cli/dist/integrations/mcp-json.js +107 -0
- package/packages/cli/dist/integrations/memory-doctor.js +124 -0
- package/packages/cli/dist/integrations/registry.js +22 -0
- package/packages/cli/dist/integrations/spawn.js +228 -0
- package/packages/cli/dist/integrations/spec-kit.js +280 -0
- package/packages/cli/dist/integrations/verify.js +193 -0
- package/packages/cli/dist/integrations/windows-job.js +275 -0
- package/packages/cli/dist/lib/elevated-paths.js +74 -0
- package/packages/cli/dist/lib/install-set.js +1 -44
- package/packages/cli/dist/lib/manifest.js +64 -5
- package/packages/cli/dist/lib/prompts.js +0 -23
- package/packages/cli/dist/lib/safe-path.js +193 -2
- package/packages/cli/dist/lib/safe-text.js +78 -0
- package/packages/cli/dist/lib/substitute.js +1 -52
- package/packages/cli/dist/lib/summary.js +5 -5
- package/packages/cli/dist/templates.js +4 -14
- package/scripts/prepare.mjs +28 -12
- package/templates/agent-os/subagent-routing.json +4 -4
- package/templates/agent-os/universal/.agents/skills/check-premises/SKILL.md +13 -9
- package/templates/agent-os/universal/.agents/skills/loop/SKILL.md +31 -6
- package/templates/agent-os/universal/.agents/skills/new-invariant/SKILL.md +5 -5
- package/templates/agent-os/universal/.agents/skills/pr-ship/SKILL.md +1 -1
- package/templates/agent-os/universal/.agents/skills/worktree-task/SKILL.md +3 -3
- package/templates/agent-os/universal/.claude/agents/code-reviewer.md +8 -6
- package/templates/agent-os/universal/.claude/agents/implementation-agent.md +41 -0
- package/templates/agent-os/universal/.claude/agents/prose-reviewer.md +8 -4
- package/templates/agent-os/universal/.claude/agents/security-scanner.md +4 -2
- package/templates/agent-os/universal/.claude/agents/test-writer.md +2 -2
- package/templates/agent-os/universal/.claude/hooks/inject-rules.mjs +83 -4
- package/templates/agent-os/universal/.claude/rules/autonomy.md +55 -27
- package/templates/agent-os/universal/.claude/rules/invariants.md +9 -8
- package/templates/agent-os/universal/.claude/rules/workflow.md +47 -22
- package/templates/agent-os/universal/.claude/scripts/decision-router.mjs +1 -1
- package/templates/agent-os/universal/.claude/scripts/detect-missed-gate.mjs +12 -9
- package/templates/agent-os/universal/.claude/scripts/doctor.mjs +100 -2
- package/templates/agent-os/universal/.claude/scripts/lib/claim-records.mjs +236 -6
- package/templates/agent-os/universal/.claude/scripts/queue/state.mjs +2 -2
- package/templates/agent-os/universal/.claude/scripts/reconcile-external-prs.mjs +4 -3
- package/templates/agent-os/universal/.claude/scripts/revalidate.mjs +16 -0
- package/templates/agent-os/universal/.claude/settings.json +0 -8
- package/templates/agent-os/universal/.claude/skills/check-premises/SKILL.md +13 -9
- package/templates/agent-os/universal/.claude/skills/loop/SKILL.md +31 -6
- package/templates/agent-os/universal/.claude/skills/new-invariant/SKILL.md +5 -5
- package/templates/agent-os/universal/.claude/skills/pr-ship/SKILL.md +1 -1
- package/templates/agent-os/universal/.claude/skills/worktree-task/SKILL.md +3 -3
- package/templates/agent-os/universal/.codex/agents/code-reviewer.toml +2 -2
- package/templates/agent-os/universal/.codex/agents/implementation-agent.toml +6 -0
- package/templates/agent-os/universal/.codex/agents/prose-reviewer.toml +2 -2
- package/templates/agent-os/universal/.codex/agents/security-scanner.toml +1 -1
- package/templates/agent-os/universal/.codex/agents/test-writer.toml +1 -1
- package/templates/agent-os/universal/.codex/hooks.json +0 -10
- package/templates/agent-os/universal/AGENTS.md +208 -107
- package/templates/agent-os/universal/CLAUDE.md +15 -162
- package/templates/agent-os/universal/PLAN.md +17 -10
- package/templates/agent-os/universal/docs/decisions/agents-md-canonical.md +313 -0
- package/templates/agent-os/universal/docs/decisions/codex-adapter.md +15 -10
- package/templates/agent-os/universal/docs/decisions/review-lanes.md +12 -8
- package/templates/agent-os/universal/docs/decisions/session-start-wire-format.md +206 -0
- package/templates/agent-os/universal/docs/decisions/subagent-routing.md +6 -3
- package/templates/agent-os/universal/docs/decisions/workflow-layer-split.md +235 -0
- package/templates/agent-os/universal/layers.json +25 -30
- package/templates/hash-history.json +8 -4
- package/templates/release-ledger.json +2 -1
- package/packages/cli/dist/lib/composition.js +0 -20
- package/packages/cli/dist/lib/targets.js +0 -28
- package/packages/cli/dist/policy/benchmark/corpus.js +0 -165
- package/packages/cli/dist/policy/core/adapter.js +0 -18
- package/packages/cli/dist/policy/core/coverage.js +0 -253
- package/packages/cli/dist/policy/core/decision-record.js +0 -287
- package/packages/cli/dist/policy/core/declaration.js +0 -127
- package/packages/cli/dist/policy/core/evidence-matrix.js +0 -94
- package/packages/cli/dist/policy/core/probe.js +0 -442
- package/packages/cli/dist/policy/core/registry.js +0 -115
- package/packages/cli/dist/policy/core/validation.js +0 -275
- package/packages/cli/dist/policy/core/vocabulary.js +0 -123
- package/packages/cli/dist/policy/harness/claude.js +0 -47
- package/packages/cli/dist/policy/harness/codex.js +0 -87
- package/packages/cli/dist/policy/harness/index.js +0 -15
- package/packages/cli/dist/policy/harness/shared-hooks.js +0 -28
- package/packages/cli/dist/policy/index.js +0 -17
- package/templates/agent-os/init/AGENTS.md +0 -201
- package/templates/agent-os/init/CLAUDE.md +0 -201
- package/templates/agent-os/stack/aws-cdk/.agents/skills/post-deploy-verify/SKILL.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.agents/skills/ro-debug/SKILL.md +0 -117
- package/templates/agent-os/stack/aws-cdk/.claude/agents/cdk-diff-reviewer.md +0 -89
- package/templates/agent-os/stack/aws-cdk/.claude/rules/aws-cdk.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.claude/skills/post-deploy-verify/SKILL.md +0 -105
- package/templates/agent-os/stack/aws-cdk/.claude/skills/ro-debug/SKILL.md +0 -117
- package/templates/agent-os/stack/aws-cdk/.codex/agents/cdk-diff-reviewer.toml +0 -6
- package/templates/agent-os/stack/node-ts/.claude/hooks/dod-checks.json +0 -1
- package/templates/agent-os/stack/node-ts/.claude/rules/node-ts.md +0 -85
- package/templates/agent-os/universal/.claude/hooks/guard-core-purity.mjs +0 -89
- package/templates/agent-os/universal/.claude/hooks/guard-web-boundary.mjs +0 -68
- package/templates/agent-os/universal/.claude/rules/architecture.md +0 -81
- package/templates/skeleton/aws-serverless/.github/workflows/ci.yml +0 -28
- package/templates/skeleton/aws-serverless/.github/workflows/deploy.yml +0 -90
- package/templates/skeleton/aws-serverless/README.md +0 -181
- package/templates/skeleton/aws-serverless/apps/web/next.config.mjs +0 -17
- package/templates/skeleton/aws-serverless/apps/web/package.json +0 -19
- package/templates/skeleton/aws-serverless/apps/web/src/app/layout.tsx +0 -17
- package/templates/skeleton/aws-serverless/apps/web/src/app/page.tsx +0 -96
- package/templates/skeleton/aws-serverless/apps/web/src/lib/api.ts +0 -36
- package/templates/skeleton/aws-serverless/apps/web/src/lib/validate.ts +0 -23
- package/templates/skeleton/aws-serverless/apps/web/test/shared-validation.test.ts +0 -38
- package/templates/skeleton/aws-serverless/apps/web/tsconfig.json +0 -14
- package/templates/skeleton/aws-serverless/eslint.config.mjs +0 -20
- package/templates/skeleton/aws-serverless/gitignore +0 -56
- package/templates/skeleton/aws-serverless/infra/bin/app.ts +0 -79
- package/templates/skeleton/aws-serverless/infra/cdk.json +0 -3
- package/templates/skeleton/aws-serverless/infra/lib/app-stack.ts +0 -248
- package/templates/skeleton/aws-serverless/infra/lib/web-stack.ts +0 -45
- package/templates/skeleton/aws-serverless/infra/package.json +0 -18
- package/templates/skeleton/aws-serverless/infra/test/allowed-origins.test.ts +0 -301
- package/templates/skeleton/aws-serverless/infra/test/app-composition.test.ts +0 -137
- package/templates/skeleton/aws-serverless/infra/test/app-stack.test.ts +0 -120
- package/templates/skeleton/aws-serverless/infra/test/web-stack.test.ts +0 -44
- package/templates/skeleton/aws-serverless/package.json +0 -30
- package/templates/skeleton/aws-serverless/packages/core/package.json +0 -11
- package/templates/skeleton/aws-serverless/packages/core/src/events.ts +0 -14
- package/templates/skeleton/aws-serverless/packages/core/src/index.ts +0 -15
- package/templates/skeleton/aws-serverless/packages/core/src/note.ts +0 -69
- package/templates/skeleton/aws-serverless/packages/core/test/events.test.ts +0 -23
- package/templates/skeleton/aws-serverless/packages/core/test/note.test.ts +0 -101
- package/templates/skeleton/aws-serverless/packages/db/package.json +0 -14
- package/templates/skeleton/aws-serverless/packages/db/src/client.ts +0 -17
- package/templates/skeleton/aws-serverless/packages/db/src/index.ts +0 -2
- package/templates/skeleton/aws-serverless/packages/db/src/note-model.ts +0 -52
- package/templates/skeleton/aws-serverless/packages/db/test/note-model.test.ts +0 -91
- package/templates/skeleton/aws-serverless/packages/shared/package.json +0 -11
- package/templates/skeleton/aws-serverless/packages/shared/src/env.ts +0 -17
- package/templates/skeleton/aws-serverless/packages/shared/src/errors.ts +0 -33
- package/templates/skeleton/aws-serverless/packages/shared/src/index.ts +0 -3
- package/templates/skeleton/aws-serverless/packages/shared/src/logger.ts +0 -20
- package/templates/skeleton/aws-serverless/packages/shared/test/env.test.ts +0 -26
- package/templates/skeleton/aws-serverless/packages/shared/test/errors.test.ts +0 -28
- package/templates/skeleton/aws-serverless/packages/shared/test/logger.test.ts +0 -19
- package/templates/skeleton/aws-serverless/pnpm-lock.yaml +0 -2855
- package/templates/skeleton/aws-serverless/pnpm-workspace.yaml +0 -14
- package/templates/skeleton/aws-serverless/services/api/package.json +0 -15
- package/templates/skeleton/aws-serverless/services/api/src/adapters/sqs-publisher.ts +0 -26
- package/templates/skeleton/aws-serverless/services/api/src/handlers/create-note.ts +0 -69
- package/templates/skeleton/aws-serverless/services/api/src/handlers/list-notes.ts +0 -37
- package/templates/skeleton/aws-serverless/services/api/src/list-main.ts +0 -12
- package/templates/skeleton/aws-serverless/services/api/src/main.ts +0 -21
- package/templates/skeleton/aws-serverless/services/api/src/usecases/create-note.ts +0 -41
- package/templates/skeleton/aws-serverless/services/api/src/usecases/list-notes.ts +0 -14
- package/templates/skeleton/aws-serverless/services/api/test/create-note.handler.test.ts +0 -211
- package/templates/skeleton/aws-serverless/services/api/test/create-note.usecase.test.ts +0 -45
- package/templates/skeleton/aws-serverless/services/api/test/list-notes.test.ts +0 -122
- package/templates/skeleton/aws-serverless/services/api/test/sqs-publisher.test.ts +0 -22
- package/templates/skeleton/aws-serverless/services/worker/package.json +0 -12
- package/templates/skeleton/aws-serverless/services/worker/src/handlers/note-created.ts +0 -15
- package/templates/skeleton/aws-serverless/services/worker/src/main.ts +0 -7
- package/templates/skeleton/aws-serverless/services/worker/src/usecases/process-note-created.ts +0 -37
- package/templates/skeleton/aws-serverless/services/worker/test/note-created.test.ts +0 -61
- package/templates/skeleton/aws-serverless/tsconfig.base.json +0 -15
- package/templates/skeleton/aws-serverless/tsconfig.json +0 -16
- package/templates/skeleton/aws-serverless/vitest.config.ts +0 -14
- package/templates/skeleton/node-service/.github/workflows/ci.yml +0 -27
- package/templates/skeleton/node-service/.github/workflows/deploy.yml +0 -29
- package/templates/skeleton/node-service/README.md +0 -104
- package/templates/skeleton/node-service/apps/web/next.config.mjs +0 -17
- package/templates/skeleton/node-service/apps/web/package.json +0 -19
- package/templates/skeleton/node-service/apps/web/src/app/layout.tsx +0 -17
- package/templates/skeleton/node-service/apps/web/src/app/page.tsx +0 -96
- package/templates/skeleton/node-service/apps/web/src/lib/api.ts +0 -29
- package/templates/skeleton/node-service/apps/web/src/lib/validate.ts +0 -23
- package/templates/skeleton/node-service/apps/web/test/shared-validation.test.ts +0 -38
- package/templates/skeleton/node-service/apps/web/tsconfig.json +0 -14
- package/templates/skeleton/node-service/eslint.config.mjs +0 -20
- package/templates/skeleton/node-service/gitignore +0 -54
- package/templates/skeleton/node-service/package.json +0 -30
- package/templates/skeleton/node-service/packages/core/package.json +0 -11
- package/templates/skeleton/node-service/packages/core/src/events.ts +0 -14
- package/templates/skeleton/node-service/packages/core/src/index.ts +0 -15
- package/templates/skeleton/node-service/packages/core/src/note.ts +0 -69
- package/templates/skeleton/node-service/packages/core/test/events.test.ts +0 -23
- package/templates/skeleton/node-service/packages/core/test/note.test.ts +0 -101
- package/templates/skeleton/node-service/packages/db/package.json +0 -12
- package/templates/skeleton/node-service/packages/db/src/index.ts +0 -1
- package/templates/skeleton/node-service/packages/db/src/note-store.ts +0 -100
- package/templates/skeleton/node-service/packages/db/test/note-store.test.ts +0 -100
- package/templates/skeleton/node-service/packages/shared/package.json +0 -11
- package/templates/skeleton/node-service/packages/shared/src/env.ts +0 -17
- package/templates/skeleton/node-service/packages/shared/src/errors.ts +0 -33
- package/templates/skeleton/node-service/packages/shared/src/index.ts +0 -3
- package/templates/skeleton/node-service/packages/shared/src/logger.ts +0 -20
- package/templates/skeleton/node-service/packages/shared/test/env.test.ts +0 -26
- package/templates/skeleton/node-service/packages/shared/test/errors.test.ts +0 -28
- package/templates/skeleton/node-service/packages/shared/test/logger.test.ts +0 -19
- package/templates/skeleton/node-service/pnpm-lock.yaml +0 -2402
- package/templates/skeleton/node-service/pnpm-workspace.yaml +0 -13
- package/templates/skeleton/node-service/scripts/build-artifact.mjs +0 -34
- package/templates/skeleton/node-service/services/api/package.json +0 -17
- package/templates/skeleton/node-service/services/api/src/adapters/spool-publisher.ts +0 -23
- package/templates/skeleton/node-service/services/api/src/handlers/create-note.ts +0 -40
- package/templates/skeleton/node-service/services/api/src/handlers/list-notes.ts +0 -23
- package/templates/skeleton/node-service/services/api/src/main.ts +0 -40
- package/templates/skeleton/node-service/services/api/src/server.ts +0 -172
- package/templates/skeleton/node-service/services/api/src/static-dir.ts +0 -20
- package/templates/skeleton/node-service/services/api/src/usecases/create-note.ts +0 -30
- package/templates/skeleton/node-service/services/api/src/usecases/list-notes.ts +0 -14
- package/templates/skeleton/node-service/services/api/test/artifact.test.ts +0 -92
- package/templates/skeleton/node-service/services/api/test/create-note.handler.test.ts +0 -64
- package/templates/skeleton/node-service/services/api/test/create-note.usecase.test.ts +0 -43
- package/templates/skeleton/node-service/services/api/test/list-notes.test.ts +0 -48
- package/templates/skeleton/node-service/services/api/test/package-manager.test.ts +0 -40
- package/templates/skeleton/node-service/services/api/test/package-manager.ts +0 -51
- package/templates/skeleton/node-service/services/api/test/server.test.ts +0 -208
- package/templates/skeleton/node-service/services/api/test/spool-publisher.test.ts +0 -32
- package/templates/skeleton/node-service/services/api/test/static-dir.test.ts +0 -29
- package/templates/skeleton/node-service/services/worker/package.json +0 -16
- package/templates/skeleton/node-service/services/worker/src/main.ts +0 -28
- package/templates/skeleton/node-service/services/worker/src/spool.ts +0 -60
- package/templates/skeleton/node-service/services/worker/src/usecases/process-note-created.ts +0 -38
- package/templates/skeleton/node-service/services/worker/test/process-note-created.test.ts +0 -34
- package/templates/skeleton/node-service/services/worker/test/spool.test.ts +0 -76
- package/templates/skeleton/node-service/tsconfig.base.json +0 -15
- package/templates/skeleton/node-service/tsconfig.json +0 -13
- package/templates/skeleton/node-service/vitest.config.ts +0 -12
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Why the workflow layer is opt-in, and where the line falls
|
|
2
|
+
|
|
3
|
+
The rule lives in `CLAUDE.md`, under "The opt-in workflow layer (experimental)".
|
|
4
|
+
This file explains why `layers.json` (RP-180) draws the line where it does,
|
|
5
|
+
and why a few files that look like PR-lifecycle automation stayed in Lean Core
|
|
6
|
+
instead of moving with the rest of it.
|
|
7
|
+
|
|
8
|
+
## What moved, and why
|
|
9
|
+
|
|
10
|
+
Before this split, `templates/agent-os/universal/layers.json` had one array,
|
|
11
|
+
and `init`/`create` installed all of it unconditionally — including the queue
|
|
12
|
+
adapter, the `loop` and `pr-ship` skills, run-state, the run journal,
|
|
13
|
+
revalidation, claim-records and the PR-lifecycle helpers named below. None of
|
|
14
|
+
that is required by Lean Core: a thin CRUD service or a solo-maintained
|
|
15
|
+
library gets the same review gates and stop rules with none of the
|
|
16
|
+
autonomous, cooperative machinery, and shipping it anyway made every fresh
|
|
17
|
+
rig carry queue-selection semantics it never asked for.
|
|
18
|
+
|
|
19
|
+
The workflow layer is what a project opts into with `init --layer workflow`:
|
|
20
|
+
the queue adapter (`.claude/scripts/queue/`, `.claude/queue.json`), the
|
|
21
|
+
`loop` and `pr-ship` skills, `run-state.mjs`, the run journal
|
|
22
|
+
(`run-journal.mjs` — see the one exception below —, `journal/README.md`),
|
|
23
|
+
revalidation and claim-records, and the PR-lifecycle helpers
|
|
24
|
+
`decision-router.mjs`, `detect-missed-gate.mjs` and
|
|
25
|
+
`reconcile-external-prs.mjs`.
|
|
26
|
+
|
|
27
|
+
## The exception: why `verdict.mjs`, `lib/verdict.mjs`, `lib/gate-coverage.mjs`
|
|
28
|
+
## and `run-journal.mjs` stayed in Lean Core
|
|
29
|
+
|
|
30
|
+
These four read as PR-lifecycle automation — the ticket's own wording groups
|
|
31
|
+
"PR-lifecycle helpers" with the workflow layer — and the first draft of this
|
|
32
|
+
split moved them too. It does not survive contact with what Lean Core
|
|
33
|
+
actually installs, for one mechanical reason: `check-premises` is a Lean Core
|
|
34
|
+
skill (a session runs it standalone, with no queue and no loop, "before the
|
|
35
|
+
Red step" and again "before the gate"), and its own second entry point tells
|
|
36
|
+
the reader to run `node .claude/scripts/verdict.mjs check <report>
|
|
37
|
+
check-premises` on its own output. `.claude/scripts/verdict.mjs` is a single
|
|
38
|
+
module with **static, top-level imports** of `./lib/gate-coverage.mjs` and
|
|
39
|
+
`./run-journal.mjs` — Node resolves the whole file before any subcommand
|
|
40
|
+
runs, so a core-only install that shipped `verdict.mjs` without those two
|
|
41
|
+
would break `check-premises`'s own documented command on the very first
|
|
42
|
+
`check` subcommand, not only on `coverage`.
|
|
43
|
+
|
|
44
|
+
The three reviewer agent specs (`code-reviewer.md`, `security-scanner.md`,
|
|
45
|
+
`prose-reviewer.md`) are Lean Core for the same reason `check-premises` is —
|
|
46
|
+
review applies to any PR, loop-driven or not — and all three cite
|
|
47
|
+
`.claude/scripts/verdict.mjs` as the shape their own report is checked
|
|
48
|
+
against.
|
|
49
|
+
|
|
50
|
+
So the dependency runs from Lean Core outward: `check-premises` (core) needs
|
|
51
|
+
`verdict.mjs` (core) to load at all, `verdict.mjs`'s own module graph needs
|
|
52
|
+
`lib/gate-coverage.mjs` and `run-journal.mjs`, and neither of those two
|
|
53
|
+
imports anything outside itself (`node:fs`, `node:path`, and in
|
|
54
|
+
`gate-coverage.mjs`'s case nothing at all — the mention of
|
|
55
|
+
`decision-router.mjs` in its header is a comment, not an import). Moving the
|
|
56
|
+
leaves and leaving the root behind was the option that did not exist;
|
|
57
|
+
`invariants.md`'s "a file a core guard imports must stay core" generalises
|
|
58
|
+
past hooks to this case on the same reasoning.
|
|
59
|
+
|
|
60
|
+
`decision-router.mjs` itself has no such pull: `lib/gate-coverage.mjs`
|
|
61
|
+
mentions it only in a comment, and the one real static import of it
|
|
62
|
+
(`.claude/hooks/lib/edit-input.mjs`) is also a comment, not code. It moved
|
|
63
|
+
with the rest of the workflow layer, and `workflow.md`'s "PR flow" section
|
|
64
|
+
states the Lean Core fallback when it is not installed: every change still
|
|
65
|
+
reaches `code-reviewer`, and a human or the session decides which additional
|
|
66
|
+
reviewers apply, by the same triggers `decision-router` would have read.
|
|
67
|
+
|
|
68
|
+
`docs/decisions/gate-coverage.md` stayed with `pr-ship` (workflow) rather
|
|
69
|
+
than `lib/gate-coverage.mjs` (core) for a different reason: nothing in Lean
|
|
70
|
+
Core cites the record, only `pr-ship`'s own skill file does. The module and
|
|
71
|
+
the rationale for *why it exists* travel separately on purpose — the module
|
|
72
|
+
is a dependency of a core skill's documented command, the essay about why a
|
|
73
|
+
hook version of the same check was rejected is not.
|
|
74
|
+
|
|
75
|
+
## The freeze this split does not touch
|
|
76
|
+
|
|
77
|
+
RP-53 holds revalidation and claim-records' *behavior* frozen through the
|
|
78
|
+
RP-26 gate (2026-10-27): no feature expansion, no experiment restart, no bias
|
|
79
|
+
introduced by this or any other 0.10 change. This split moves their
|
|
80
|
+
*install-time layer* only — which `layers.json` array they sit in — and
|
|
81
|
+
changes not one line of `revalidate.mjs`, `revalidation-report.mjs`,
|
|
82
|
+
`lib/revalidation-evidence.mjs`, `lib/revalidation-points.mjs` or
|
|
83
|
+
`lib/claim-records.mjs` beyond that relocation. After the gate: GO retains
|
|
84
|
+
them in the optional workflow layer as they are today; NO-GO removes them in
|
|
85
|
+
a bounded follow-up. Missing evidence is not a NO-GO.
|
|
86
|
+
|
|
87
|
+
## What the manifest records, and the direction that matters
|
|
88
|
+
|
|
89
|
+
`RigManifest.layers` records which layer(s) a rig installed, and `upgrade`
|
|
90
|
+
refreshes only what it names. The one detail worth restating here because
|
|
91
|
+
getting it backwards is silent and destructive: a manifest written **before**
|
|
92
|
+
this field existed recorded nothing about layers because there was only one
|
|
93
|
+
payload to record — so `parseManifest` reads that absence as `['process',
|
|
94
|
+
'workflow']`, never as `['process']`. A fresh `init` with no
|
|
95
|
+
`--layer workflow` flag writes `['process']` explicitly. The two defaults
|
|
96
|
+
point in opposite directions on purpose, and swapping them would make the
|
|
97
|
+
very next `upgrade` on an existing dogfood repository report every workflow
|
|
98
|
+
file it already has as `retired` and stop managing it.
|
|
99
|
+
|
|
100
|
+
## Interaction with `uninstall` (RP-181, merged after this split was written)
|
|
101
|
+
|
|
102
|
+
`uninstall` needs no separate awareness of `layers` at all, and gains none:
|
|
103
|
+
it walks `manifest.files` and `manifest.kept` directly (`commands/uninstall.ts`),
|
|
104
|
+
and both of those already name exactly the paths a given install wrote or
|
|
105
|
+
found, regardless of which `layers.json` array a path happens to live in. Three
|
|
106
|
+
cases, all covered by the same unmodified byte-hash check:
|
|
107
|
+
|
|
108
|
+
- **A Core-only rig** (no `--layer workflow`) never has a workflow-layer path in
|
|
109
|
+
`manifest.files` in the first place — `initManifest` only reads the layers
|
|
110
|
+
`effectiveLayers` resolved — so `uninstall` has nothing workflow-shaped to
|
|
111
|
+
remove and reports nothing about it.
|
|
112
|
+
- **A rig that opted into the workflow layer** has those paths in
|
|
113
|
+
`manifest.files` exactly like any process-layer path, and `uninstall` removes
|
|
114
|
+
or preserves them by the same pristine-bytes check as everything else it
|
|
115
|
+
owns.
|
|
116
|
+
- **An inherited pre-0.10 rig** (a manifest with no `layers` key at all) had its
|
|
117
|
+
workflow files recorded in `files` the only way any release before this one
|
|
118
|
+
ever wrote a manifest — there was no `kept`/`files` split by layer to begin
|
|
119
|
+
with — so `uninstall` already treats them as owned, the same as it always
|
|
120
|
+
has. Nothing here widens what `uninstall` is willing to remove, and nothing
|
|
121
|
+
narrows it: a manifest either names a path in `files`/`kept` with the right
|
|
122
|
+
hash, or `uninstall` leaves it alone, and that rule does not read `layers`.
|
|
123
|
+
|
|
124
|
+
Pinned in `packages/cli/test/uninstall.test.ts` (absent in a generated rig —
|
|
125
|
+
this is the generator's own test suite, not a payload path) › "removes an
|
|
126
|
+
installed workflow-layer file exactly like any Core file, when the rig opted
|
|
127
|
+
in", › "a workflow-layer file never installed here (Core-only rig) is simply
|
|
128
|
+
absent from the manifest, never reported \"not a path this release installs\"",
|
|
129
|
+
and › "an inherited pre-layers manifest (no `layers` key) still owns its
|
|
130
|
+
workflow files, exactly like any other installed path".
|
|
131
|
+
|
|
132
|
+
## There is no opt-out short of `uninstall`
|
|
133
|
+
|
|
134
|
+
Once a rig has the workflow layer — `init --layer workflow`, or inherited
|
|
135
|
+
from before RP-180 — nothing in `init` or `upgrade` ever drops a layer a
|
|
136
|
+
READABLE manifest already recorded; `effectiveLayers` (`init.ts`) is
|
|
137
|
+
additive by construction, full stop. `detectLayersOnDisk` (`upgrade.ts`) is
|
|
138
|
+
a narrower claim: it only ever runs when there is NO readable manifest at
|
|
139
|
+
all, and even then it does not treat "a layer's files exist" as license to
|
|
140
|
+
keep them regardless of how many — it is additive in the same direction
|
|
141
|
+
(never narrows what a READABLE manifest said), but on the bootstrapped path
|
|
142
|
+
it decides per layer by quorum (`LAYER_ADOPTION_QUORUM`, more than half of
|
|
143
|
+
the layer's own files present), and can legitimately decide a layer is NOT
|
|
144
|
+
this rig's: a Core-only rig with one or a few stray files that happen to
|
|
145
|
+
share a workflow-layer path is left at Core, its stray files untouched and
|
|
146
|
+
unrecorded (round 4, blocker A — round 3's fix asked only "does at least one
|
|
147
|
+
file exist", which re-adopted the whole layer from a single stray path).
|
|
148
|
+
The only supported way back to Core-only for a rig the manifest genuinely
|
|
149
|
+
still names as having the workflow layer is `uninstall` (removing the
|
|
150
|
+
workflow files this rig owns) followed by a fresh `init` with no `--layer`
|
|
151
|
+
flag — see "The exact opt-out procedure, measured" below for what that
|
|
152
|
+
takes when `uninstall` had to preserve something.
|
|
153
|
+
|
|
154
|
+
**Hand-editing `layers` in `.claude/.rig-manifest.json` down to `["process"]`
|
|
155
|
+
is not that opt-out, and it does not do what it looks like it does.** The
|
|
156
|
+
files themselves are untouched by the edit itself — nothing deletes them —
|
|
157
|
+
but the next `upgrade` reads the manifest's `layers` as authoritative
|
|
158
|
+
(`upgrade.ts`'s `initInstallSet(repoDir, project, layers)`), so every
|
|
159
|
+
workflow path drops out of that plan's own install set and is reported
|
|
160
|
+
`retired`, reason `"no longer shipped by this release — the rig no longer
|
|
161
|
+
manages it; it is now yours"` — the same verdict RP-177 gave a deleted stack
|
|
162
|
+
overlay, applied here to files that are simply no longer read as this rig's
|
|
163
|
+
layer. `applyUpgrade` then writes a manifest whose `files` map has no entry
|
|
164
|
+
for any of the roughly three dozen workflow paths at all — measured, on a
|
|
165
|
+
clean `--layer workflow` install, at exactly 89 file entries down to 56
|
|
166
|
+
(`packages/cli/test/upgrade.test.ts`, absent in a generated rig, pins "a
|
|
167
|
+
clean workflow-layer install hand-edited down to a core-only layers array
|
|
168
|
+
goes from 89 manifest entries to 56"; the figure moved by one from an
|
|
169
|
+
earlier 86/53 when RP-186 added `docs/decisions/agents-md-canonical.md` to
|
|
170
|
+
the process layer, and by two more when `implementation-agent` joined it).
|
|
171
|
+
The files stay on disk, silently un-hashed and unowned —
|
|
172
|
+
and a LATER `uninstall`, reading the same manifest, has nothing there to
|
|
173
|
+
recognise them by: they read as an ordinary foreign/untracked path, not as
|
|
174
|
+
something this release ever installed, and are left alone. The manifest
|
|
175
|
+
itself does not warn about this because it has no opinion on why `layers`
|
|
176
|
+
changed; the tool trusts its own evidence file. This is measured behaviour,
|
|
177
|
+
not a guess: `packages/cli/test/upgrade.test.ts` (absent in a generated rig)
|
|
178
|
+
pins the `retired` verdict and the orphaning it causes in "hand-editing
|
|
179
|
+
`layers` down to `["process"]` on a rig that already has the workflow
|
|
180
|
+
layer retires every workflow file — on disk, unowned, never deleted".
|
|
181
|
+
|
|
182
|
+
**The mirror hand-edit — `layers: ["workflow"]` alone, dropping `process` —
|
|
183
|
+
does the identical thing in the other direction, on a still-readable
|
|
184
|
+
manifest.** `initInstallSet` reads exactly the array it is given; a `layers`
|
|
185
|
+
that never names `process` un-owns every Core file the same way dropping
|
|
186
|
+
`workflow` un-owns every workflow file: the next `upgrade` retires them from
|
|
187
|
+
the plan and drops them from `files`, silently, files untouched on disk.
|
|
188
|
+
(This is not the bootstrapped path's own normalisation — `detectLayersOnDisk`
|
|
189
|
+
always forces `process` into a layer set it INFERS from disk; a READABLE
|
|
190
|
+
manifest is trusted as written, `process` included, and nothing here
|
|
191
|
+
prevents an operator from writing one that omits it.)
|
|
192
|
+
|
|
193
|
+
## The exact opt-out procedure, measured (RP-180 round 4, blocker B)
|
|
194
|
+
|
|
195
|
+
`uninstall --yes` followed by a fresh `init` (no `--layer` flag) reaches
|
|
196
|
+
Core-only in exactly ONE of the two cases that matter, and round 3 stated it
|
|
197
|
+
as though it always worked. Measured on the built CLI, both ways:
|
|
198
|
+
|
|
199
|
+
- **Nothing on the rig was ever edited.** `uninstall --yes` removes every
|
|
200
|
+
file it owns — Core and workflow alike — and, because nothing was left to
|
|
201
|
+
preserve, deletes the manifest too. A fresh `init` then finds no manifest
|
|
202
|
+
and no workflow files: Core-only, as documented. A fresh `init` then
|
|
203
|
+
installs Core only.
|
|
204
|
+
- **Anything was edited — one file is enough.** `uninstall --yes` preserves
|
|
205
|
+
that one file (and reports it) and, because something was preserved,
|
|
206
|
+
**keeps the manifest** — still recording `layers: ["process","
|
|
207
|
+
workflow"]`. The next plain `init` reads that surviving manifest
|
|
208
|
+
(`effectiveLayers` in `init.ts`: `previous?.layers.includes('workflow')`)
|
|
209
|
+
and reinstalls the entire workflow layer right back. `uninstall --yes` leaves
|
|
210
|
+
the one preserved file plus the manifest, and a plain `init` afterward
|
|
211
|
+
brings the whole workflow layer back, `layers` still both. The
|
|
212
|
+
"fresh `init`" instruction alone does NOT reach Core-only here — round 3
|
|
213
|
+
said it did.
|
|
214
|
+
|
|
215
|
+
**The procedure that actually reaches Core-only when something was
|
|
216
|
+
preserved: pass `--detach`.** `uninstall --yes --detach` performs the
|
|
217
|
+
identical safe removal and then deletes the manifest regardless of what is
|
|
218
|
+
left behind, handing the preserved file(s) over to the operator outright
|
|
219
|
+
(they stay on disk, no longer named by anything). The next plain `init`
|
|
220
|
+
then finds no manifest at all and installs Core only. A fresh `init` then installs
|
|
221
|
+
Core, leaves the preserved file untouched, and records `layers: ["process"]`. No new flag
|
|
222
|
+
was added for this — `--detach` already existed (RP-181) for the identical
|
|
223
|
+
reason: a manifest kept alive only by something it has no business
|
|
224
|
+
prescribing further action over.
|
|
225
|
+
|
|
226
|
+
Equivalently, without `--detach`: remove the file(s) `uninstall --yes`
|
|
227
|
+
reported as preserved, then remove `.claude/.rig-manifest.json` by hand,
|
|
228
|
+
then run a plain `init`. Both procedures were measured to reach the same
|
|
229
|
+
end state; `--detach` is the one to recommend because it is one command
|
|
230
|
+
instead of a report a human has to read and act on by hand.
|
|
231
|
+
|
|
232
|
+
Pinned end-to-end on the built CLI in `test/e2e/uninstall.test.ts` (absent in
|
|
233
|
+
a generated rig) › `describe('the opt-out procedure to Core-only, measured
|
|
234
|
+
(RP-180 round 4, blocker B)')`: both cases end in `layers: ["process"]` and
|
|
235
|
+
no un-preserved workflow file left on disk.
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
".claude/skills/new-invariant/guard-invariant.example.mjs",
|
|
8
8
|
".claude/skills/new-invariant/guard-invariant.example.test.mjs",
|
|
9
9
|
".claude/agents/test-writer.md",
|
|
10
|
+
".claude/agents/implementation-agent.md",
|
|
10
11
|
".claude/agents/code-reviewer.md",
|
|
11
12
|
".claude/agents/security-scanner.md",
|
|
12
13
|
".claude/agents/prose-reviewer.md",
|
|
@@ -20,41 +21,52 @@
|
|
|
20
21
|
".claude/hooks/warn-subagent-routing.mjs",
|
|
21
22
|
".claude/hooks/lib/edit-input.mjs",
|
|
22
23
|
".claude/hooks/lib/hook-input.mjs",
|
|
23
|
-
".claude/skills/pr-ship/SKILL.md",
|
|
24
|
-
".claude/skills/loop/SKILL.md",
|
|
25
24
|
".claude/skills/check-premises/SKILL.md",
|
|
26
25
|
".claude/skills/worktree-task/SKILL.md",
|
|
27
26
|
".agents/skills/new-invariant/SKILL.md",
|
|
28
27
|
".agents/skills/new-invariant/guard-invariant.example.mjs",
|
|
29
28
|
".agents/skills/new-invariant/guard-invariant.example.test.mjs",
|
|
30
|
-
".agents/skills/pr-ship/SKILL.md",
|
|
31
|
-
".agents/skills/loop/SKILL.md",
|
|
32
29
|
".agents/skills/check-premises/SKILL.md",
|
|
33
30
|
".agents/skills/worktree-task/SKILL.md",
|
|
34
31
|
".codex/agents/test-writer.toml",
|
|
32
|
+
".codex/agents/implementation-agent.toml",
|
|
35
33
|
".codex/agents/code-reviewer.toml",
|
|
36
34
|
".codex/agents/security-scanner.toml",
|
|
37
35
|
".codex/agents/prose-reviewer.toml",
|
|
38
|
-
".claude/scripts/detect-missed-gate.mjs",
|
|
39
|
-
".claude/scripts/decision-router.mjs",
|
|
40
|
-
".claude/scripts/reconcile-external-prs.mjs",
|
|
41
36
|
".claude/scripts/stop-flag.mjs",
|
|
42
37
|
".claude/scripts/unattended-flag.mjs",
|
|
43
38
|
".claude/scripts/git-env.mjs",
|
|
44
|
-
".claude/scripts/preflight.mjs",
|
|
45
39
|
".claude/scripts/doctor.mjs",
|
|
46
40
|
".claude/scripts/run-journal.mjs",
|
|
47
|
-
".claude/scripts/run-state.mjs",
|
|
48
41
|
".claude/scripts/verdict.mjs",
|
|
42
|
+
".claude/scripts/lib/gate-coverage.mjs",
|
|
43
|
+
".claude/scripts/lib/verdict.mjs",
|
|
44
|
+
".claude/scripts/lib/secrets.mjs",
|
|
45
|
+
".claude/scripts/lib/shell-tools.mjs",
|
|
46
|
+
"PLAN.md",
|
|
47
|
+
"docs/decisions/fail-open-guards.md",
|
|
48
|
+
"docs/decisions/codex-adapter.md",
|
|
49
|
+
"docs/decisions/subagent-routing.md",
|
|
50
|
+
"docs/decisions/review-lanes.md",
|
|
51
|
+
"docs/decisions/workflow-layer-split.md",
|
|
52
|
+
"docs/decisions/session-start-wire-format.md",
|
|
53
|
+
"docs/decisions/agents-md-canonical.md"
|
|
54
|
+
],
|
|
55
|
+
"workflow": [
|
|
56
|
+
".claude/skills/pr-ship/SKILL.md",
|
|
57
|
+
".claude/skills/loop/SKILL.md",
|
|
58
|
+
".agents/skills/pr-ship/SKILL.md",
|
|
59
|
+
".agents/skills/loop/SKILL.md",
|
|
60
|
+
".claude/scripts/detect-missed-gate.mjs",
|
|
61
|
+
".claude/scripts/decision-router.mjs",
|
|
62
|
+
".claude/scripts/reconcile-external-prs.mjs",
|
|
63
|
+
".claude/scripts/preflight.mjs",
|
|
64
|
+
".claude/scripts/run-state.mjs",
|
|
49
65
|
".claude/scripts/revalidate.mjs",
|
|
50
66
|
".claude/scripts/revalidation-report.mjs",
|
|
51
|
-
".claude/scripts/lib/gate-coverage.mjs",
|
|
52
67
|
".claude/scripts/lib/claim-records.mjs",
|
|
53
68
|
".claude/scripts/lib/revalidation-evidence.mjs",
|
|
54
69
|
".claude/scripts/lib/revalidation-points.mjs",
|
|
55
|
-
".claude/scripts/lib/verdict.mjs",
|
|
56
|
-
".claude/scripts/lib/secrets.mjs",
|
|
57
|
-
".claude/scripts/lib/shell-tools.mjs",
|
|
58
70
|
".claude/scripts/queue/core.mjs",
|
|
59
71
|
".claude/scripts/queue/plan-md.mjs",
|
|
60
72
|
".claude/scripts/queue/github-issues.mjs",
|
|
@@ -66,30 +78,13 @@
|
|
|
66
78
|
".claude/scripts/queue/gate-rounds.mjs",
|
|
67
79
|
".claude/queue.json",
|
|
68
80
|
".rig/revalidation.json",
|
|
69
|
-
"PLAN.md",
|
|
70
81
|
"journal/README.md",
|
|
71
82
|
"docs/decisions/gate-coverage.md",
|
|
72
|
-
"docs/decisions/fail-open-guards.md",
|
|
73
|
-
"docs/decisions/codex-adapter.md",
|
|
74
|
-
"docs/decisions/subagent-routing.md",
|
|
75
83
|
"docs/decisions/closing-a-task.md",
|
|
76
84
|
"docs/decisions/content-blind-revalidation.md",
|
|
77
|
-
"docs/decisions/review-lanes.md",
|
|
78
85
|
"docs/decisions/run-directory.md",
|
|
79
86
|
"docs/decisions/spacing-rations-mechanisms.md",
|
|
80
87
|
"docs/decisions/stop-conditions-in-a-file.md",
|
|
81
88
|
"docs/decisions/two-empty-endings.md"
|
|
82
|
-
],
|
|
83
|
-
"architecture": [
|
|
84
|
-
".claude/rules/architecture.md",
|
|
85
|
-
".claude/hooks/guard-core-purity.mjs",
|
|
86
|
-
".claude/hooks/guard-web-boundary.mjs"
|
|
87
|
-
],
|
|
88
|
-
"meta": [
|
|
89
|
-
".claude/settings.json",
|
|
90
|
-
".codex/config.toml",
|
|
91
|
-
".codex/hooks.json",
|
|
92
|
-
"CLAUDE.md",
|
|
93
|
-
"AGENTS.md"
|
|
94
89
|
]
|
|
95
90
|
}
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"0.7.0",
|
|
13
13
|
"0.7.1",
|
|
14
14
|
"0.8.0",
|
|
15
|
-
"0.9.0"
|
|
15
|
+
"0.9.0",
|
|
16
|
+
"0.9.1"
|
|
16
17
|
],
|
|
17
18
|
"files": {
|
|
18
19
|
".agents/skills/check-premises/SKILL.md": {
|
|
@@ -397,7 +398,8 @@
|
|
|
397
398
|
"d8a5916bae71efcc6a21978af713112c9ec33a7554fd07f5978bdf2c3633b560",
|
|
398
399
|
"1804c2351a4f3042dc6a3fb4203f96e98ae12bec32569b99bda77d002d6ba5f2",
|
|
399
400
|
"b81ae3181e02b9c1c3f0e954688490ab3db3961381c2dc397c47c651c9d07f88",
|
|
400
|
-
"c9902da15d06de3e952352115db0288433520eae2caac1f70ee6e06753d1f444"
|
|
401
|
+
"c9902da15d06de3e952352115db0288433520eae2caac1f70ee6e06753d1f444",
|
|
402
|
+
"e31f9899d6edad127db7a2f43dafdfff2671c5c780209cccd3107e56b09c6042"
|
|
401
403
|
]
|
|
402
404
|
},
|
|
403
405
|
".claude/scripts/queue/gate-rounds.mjs": {
|
|
@@ -437,7 +439,8 @@
|
|
|
437
439
|
"b8be5855809c0d44ece94858456098663296c17c5ad9abb1ea2cf1a8f48ca491",
|
|
438
440
|
"3fc8ff9a06a2e22355a660a31e2943a97f50869f7e5726f768a7931d17b64b5b",
|
|
439
441
|
"f44203af187e855b9f738f8dbedfd313abf9d6a5cc29182fb46cd58d70698d7a",
|
|
440
|
-
"c2f2af8ac5eadd8d35a15bcdeffe585e32c6f99b4e6ab9ace0f9d7fd9d694943"
|
|
442
|
+
"c2f2af8ac5eadd8d35a15bcdeffe585e32c6f99b4e6ab9ace0f9d7fd9d694943",
|
|
443
|
+
"add45ea2bf2f96fbda0399afc1903bab75c251001f4d05fcbaa0b5958c8c1702"
|
|
441
444
|
]
|
|
442
445
|
},
|
|
443
446
|
".claude/scripts/queue/plan-md.mjs": {
|
|
@@ -459,7 +462,8 @@
|
|
|
459
462
|
".claude/scripts/reconcile-external-prs.mjs": {
|
|
460
463
|
"since": "0.3.0",
|
|
461
464
|
"hashes": [
|
|
462
|
-
"a326acd64ea19a50d093c91e711ad0234eb05c76d00066db5657c22f4355c190"
|
|
465
|
+
"a326acd64ea19a50d093c91e711ad0234eb05c76d00066db5657c22f4355c190",
|
|
466
|
+
"1b14ee0302932a40611011a57410d7f45d6c2d54799847b94f01f448de7c1827"
|
|
463
467
|
]
|
|
464
468
|
},
|
|
465
469
|
".claude/scripts/revalidate.mjs": {
|
|
@@ -12,5 +12,6 @@
|
|
|
12
12
|
"0.7.0": "6589db36e1daa63a99ec595191db1cccf7373196",
|
|
13
13
|
"0.7.1": "52e879b6c103f6ba70493007b6a6466c57ea9824",
|
|
14
14
|
"0.8.0": "870f9a3ecae2881908ece8ec3e2ac13f84f505f5",
|
|
15
|
-
"0.9.0": "c27f391e7395accaf09354f255a07e1b9e4710c1"
|
|
15
|
+
"0.9.0": "c27f391e7395accaf09354f255a07e1b9e4710c1",
|
|
16
|
+
"0.9.1": "872f7f67f11761c17aad3cbbe26540862581795b"
|
|
16
17
|
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Layer-composition policy (PLAN phase 9): layers must claim disjoint paths.
|
|
3
|
-
* A collision is refused, never resolved silently by copy order. Intended
|
|
4
|
-
* overwrites — if one ever becomes necessary — are declared here, visibly,
|
|
5
|
-
* not implied by ordering.
|
|
6
|
-
*/
|
|
7
|
-
export const ALLOWED_OVERWRITES = new Set([]);
|
|
8
|
-
export function detectCollisions(layers, allowed) {
|
|
9
|
-
const claims = new Map();
|
|
10
|
-
for (const layer of layers) {
|
|
11
|
-
for (const file of layer.files) {
|
|
12
|
-
const owners = claims.get(file) ?? [];
|
|
13
|
-
owners.push(layer.name);
|
|
14
|
-
claims.set(file, owners);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return [...claims]
|
|
18
|
-
.filter(([file, owners]) => owners.length > 1 && !allowed.has(file))
|
|
19
|
-
.map(([file, owners]) => ({ path: file, layers: owners }));
|
|
20
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export const TARGETS = {
|
|
2
|
-
'aws-serverless': {
|
|
3
|
-
skeletonDir: 'aws-serverless',
|
|
4
|
-
stacks: ['node-ts', 'aws-cdk'],
|
|
5
|
-
defaultRegion: 'eu-central-1',
|
|
6
|
-
},
|
|
7
|
-
'node-service': {
|
|
8
|
-
skeletonDir: 'node-service',
|
|
9
|
-
stacks: ['node-ts'],
|
|
10
|
-
},
|
|
11
|
-
};
|
|
12
|
-
export const TARGET_NAMES = Object.keys(TARGETS);
|
|
13
|
-
/**
|
|
14
|
-
* The pre-selected entry in the interactive menu, and the API-level default.
|
|
15
|
-
*
|
|
16
|
-
* 🔴 **Not the fallback for a non-interactive run.** A run with no TTY and no
|
|
17
|
-
* `--target` is *refused* (`index.ts`) — never prompt into a pipe, and never
|
|
18
|
-
* guess a whole project shape for a script that did not say. This constant is
|
|
19
|
-
* what `Enter`, an out-of-range number or an unrecognised name resolve to at the
|
|
20
|
-
* prompt (`prompts.ts`), plus what `createProject` uses when called as a library
|
|
21
|
-
* with no target.
|
|
22
|
-
*
|
|
23
|
-
* The comment this replaces said "one implicit target", which was stale from
|
|
24
|
-
* when there was one. Its first correction claimed the CLI defaults silently in
|
|
25
|
-
* CI — the opposite of what it does, in the file a maintainer would open to
|
|
26
|
-
* check exactly that.
|
|
27
|
-
*/
|
|
28
|
-
export const DEFAULT_TARGET = 'aws-serverless';
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { CAPABILITY_STATES } from '../core/vocabulary.js';
|
|
2
|
-
export const BENCHMARK_CLASSIFICATIONS = Object.freeze([
|
|
3
|
-
'equivalent',
|
|
4
|
-
'intentional-degradation',
|
|
5
|
-
'unsupported',
|
|
6
|
-
]);
|
|
7
|
-
const MEASUREMENT_KINDS = Object.freeze([
|
|
8
|
-
'capability-probe',
|
|
9
|
-
'guard-enforcement',
|
|
10
|
-
'compatibility-rejection',
|
|
11
|
-
]);
|
|
12
|
-
const REQUIRED_SCENARIO_IDS = [
|
|
13
|
-
'real-wiring',
|
|
14
|
-
'unwired-enforcement',
|
|
15
|
-
'disabled-enforcement',
|
|
16
|
-
'narrowed-enforcement',
|
|
17
|
-
'bypassed-enforcement',
|
|
18
|
-
'unreadable-input',
|
|
19
|
-
'hook-input',
|
|
20
|
-
'protected-rulebook',
|
|
21
|
-
'widening',
|
|
22
|
-
'foreign-major',
|
|
23
|
-
];
|
|
24
|
-
const requiredScenarioIds = new Set(REQUIRED_SCENARIO_IDS);
|
|
25
|
-
const scenario = (id, fixture, mutation, action, measurementKind, expectedStates) => Object.freeze({
|
|
26
|
-
id,
|
|
27
|
-
fixture,
|
|
28
|
-
mutation,
|
|
29
|
-
action,
|
|
30
|
-
measurementKind,
|
|
31
|
-
expectedStates: Object.freeze([...expectedStates]),
|
|
32
|
-
});
|
|
33
|
-
export const BENCHMARK_CORPUS = Object.freeze({
|
|
34
|
-
contractMajor: 1,
|
|
35
|
-
scenarios: Object.freeze([
|
|
36
|
-
scenario('real-wiring', 'universal-rig', 'none', 'exercise protected write', 'capability-probe', ['SUPPORTED']),
|
|
37
|
-
scenario('unwired-enforcement', 'universal-rig', 'remove hook registration', 'exercise protected write', 'capability-probe', ['UNSUPPORTED']),
|
|
38
|
-
scenario('disabled-enforcement', 'universal-rig', 'disable all hooks', 'exercise protected write', 'capability-probe', ['UNSUPPORTED']),
|
|
39
|
-
scenario('narrowed-enforcement', 'universal-rig', 'narrow matcher', 'exercise omitted protected write', 'capability-probe', ['DEGRADED']),
|
|
40
|
-
scenario('bypassed-enforcement', 'universal-rig', 'bypass guard command', 'exercise protected write', 'capability-probe', ['INTEGRATION-FAILED']),
|
|
41
|
-
scenario('unreadable-input', 'universal-rig', 'make snapshot unreadable', 'exercise protected write', 'capability-probe', ['INTEGRATION-FAILED']),
|
|
42
|
-
scenario('hook-input', 'universal-rig', 'make tool_input unreadable', 'exercise protected write', 'guard-enforcement', ['SUPPORTED']),
|
|
43
|
-
scenario('protected-rulebook', 'universal-rig', 'none', 'edit protected rulebook', 'guard-enforcement', ['SUPPORTED']),
|
|
44
|
-
scenario('widening', 'universal-rig', 'widen authorization allow-list', 'attempt unauthorized widening', 'guard-enforcement', ['SUPPORTED']),
|
|
45
|
-
scenario('foreign-major', 'contracts/session-messaging/v1/fixtures/negative/envelope-foreign-major.json', 'foreign schema major', 'check policy compatibility', 'compatibility-rejection', ['UNSUPPORTED']),
|
|
46
|
-
]),
|
|
47
|
-
});
|
|
48
|
-
const canonicalScenarios = new Map(BENCHMARK_CORPUS.scenarios.map((entry) => [entry.id, entry]));
|
|
49
|
-
export const classifyCapability = (state) => {
|
|
50
|
-
switch (state) {
|
|
51
|
-
case 'SUPPORTED':
|
|
52
|
-
return { classification: 'equivalent', integrationFailed: false };
|
|
53
|
-
case 'DEGRADED':
|
|
54
|
-
return { classification: 'intentional-degradation', integrationFailed: false };
|
|
55
|
-
case 'UNSUPPORTED':
|
|
56
|
-
return { classification: 'unsupported', integrationFailed: false };
|
|
57
|
-
case 'INTEGRATION-FAILED':
|
|
58
|
-
return { classification: 'unsupported', integrationFailed: true };
|
|
59
|
-
default:
|
|
60
|
-
throw new Error(`Unknown capability state: ${String(state)}`);
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
const isOwnDataRecord = (value) => {
|
|
64
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
65
|
-
return false;
|
|
66
|
-
const prototype = Object.getPrototypeOf(value);
|
|
67
|
-
if (prototype !== Object.prototype && prototype !== null)
|
|
68
|
-
return false;
|
|
69
|
-
return Object.values(Object.getOwnPropertyDescriptors(value)).every((descriptor) => descriptor.enumerable === true && 'value' in descriptor);
|
|
70
|
-
};
|
|
71
|
-
const isDataArray = (value) => {
|
|
72
|
-
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype)
|
|
73
|
-
return false;
|
|
74
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
75
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
76
|
-
if (descriptor === undefined || descriptor.enumerable !== true || !('value' in descriptor))
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
return true;
|
|
80
|
-
};
|
|
81
|
-
const hasOnlyKeys = (value, keys) => {
|
|
82
|
-
const actual = Object.keys(value);
|
|
83
|
-
return actual.length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
84
|
-
};
|
|
85
|
-
const nonBlank = (value) => typeof value === 'string' && value.trim() !== '';
|
|
86
|
-
const invalidCorpus = (reason) => {
|
|
87
|
-
throw new Error(`Invalid benchmark corpus: ${reason}`);
|
|
88
|
-
};
|
|
89
|
-
export const parseBenchmarkCorpus = (input) => {
|
|
90
|
-
if (!isOwnDataRecord(input) || !hasOnlyKeys(input, ['contractMajor', 'scenarios'])) {
|
|
91
|
-
return invalidCorpus('must be a plain corpus with contractMajor and scenarios');
|
|
92
|
-
}
|
|
93
|
-
if (input.contractMajor !== 1)
|
|
94
|
-
return invalidCorpus('unsupported contract major; expected 1');
|
|
95
|
-
if (!isDataArray(input.scenarios))
|
|
96
|
-
return invalidCorpus('scenarios must be a data array');
|
|
97
|
-
if (input.scenarios.length !== REQUIRED_SCENARIO_IDS.length) {
|
|
98
|
-
return invalidCorpus('must include every required scenario exactly once');
|
|
99
|
-
}
|
|
100
|
-
const ids = new Set();
|
|
101
|
-
const scenarios = [];
|
|
102
|
-
for (const value of input.scenarios) {
|
|
103
|
-
if (!isOwnDataRecord(value) ||
|
|
104
|
-
!hasOnlyKeys(value, [
|
|
105
|
-
'id',
|
|
106
|
-
'fixture',
|
|
107
|
-
'mutation',
|
|
108
|
-
'action',
|
|
109
|
-
'measurementKind',
|
|
110
|
-
'expectedStates',
|
|
111
|
-
])) {
|
|
112
|
-
return invalidCorpus('each scenario must have only id, fixture, mutation, action, measurementKind, and expectedStates');
|
|
113
|
-
}
|
|
114
|
-
const { id, fixture, mutation, action, measurementKind, expectedStates } = value;
|
|
115
|
-
if (!nonBlank(id) || !requiredScenarioIds.has(id))
|
|
116
|
-
return invalidCorpus(`unknown scenario ${String(id)}`);
|
|
117
|
-
if (ids.has(id))
|
|
118
|
-
return invalidCorpus(`scenario ${id} is duplicated`);
|
|
119
|
-
if (!nonBlank(fixture) || !nonBlank(mutation) || !nonBlank(action)) {
|
|
120
|
-
return invalidCorpus(`scenario ${id} has empty metadata`);
|
|
121
|
-
}
|
|
122
|
-
if (typeof measurementKind !== 'string' ||
|
|
123
|
-
!MEASUREMENT_KINDS.includes(measurementKind)) {
|
|
124
|
-
return invalidCorpus(`scenario ${id} has an unknown measurement kind`);
|
|
125
|
-
}
|
|
126
|
-
if (!isDataArray(expectedStates) || expectedStates.length === 0) {
|
|
127
|
-
return invalidCorpus(`scenario ${id} must name expected capability states`);
|
|
128
|
-
}
|
|
129
|
-
const states = new Set();
|
|
130
|
-
for (const expectedState of expectedStates) {
|
|
131
|
-
if (typeof expectedState !== 'string' ||
|
|
132
|
-
!CAPABILITY_STATES.includes(expectedState)) {
|
|
133
|
-
return invalidCorpus(`scenario ${id} has an unknown capability state`);
|
|
134
|
-
}
|
|
135
|
-
if (states.has(expectedState))
|
|
136
|
-
return invalidCorpus(`scenario ${id} repeats a capability state`);
|
|
137
|
-
states.add(expectedState);
|
|
138
|
-
}
|
|
139
|
-
const canonical = canonicalScenarios.get(id);
|
|
140
|
-
if (fixture !== canonical.fixture ||
|
|
141
|
-
mutation !== canonical.mutation ||
|
|
142
|
-
action !== canonical.action ||
|
|
143
|
-
measurementKind !== canonical.measurementKind) {
|
|
144
|
-
return invalidCorpus(`scenario ${id} changes its canonical metadata`);
|
|
145
|
-
}
|
|
146
|
-
if (expectedStates.length !== canonical.expectedStates.length ||
|
|
147
|
-
expectedStates.some((state, index) => state !== canonical.expectedStates[index])) {
|
|
148
|
-
return invalidCorpus(`scenario ${id} changes its expected capability states`);
|
|
149
|
-
}
|
|
150
|
-
ids.add(id);
|
|
151
|
-
scenarios.push(Object.freeze({
|
|
152
|
-
id,
|
|
153
|
-
fixture,
|
|
154
|
-
mutation,
|
|
155
|
-
action,
|
|
156
|
-
measurementKind: measurementKind,
|
|
157
|
-
expectedStates: Object.freeze([...states]),
|
|
158
|
-
}));
|
|
159
|
-
}
|
|
160
|
-
for (const id of REQUIRED_SCENARIO_IDS) {
|
|
161
|
-
if (!ids.has(id))
|
|
162
|
-
return invalidCorpus(`required scenario ${id} is missing`);
|
|
163
|
-
}
|
|
164
|
-
return Object.freeze({ contractMajor: 1, scenarios: Object.freeze(scenarios) });
|
|
165
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The contract a harness adapter satisfies (RP-76).
|
|
3
|
-
*
|
|
4
|
-
* The core knows that a harness exists and has a hook-wiring surface; it does
|
|
5
|
-
* not know any harness's name, event vocabulary, tool names or paths. Those
|
|
6
|
-
* belong to the adapter, one module per harness under `../harness/`, and
|
|
7
|
-
* adding a harness means adding one such module and registering it — pinned in
|
|
8
|
-
* `test/template/policy-declaration.test.ts` under "adding a harness touches
|
|
9
|
-
* adapters only", whose two tests name exactly the files that may mention each
|
|
10
|
-
* harness. Their names carry the harness words this file may not, which is why
|
|
11
|
-
* the describe is cited here rather than either test.
|
|
12
|
-
*
|
|
13
|
-
* An adapter is a mapping, not a compiler: given a declaration it names the
|
|
14
|
-
* event, matcher and hook path the harness wires for it. The correspondence
|
|
15
|
-
* between that answer and the snapshot the rig actually ships is a test, in
|
|
16
|
-
* both directions, in the same file.
|
|
17
|
-
*/
|
|
18
|
-
export {};
|