gentle-pi 2.1.2 → 2.3.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/README.md +108 -79
- package/assets/agents/gentle-ai-worker.md +7 -3
- package/assets/agents/jd-fix-agent.md +1 -1
- package/assets/agents/jd-judge-a.md +3 -1
- package/assets/agents/jd-judge-b.md +3 -1
- package/assets/agents/review-readability.md +4 -3
- package/assets/agents/review-reliability.md +4 -3
- package/assets/agents/review-resilience.md +4 -3
- package/assets/agents/review-risk.md +4 -3
- package/assets/agents/sdd-apply.md +11 -4
- package/assets/agents/sdd-archive.md +6 -1
- package/assets/agents/sdd-design.md +6 -1
- package/assets/agents/sdd-explore.md +6 -2
- package/assets/agents/sdd-init.md +10 -2
- package/assets/agents/sdd-onboard.md +6 -1
- package/assets/agents/sdd-proposal.md +8 -1
- package/assets/agents/sdd-research.md +54 -0
- package/assets/agents/sdd-spec.md +6 -1
- package/assets/agents/sdd-status.md +10 -5
- package/assets/agents/sdd-sync.md +6 -1
- package/assets/agents/sdd-tasks.md +8 -4
- package/assets/agents/sdd-verify.md +27 -2
- package/assets/chains/4r-review.chain.md +2 -0
- package/assets/chains/sdd-full.chain.md +2 -2
- package/assets/chains/sdd-plan.chain.md +1 -1
- package/assets/chains/sdd-verify.chain.md +2 -2
- package/assets/orchestrator-delegation.md +145 -160
- package/assets/orchestrator-memory.md +2 -0
- package/assets/orchestrator.md +25 -48
- package/assets/sdd-orchestrator-workflow.md +163 -25
- package/assets/support/sdd-status-contract.md +24 -6
- package/contracts/review-integration/v1/fixtures/consent.fixture.json +3 -3
- package/contracts/review-integration/v1/fixtures/start-v2.fixture.json +19 -28
- package/contracts/review-integration/v1/fixtures/start.fixture.json +1 -10
- package/contracts/review-integration/v1/fixtures/status-v2.fixture.json +12 -21
- package/contracts/review-integration/v1/schemas/correction-plan-request.schema.json +49 -0
- package/contracts/review-integration/v1/schemas/operation.schema.json +76 -0
- package/contracts/review-integration/v1/schemas/repair.schema.json +39 -0
- package/contracts/review-integration/v1/schemas/status-v2.schema.json +4 -2
- package/contracts/review-integration/v1/schemas/status.schema.json +4 -2
- package/contracts/review-integration/v1/schemas/transition-execution.schema.json +42 -0
- package/contracts/review-integration/v2/fixtures/consent.fixture.json +1 -1
- package/contracts/review-integration/v2/fixtures/start.fixture.json +1 -10
- package/contracts/review-integration/v2/fixtures/status.fixture.json +1 -10
- package/contracts/review-integration/v2/schemas/failure.schema.json +5 -1
- package/contracts/review-integration/v2/schemas/last-event-closure.schema.json +66 -0
- package/contracts/review-integration/v2/schemas/opencode-provider-role.schema.json +14 -0
- package/contracts/review-integration/v2/schemas/operation.schema.json +6 -1
- package/contracts/review-integration/v2/schemas/repair.schema.json +4 -2
- package/contracts/review-integration/v2/schemas/start.schema.json +5 -2
- package/contracts/review-integration/v2/schemas/status.schema.json +4 -2
- package/contracts/review-provider-contract-mirror/provider-contract.lock.json +30 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/README.md +12 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/manifest.json +65 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/lens.schema.json +16 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/refuter.schema.json +1 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/schemas/targeted-validator.schema.json +1 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/lens.json +1 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/refuter.json +1 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/bundle/vectors/targeted-validator.json +1 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/generated/provider-capabilities.baseline.json +15 -0
- package/contracts/review-provider-contract-mirror/v1.1.0/generated/provider-roles.baseline.json +42 -0
- package/docs/native-authority-architecture.md +14 -16
- package/docs/review-integration.md +27 -353
- package/extensions/ask-user-choice.ts +151 -0
- package/extensions/gentle-ai.ts +2710 -3211
- package/extensions/quiet-tools.ts +515 -32
- package/extensions/sdd-init.ts +21 -12
- package/extensions/skill-registry.ts +10 -2
- package/extensions/startup-banner.ts +10 -4
- package/lib/gentle-ai-binary.ts +173 -2
- package/lib/gentle-ai-renderer.ts +70 -0
- package/lib/model-routing-authority.ts +133 -0
- package/lib/native-review-cli.ts +676 -781
- package/lib/opaque-pi-reviewer-adapter.ts +284 -0
- package/lib/provider-contract-bundle.ts +704 -0
- package/lib/review-candidate-view.ts +836 -118
- package/lib/review-compact-contract.ts +59 -248
- package/lib/review-host-relay.ts +578 -0
- package/lib/review-integration-v2.ts +1254 -221
- package/lib/review-last-event-controller.ts +35 -0
- package/lib/review-relay-contract.ts +16 -0
- package/lib/sdd-preflight.ts +230 -67
- package/lib/sdd-status.ts +66 -111
- package/lib/terminal-theme.ts +1 -1
- package/package.json +83 -79
- package/runtime/gentle-ai-binary.mjs +174 -3
- package/runtime/native-review-cli.mjs +610 -715
- package/runtime/review-integration-v2.mjs +1223 -190
- package/runtime/review-relay-contract.mjs +17 -0
- package/scripts/{build-git-commit-transaction-runner.mjs → build-runtime-modules.mjs} +5 -5
- package/scripts/check-provider-contract.mjs +138 -0
- package/scripts/gentle-ai-installer.mjs +85 -22
- package/scripts/maintainer/provider-relay-matrix.mjs +403 -0
- package/scripts/mirror-provider-contract.mjs +143 -0
- package/scripts/test-packed-runner.mjs +20 -9
- package/scripts/verify-package-files.mjs +119 -43
- package/skills/_shared/review-ledger-contract.md +11 -19
- package/skills/chained-pr/SKILL.md +3 -0
- package/skills/cognitive-doc-design/SKILL.md +1 -1
- package/skills/comment-writer/SKILL.md +1 -1
- package/skills/gentle-ai/SKILL.md +7 -74
- package/skills/issue-creation/SKILL.md +94 -168
- package/skills/judgment-day/SKILL.md +9 -5
- package/skills/judgment-day/references/prompts-and-formats.md +2 -0
- package/skills/rdd-defect-workflow/SKILL.md +54 -0
- package/skills/release/SKILL.md +3 -3
- package/skills/skill-registry/SKILL.md +1 -1
- package/skills/work-unit-commits/SKILL.md +3 -1
- package/tests/artifact-language.test.ts +24 -11
- package/tests/ask-user-choice.test.ts +264 -0
- package/tests/background-subagents.test.ts +771 -0
- package/tests/codegraph-tools.test.ts +3 -3
- package/tests/crosslane/cross-lane.mjs +16 -0
- package/tests/delegated-key-learnings-contract.test.ts +240 -0
- package/tests/devbinary/native-review-parity.devtest.ts +167 -250
- package/tests/devbinary/pi-host-relay.devtest.ts +867 -0
- package/tests/fixtures/devbinary/capabilities-v2.1.derived.json +331 -0
- package/tests/fixtures/devbinary/capabilities-v2.2.captured.json +340 -0
- package/tests/fixtures/devbinary/consent-v3.captured.json +37 -0
- package/tests/fixtures/devbinary/failure-v2-capture-evidence.captured.json +16 -0
- package/tests/fixtures/devbinary/last-event-capture-correction-plan.captured.json +10 -0
- package/tests/fixtures/devbinary/last-event-capture-refuter-approved.captured.json +20 -0
- package/tests/fixtures/devbinary/last-event-capture-refuter-correction-required.captured.json +26 -0
- package/tests/fixtures/devbinary/last-event-capture-result-approved.captured.json +8 -0
- package/tests/fixtures/devbinary/last-event-capture-result-correction-required.captured.json +26 -0
- package/tests/fixtures/devbinary/last-event-capture-validation-approved.captured.json +8 -0
- package/tests/fixtures/devbinary/last-event-closure.provenance.md +13 -0
- package/tests/fixtures/devbinary/result-artifact-v2-path.captured.json +12 -0
- package/tests/fixtures/devbinary/result-artifact-v2.captured.json +12 -0
- package/tests/fixtures/devbinary/review-acknowledged-v1.captured.json +9 -0
- package/tests/fixtures/devbinary/review-acknowledged.provenance.md +31 -0
- package/tests/fixtures/devbinary/start-v3-consent-declined.captured.json +19 -0
- package/tests/fixtures/devbinary/start-v3-consent-granted.captured.json +109 -0
- package/tests/fixtures/devbinary/start-v3-zero-lens-closed.captured.json +21 -0
- package/tests/fixtures/devbinary/status-v5-capture-result-submission.captured.json +184 -0
- package/tests/fixtures/devbinary/status-v5-repository-context.captured.json +138 -0
- package/tests/fixtures/devbinary/status-v5.captured.json +88 -0
- package/tests/fixtures/native-review-cli/v2.5.0-rc.1/PROVENANCE.txt +15 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/README.md +12 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/manifest.json +65 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/lens.schema.json +16 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/refuter.schema.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/schemas/targeted-validator.schema.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/lens.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/refuter.json +1 -0
- package/tests/fixtures/provider-contract-bundle/v1.1.0/vectors/targeted-validator.json +1 -0
- package/tests/gentle-ai-binary.test.ts +83 -13
- package/tests/gentle-ai-dev-binary-surfacing.test.ts +195 -0
- package/tests/gentle-ai-dev-binary.test.ts +159 -0
- package/tests/gentle-ai-installer.test.ts +138 -48
- package/tests/gentle-ai.test.ts +820 -131
- package/tests/gentle-theme.test.ts +133 -0
- package/tests/maintainer/provider-relay.maintest.ts +601 -0
- package/tests/model-routing-authority.test.ts +257 -0
- package/tests/native-review-capability-contract.test.ts +75 -2
- package/tests/native-review-cli.test.ts +588 -908
- package/tests/native-review-consent.test.ts +283 -38
- package/tests/native-review-parity-runtime.test.ts +108 -350
- package/tests/native-review-parity.test.ts +684 -732
- package/tests/native-sdd-attempt-authority.test.ts +235 -0
- package/tests/opaque-pi-reviewer-adapter.test.ts +266 -0
- package/tests/orchestrator-budget.test.ts +158 -89
- package/tests/orchestrator-rdd-ownership.test.ts +103 -0
- package/tests/package-manifest.test.ts +128 -100
- package/tests/provider-contract-bundle.test.ts +385 -0
- package/tests/provider-contract-mirror.test.ts +206 -0
- package/tests/provider-defect-handoff.test.ts +252 -0
- package/tests/quiet-tool-rendering.test.ts +1055 -28
- package/tests/review-actor-tool-deny.test.ts +12 -13
- package/tests/review-authority-recovery-docs.test.ts +1 -2
- package/tests/review-candidate-view.test.ts +898 -12
- package/tests/review-compact-contract.test.ts +29 -122
- package/tests/review-controller-lock-status.test.ts +2 -2
- package/tests/review-controller-native-recovery.test.ts +366 -857
- package/tests/review-controller-native-routing.test.ts +1253 -4199
- package/tests/review-controller-retired-ops.test.ts +1 -1
- package/tests/review-controller-workspace-root.test.ts +236 -70
- package/tests/review-controller.test.ts +26 -816
- package/tests/review-corrected-finalize-binding.test.ts +134 -0
- package/tests/review-dispatch-hydration-gap.test.ts +145 -0
- package/tests/review-gate.test.ts +0 -45
- package/tests/review-host-relay-restart-parity.test.ts +360 -0
- package/tests/review-host-relay-routing.test.ts +352 -0
- package/tests/review-host-relay.test.ts +754 -0
- package/tests/review-integration-v2-forward.test.ts +654 -0
- package/tests/review-integration-v2.test.ts +317 -129
- package/tests/review-last-event-closure.test.ts +408 -0
- package/tests/review-ledger-contract.test.ts +106 -60
- package/tests/review-recovered-lineage-routing.test.ts +199 -0
- package/tests/review-relay-transport-agent.test.ts +322 -0
- package/tests/review-snapshot.test.ts +3 -2
- package/tests/runtime-harness.mjs +573 -180
- package/tests/sdd-agent-tools.test.ts +53 -32
- package/tests/sdd-preflight.test.ts +81 -15
- package/tests/sdd-status.test.ts +109 -110
- package/tests/skill-collision-prefixes.test.ts +6 -8
- package/tests/skill-registry.test.ts +50 -1
- package/tests/verify-package-files.test.ts +62 -0
- package/tests/writer-edit-surface-scope.test.ts +230 -0
- package/themes/Gentleman-Cute.json +94 -0
- package/themes/Gentleman-Sexy.json +92 -0
- package/assets/agents/review-refuter.md +0 -40
- package/assets/agents/review-validator.md +0 -23
- package/lib/git-commit-transaction.ts +0 -801
- package/lib/native-review-remediation.ts +0 -49
- package/lib/review-compact.ts +0 -947
- package/lib/review-refuter-adapter.ts +0 -129
- package/lib/review-runtime-contract.ts +0 -68
- package/prompts/gcl.md +0 -54
- package/prompts/gis.md +0 -25
- package/prompts/gpr.md +0 -41
- package/prompts/gwr.md +0 -31
- package/runtime/git-commit-transaction.mjs +0 -802
- package/scripts/run-git-commit-transaction.mjs +0 -35
- package/tests/fixtures/native-review-cli/v2.1.2/bind-sdd.json +0 -25
- package/tests/fixtures/native-review-cli/v2.1.2/finalize.json +0 -8
- package/tests/fixtures/native-review-cli/v2.1.2/sdd-status-engram.json +0 -139
- package/tests/fixtures/native-review-cli/v2.1.2/sdd-status.json +0 -200
- package/tests/fixtures/native-review-cli/v2.1.2/start.json +0 -12
- package/tests/fixtures/native-review-cli/v2.1.2/validate-allow.json +0 -24
- package/tests/fixtures/native-review-cli/v2.1.2/validate-deny-empty-context.json +0 -20
- package/tests/fixtures/native-review-cli/v2.1.2/validate-deny.json +0 -28
- package/tests/fixtures/native-review-cli/v2.1.3/sdd-status-engram.json +0 -139
- package/tests/fixtures/native-review-cli/v2.1.3/sdd-status.json +0 -200
- package/tests/git-commit-transaction.test.ts +0 -302
- package/tests/review-compact.test.ts +0 -243
- package/tests/review-refuter-adapter.test.ts +0 -89
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync
|
|
3
|
+
import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import test, { after } from "node:test";
|
|
@@ -9,8 +9,8 @@ import test, { after } from "node:test";
|
|
|
9
9
|
// orchestrator-lazy-diet migration tests
|
|
10
10
|
//
|
|
11
11
|
// Locks the split of the always-on `assets/orchestrator.md` into a thin core
|
|
12
|
-
// plus
|
|
13
|
-
//
|
|
12
|
+
// plus lazy reference files (see design.md "Core budget rebuilt from measured
|
|
13
|
+
// drafts" and "Appendix: drafted core texts").
|
|
14
14
|
//
|
|
15
15
|
// `getOrchestratorPrompt`'s rendered return value is memoized in a
|
|
16
16
|
// module-level cache (first-read-wins for the process lifetime — see design.md
|
|
@@ -19,17 +19,19 @@ import test, { after } from "node:test";
|
|
|
19
19
|
// ambient environment variables, so production runtime asset resolution stays
|
|
20
20
|
// deterministic. The representative production assets directory below is
|
|
21
21
|
// populated by COPYING the real repo assets (dynamically, at test-run time)
|
|
22
|
-
// into
|
|
23
|
-
// real repo's absolute path length while keeping content
|
|
24
|
-
// production. Tests that need to inspect the real repo files
|
|
25
|
-
// disposition-mapped union sweep, the core-alone token
|
|
26
|
-
// `assets/*.md` directly via `readFileSync`, sidestepping the
|
|
22
|
+
// into short and deliberately long tmpdir paths. This isolates byte-budget
|
|
23
|
+
// measurement from the real repo's absolute path length while keeping content
|
|
24
|
+
// representative of production. Tests that need to inspect the real repo files
|
|
25
|
+
// directly (the disposition-mapped union sweep, the core-alone token
|
|
26
|
+
// assertions) read `assets/*.md` directly via `readFileSync`, sidestepping the
|
|
27
|
+
// cache entirely.
|
|
27
28
|
// ---------------------------------------------------------------------------
|
|
28
29
|
|
|
29
30
|
const REPO_ROOT = join(import.meta.dirname, "..");
|
|
30
31
|
const REAL_ASSETS_DIR = join(REPO_ROOT, "assets");
|
|
31
32
|
const FIXTURE_PATH = join(import.meta.dirname, "fixtures", "orchestrator.pre-diet.md");
|
|
32
|
-
const BUDGET_BYTES =
|
|
33
|
+
const BUDGET_BYTES = 8192;
|
|
34
|
+
const MIN_CONTROLLED_LONG_ASSETS_ROOT_CHARS = 93;
|
|
33
35
|
|
|
34
36
|
const LAZY_ASSET_NAMES = [
|
|
35
37
|
"orchestrator.md",
|
|
@@ -38,42 +40,56 @@ const LAZY_ASSET_NAMES = [
|
|
|
38
40
|
"orchestrator-memory.md",
|
|
39
41
|
"orchestrator-skills.md",
|
|
40
42
|
] as const;
|
|
43
|
+
const LAZY_REFERENCE_FILE_NAMES = LAZY_ASSET_NAMES.slice(1);
|
|
41
44
|
|
|
42
|
-
|
|
43
|
-
for (const name of LAZY_ASSET_NAMES) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
join(
|
|
47
|
-
|
|
48
|
-
);
|
|
45
|
+
function copyRequiredLazyAssets(destination: string): void {
|
|
46
|
+
for (const name of LAZY_ASSET_NAMES) {
|
|
47
|
+
const source = join(REAL_ASSETS_DIR, name);
|
|
48
|
+
assert.ok(existsSync(source), `missing packaged lazy asset: ${name}`);
|
|
49
|
+
copyFileSync(source, join(destination, name));
|
|
50
|
+
}
|
|
49
51
|
}
|
|
50
|
-
const { __testing } = await import("../extensions/gentle-ai.ts");
|
|
51
52
|
|
|
52
|
-
const
|
|
53
|
+
const representativeProductionAssetsDir = mkdtempSync(join(tmpdir(), "gp-b-"));
|
|
54
|
+
copyRequiredLazyAssets(representativeProductionAssetsDir);
|
|
55
|
+
const { __testing } = await import("../extensions/gentle-ai.ts");
|
|
53
56
|
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
// to
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
// A controlled long assets root proves the parent prompt remains within the
|
|
58
|
+
// canonical budget independently of the checkout or installed-package path.
|
|
59
|
+
// The child-process measurement keeps production cache behavior separate from
|
|
60
|
+
// fixture measurements.
|
|
61
|
+
// The root is built to one exact length rather than "tmpdir plus a long
|
|
62
|
+
// suffix". The prompt declares the absolute root once, so it grows one byte
|
|
63
|
+
// per root character, and a 48-character macOS tmpdir pushed the previous
|
|
64
|
+
// construction to 164 characters where a 4-character Linux /tmp gave 121.
|
|
65
|
+
// A fixed length makes every platform measure the same budget claim.
|
|
66
|
+
const CONTROLLED_LONG_ASSETS_ROOT_CHARS = 128;
|
|
67
|
+
const controlledLongBaseDir = mkdtempSync(join(tmpdir(), "gp-long-"));
|
|
68
|
+
const controlledLongSegmentChars = CONTROLLED_LONG_ASSETS_ROOT_CHARS - join(controlledLongBaseDir, "x", "assets").length + 1;
|
|
62
69
|
assert.ok(
|
|
63
|
-
|
|
64
|
-
`
|
|
70
|
+
controlledLongSegmentChars >= 1,
|
|
71
|
+
`tmpdir ${tmpdir()} is too long to build a ${CONTROLLED_LONG_ASSETS_ROOT_CHARS}-char controlled assets root`,
|
|
65
72
|
);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
const controlledLongAssetsDir = join(
|
|
74
|
+
controlledLongBaseDir,
|
|
75
|
+
"path-independent-prompt-budget-".repeat(Math.ceil(controlledLongSegmentChars / 31)).slice(0, controlledLongSegmentChars),
|
|
76
|
+
"assets",
|
|
77
|
+
);
|
|
78
|
+
mkdirSync(controlledLongAssetsDir, { recursive: true });
|
|
79
|
+
assert.equal(
|
|
80
|
+
controlledLongAssetsDir.length,
|
|
81
|
+
CONTROLLED_LONG_ASSETS_ROOT_CHARS,
|
|
82
|
+
`controlled long assets root is ${controlledLongAssetsDir.length} chars, want exactly ${CONTROLLED_LONG_ASSETS_ROOT_CHARS}`,
|
|
83
|
+
);
|
|
84
|
+
assert.ok(
|
|
85
|
+
controlledLongAssetsDir.length >= MIN_CONTROLLED_LONG_ASSETS_ROOT_CHARS,
|
|
86
|
+
`controlled long assets root is only ${controlledLongAssetsDir.length} chars, need >= ${MIN_CONTROLLED_LONG_ASSETS_ROOT_CHARS}`,
|
|
87
|
+
);
|
|
88
|
+
copyRequiredLazyAssets(controlledLongAssetsDir);
|
|
73
89
|
|
|
74
90
|
after(() => {
|
|
75
91
|
rmSync(representativeProductionAssetsDir, { recursive: true, force: true });
|
|
76
|
-
rmSync(
|
|
92
|
+
rmSync(controlledLongBaseDir, { recursive: true, force: true });
|
|
77
93
|
});
|
|
78
94
|
|
|
79
95
|
function readRealAsset(name: string): string {
|
|
@@ -98,7 +114,7 @@ function measureOrchestratorPromptBytes(assetsDir: string): number {
|
|
|
98
114
|
// 2.2 — Byte budget (Spec: Always-On Injection Byte Budget)
|
|
99
115
|
// ---------------------------------------------------------------------------
|
|
100
116
|
|
|
101
|
-
test("getOrchestratorPrompt return value stays within the
|
|
117
|
+
test("getOrchestratorPrompt return value stays within the canonical 8,192 B budget at a short assets root", () => {
|
|
102
118
|
const rendered = __testing.renderOrchestratorPrompt(representativeProductionAssetsDir);
|
|
103
119
|
const bytes = Buffer.byteLength(rendered, "utf8");
|
|
104
120
|
assert.ok(
|
|
@@ -107,33 +123,46 @@ test("getOrchestratorPrompt return value stays within the 10,240 B budget (short
|
|
|
107
123
|
);
|
|
108
124
|
});
|
|
109
125
|
|
|
110
|
-
test(`getOrchestratorPrompt
|
|
111
|
-
const
|
|
126
|
+
test(`getOrchestratorPrompt keeps a controlled long (>= ${MIN_CONTROLLED_LONG_ASSETS_ROOT_CHARS} char) assets root within the canonical budget`, () => {
|
|
127
|
+
const rendered = __testing.renderOrchestratorPrompt(controlledLongAssetsDir);
|
|
128
|
+
const bytes = measureOrchestratorPromptBytes(controlledLongAssetsDir);
|
|
129
|
+
assert.equal(bytes, Buffer.byteLength(rendered, "utf8"), "child-process and direct render byte counts must match");
|
|
112
130
|
assert.ok(
|
|
113
131
|
bytes <= BUDGET_BYTES,
|
|
114
|
-
`getOrchestratorPrompt() returned ${bytes} B at
|
|
132
|
+
`getOrchestratorPrompt() returned ${bytes} B at controlled ${controlledLongAssetsDir.length}-char assets root, exceeds the ${BUDGET_BYTES} B budget`,
|
|
115
133
|
);
|
|
134
|
+
assert.equal(
|
|
135
|
+
rendered.split(controlledLongAssetsDir).length - 1,
|
|
136
|
+
1,
|
|
137
|
+
"the absolute assets root must be declared exactly once",
|
|
138
|
+
);
|
|
139
|
+
assert.ok(
|
|
140
|
+
rendered.includes(`Package assets root: \`${controlledLongAssetsDir}\`. Lazy asset paths below are relative to this root.`),
|
|
141
|
+
"the parent prompt must declare how to resolve relative lazy asset paths",
|
|
142
|
+
);
|
|
143
|
+
for (const name of LAZY_REFERENCE_FILE_NAMES) {
|
|
144
|
+
assert.ok(rendered.includes(`\`${name}\``), `lazy asset filename is missing: ${name}`);
|
|
145
|
+
}
|
|
146
|
+
assert.doesNotMatch(rendered, /\{\{/, "unresolved {{...}} placeholder leaked into the rendered prompt");
|
|
116
147
|
});
|
|
117
148
|
|
|
118
149
|
// ---------------------------------------------------------------------------
|
|
119
150
|
// 2.3 — Disposition-mapped union sweep (Spec: No Normative Content Loss +
|
|
120
151
|
// Pointer reachability)
|
|
121
152
|
//
|
|
122
|
-
// Every normative line of the frozen pre-diet fixture is assigned to
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
// (intentionally absent
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
// LAZY_VERBATIM against their one target lazy file — never a blanket union
|
|
129
|
-
// across all three.
|
|
153
|
+
// Every normative line of the frozen pre-diet fixture is assigned to a
|
|
154
|
+
// documented disposition: CORE_VERBATIM (byte-identical in the core),
|
|
155
|
+
// LAZY_VERBATIM (byte-identical in one specific lazy file), OBSOLETE
|
|
156
|
+
// (intentionally absent), or REPLACED (superseded by the focused #3417 asset
|
|
157
|
+
// policy ratchets below). REPLACED preserves the historical fixture without
|
|
158
|
+
// treating a retired prompt mirror as a current normative source.
|
|
130
159
|
// ---------------------------------------------------------------------------
|
|
131
160
|
|
|
132
161
|
type Target = "core" | "delegation" | "memory" | "skills";
|
|
133
162
|
|
|
134
163
|
interface DispositionRange {
|
|
135
164
|
lines: [number, number];
|
|
136
|
-
target: Target | "obsolete";
|
|
165
|
+
target: Target | "obsolete" | "replaced";
|
|
137
166
|
label: string;
|
|
138
167
|
}
|
|
139
168
|
|
|
@@ -158,13 +187,37 @@ const DISPOSITION_MAP: DispositionRange[] = [
|
|
|
158
187
|
{ lines: [25, 29], target: "delegation", label: "Language Boundary LB5 (exceptions)" },
|
|
159
188
|
{ lines: [31, 40], target: "core", label: "Mental Model" },
|
|
160
189
|
{ lines: [42, 42], target: "core", label: "Work Routing Ladder heading" },
|
|
161
|
-
{
|
|
190
|
+
{
|
|
191
|
+
lines: [44, 97],
|
|
192
|
+
target: "replaced",
|
|
193
|
+
label: "Pre-RDD routing detail replaced by focused direct-delegation guidance (#3417)",
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
lines: [98, 107],
|
|
197
|
+
target: "obsolete",
|
|
198
|
+
label: "Size/risk-selected SDD tier replaced by explicit-request/accepted-proposal selection (#312)",
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
lines: [108, 108],
|
|
202
|
+
target: "replaced",
|
|
203
|
+
label: "Earlier SDD trigger wording replaced by the focused SDD boundary (#3417)",
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
lines: [109, 110],
|
|
207
|
+
target: "obsolete",
|
|
208
|
+
label: "Size-gated SDD entry replaced by explicit-selection gating (#312)",
|
|
209
|
+
},
|
|
162
210
|
{ lines: [112, 112], target: "core", label: "Delegation Rules heading" },
|
|
163
211
|
{ lines: [114, 114], target: "core", label: "Delegation Rules core question" },
|
|
164
212
|
{
|
|
165
|
-
lines: [116,
|
|
166
|
-
target: "
|
|
167
|
-
label: "
|
|
213
|
+
lines: [116, 126],
|
|
214
|
+
target: "obsolete",
|
|
215
|
+
label: "Pre-canon delegation table replaced by the mirrored gentle-ai canon table (#312)",
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
lines: [128, 132],
|
|
219
|
+
target: "replaced",
|
|
220
|
+
label: "Pre-RDD trigger wording replaced by focused direct-delegation guidance (#3417)",
|
|
168
221
|
},
|
|
169
222
|
{
|
|
170
223
|
lines: [133, 133],
|
|
@@ -172,14 +225,27 @@ const DISPOSITION_MAP: DispositionRange[] = [
|
|
|
172
225
|
label: "Superseded no-runtime inline exception",
|
|
173
226
|
},
|
|
174
227
|
{
|
|
175
|
-
lines: [134,
|
|
176
|
-
target: "
|
|
177
|
-
label: "
|
|
228
|
+
lines: [134, 167],
|
|
229
|
+
target: "replaced",
|
|
230
|
+
label: "Pre-RDD trigger and workflow wording replaced by focused delegation guidance (#3417)",
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
lines: [169, 181],
|
|
234
|
+
target: "obsolete",
|
|
235
|
+
label: "Parent-selected review lens table replaced by native RAR lens ownership (#312)",
|
|
178
236
|
},
|
|
179
237
|
{ lines: [183, 191], target: "core", label: "SDD Workflow pointer" },
|
|
180
238
|
{ lines: [193, 193], target: "core", label: "Memory Contract heading" },
|
|
181
|
-
{
|
|
182
|
-
|
|
239
|
+
{
|
|
240
|
+
lines: [195, 195],
|
|
241
|
+
target: "replaced",
|
|
242
|
+
label: "Verbose memory introduction replaced by compact parent/subagent ownership (#3417)",
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
lines: [197, 201],
|
|
246
|
+
target: "replaced",
|
|
247
|
+
label: "Verbose non-SDD memory forwarding replaced by compact ownership (#3417)",
|
|
248
|
+
},
|
|
183
249
|
{ lines: [203, 230], target: "memory", label: "Memory Contract SDD phases table + artifact keys + lifecycle rule" },
|
|
184
250
|
{ lines: [232, 232], target: "core", label: "Skill Registry Protocol heading" },
|
|
185
251
|
{ lines: [234, 253], target: "skills", label: "Skill Registry Protocol detail" },
|
|
@@ -198,9 +264,18 @@ function isNormativeLine(line: string): boolean {
|
|
|
198
264
|
}
|
|
199
265
|
|
|
200
266
|
const fixtureLines = readFileSync(FIXTURE_PATH, "utf8").split("\n");
|
|
267
|
+
// Fixture lines 187 and 191 predate the root-relative lazy-asset contract and
|
|
268
|
+
// canonical-authority resolution. Keep their coverage by asserting the
|
|
269
|
+
// intentionally updated production wording instead of weakening the range.
|
|
270
|
+
const CURRENT_SDD_WORKFLOW_PATH = "`sdd-orchestrator-workflow.md`";
|
|
271
|
+
const CURRENT_HARD_PREFLIGHT_INVARIANT = "Hard preflight invariant: `openspec/config.yaml`, existing SDD changes, installed `.pi`/global SDD assets, or a todo named \"preflight\" are not session preflight. Do not mark SDD preflight complete, start `sdd-init`, launch SDD subagents/chains, or move to explore/proposal/spec/design/tasks until this session has an injected `## SDD Session Preflight` block or a canonical-authority resolution. Defaults and capability constraints may resolve fields without confirmation prompts; preserve unresolved-choice and safety gates.";
|
|
201
272
|
const SUPERSEDED_LIFECYCLE_REVIEW_LINES = new Set([
|
|
202
273
|
70,
|
|
274
|
+
// 74/77: the loose mode-choice background lines were replaced by the
|
|
275
|
+
// marked gentle-pi:background-subagents policy block (issue #256).
|
|
276
|
+
74,
|
|
203
277
|
76,
|
|
278
|
+
77,
|
|
204
279
|
92,
|
|
205
280
|
125,
|
|
206
281
|
126,
|
|
@@ -215,6 +290,7 @@ const SUPERSEDED_LIFECYCLE_REVIEW_LINES = new Set([
|
|
|
215
290
|
]);
|
|
216
291
|
|
|
217
292
|
for (const range of DISPOSITION_MAP) {
|
|
293
|
+
if (range.target === "replaced") continue;
|
|
218
294
|
test(
|
|
219
295
|
`disposition-mapped union: ${range.label} (fixture:${range.lines[0]}-${range.lines[1]}) -> ${range.target}`,
|
|
220
296
|
() => {
|
|
@@ -226,6 +302,12 @@ for (const range of DISPOSITION_MAP) {
|
|
|
226
302
|
const raw = fixtureLines[ln - 1];
|
|
227
303
|
if (raw === undefined || !isNormativeLine(raw)) continue;
|
|
228
304
|
const trimmed = raw.trim();
|
|
305
|
+
const expected =
|
|
306
|
+
ln === 187
|
|
307
|
+
? CURRENT_SDD_WORKFLOW_PATH
|
|
308
|
+
: ln === 191
|
|
309
|
+
? CURRENT_HARD_PREFLIGHT_INVARIANT
|
|
310
|
+
: trimmed;
|
|
229
311
|
if (SUPERSEDED_LIFECYCLE_REVIEW_LINES.has(ln)) {
|
|
230
312
|
assert.ok(
|
|
231
313
|
!targetContent.includes(trimmed),
|
|
@@ -241,8 +323,8 @@ for (const range of DISPOSITION_MAP) {
|
|
|
241
323
|
continue;
|
|
242
324
|
}
|
|
243
325
|
assert.ok(
|
|
244
|
-
targetContent.includes(
|
|
245
|
-
`normative line lost: fixture:${ln} "${
|
|
326
|
+
targetContent.includes(expected),
|
|
327
|
+
`normative line lost: fixture:${ln} "${expected}" not found verbatim in ${TARGET_FILE[range.target]} (disposition: ${range.target}, section: ${range.label})`,
|
|
246
328
|
);
|
|
247
329
|
}
|
|
248
330
|
},
|
|
@@ -254,32 +336,28 @@ for (const range of DISPOSITION_MAP) {
|
|
|
254
336
|
// string alone, no lazy union.
|
|
255
337
|
// ---------------------------------------------------------------------------
|
|
256
338
|
|
|
257
|
-
test("core-alone: load-bearing delegation tokens
|
|
339
|
+
test("core-alone: load-bearing direct-delegation tokens remain without lazy union", () => {
|
|
258
340
|
const core = readRealAsset("orchestrator.md");
|
|
259
341
|
assert.match(core, /4-file rule/);
|
|
260
342
|
assert.match(core, /Multi-file write rule/);
|
|
261
|
-
assert.match(core, /Lifecycle gate rule/);
|
|
262
343
|
assert.match(core, /Incident rule/);
|
|
344
|
+
assert.match(core, /Verification rule/);
|
|
263
345
|
assert.match(core, /Long-session rule/);
|
|
264
|
-
assert.match(core, /Review actor rule/);
|
|
265
346
|
});
|
|
266
347
|
|
|
267
|
-
test("core-alone:
|
|
348
|
+
test("core-alone: dynamic Gentle AI ownership replaces package lifecycle instructions", () => {
|
|
268
349
|
const core = readRealAsset("orchestrator.md");
|
|
269
|
-
assert.match(core, /
|
|
270
|
-
assert.match(core, /
|
|
271
|
-
assert.
|
|
272
|
-
assert.
|
|
273
|
-
assert.match(core, /Dangerous-command safety remains independent and authoritative/i);
|
|
274
|
-
assert.match(core, /SDD completion adds no review or Judgment Day pass/i);
|
|
350
|
+
assert.match(core, /dynamically supplies runtime-specific RDD instructions via generated Pi APPEND_SYSTEM composition/);
|
|
351
|
+
assert.match(core, /if absent or unsupported, this package does not invent or fall back/);
|
|
352
|
+
assert.doesNotMatch(core, /start -> finalize -> validate/i);
|
|
353
|
+
assert.doesNotMatch(core, /receipt validation/i);
|
|
275
354
|
});
|
|
276
355
|
|
|
277
|
-
test("lazy
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
assert.match(content, /review-readability/);
|
|
356
|
+
test("lazy delegation detail has no native RDD controller markers", () => {
|
|
357
|
+
const delegation = readRealAsset("orchestrator-delegation.md");
|
|
358
|
+
for (const marker of ["next_transition", "review.capture-result", "reconcile-terminal-mirrors"]) {
|
|
359
|
+
assert.ok(!delegation.includes(marker), `stale RDD marker retained: ${marker}`);
|
|
360
|
+
}
|
|
283
361
|
});
|
|
284
362
|
|
|
285
363
|
test("live orchestrator assets remove the stale strong-gate retry contract", () => {
|
|
@@ -320,20 +398,11 @@ test("relocated lazy bodies are not double-delivered in the always-on core", ()
|
|
|
320
398
|
);
|
|
321
399
|
});
|
|
322
400
|
|
|
323
|
-
test("relocated lazy files are reachable via in-core
|
|
401
|
+
test("relocated lazy files are reachable via root-relative in-core filenames", () => {
|
|
324
402
|
const rendered = __testing.getOrchestratorPrompt();
|
|
325
|
-
|
|
326
|
-
rendered.includes(
|
|
327
|
-
|
|
328
|
-
);
|
|
329
|
-
assert.ok(
|
|
330
|
-
rendered.includes(join(REAL_ASSETS_DIR, "orchestrator-memory.md")),
|
|
331
|
-
"core is missing a reachable pointer to orchestrator-memory.md",
|
|
332
|
-
);
|
|
333
|
-
assert.ok(
|
|
334
|
-
rendered.includes(join(REAL_ASSETS_DIR, "orchestrator-skills.md")),
|
|
335
|
-
"core is missing a reachable pointer to orchestrator-skills.md",
|
|
336
|
-
);
|
|
403
|
+
for (const name of LAZY_REFERENCE_FILE_NAMES) {
|
|
404
|
+
assert.ok(rendered.includes(`\`${name}\``), `core is missing a reachable pointer to ${name}`);
|
|
405
|
+
}
|
|
337
406
|
});
|
|
338
407
|
|
|
339
408
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
|
|
6
|
+
const ROOT = join(import.meta.dirname, "..");
|
|
7
|
+
const ASSETS = join(ROOT, "assets");
|
|
8
|
+
const BOUNDARY =
|
|
9
|
+
"Gentle AI dynamically supplies runtime-specific RDD instructions via generated Pi APPEND_SYSTEM composition. Follow only those exact native instructions; if absent or unsupported, this package does not invent or fall back.";
|
|
10
|
+
|
|
11
|
+
function read(relativePath: string): string {
|
|
12
|
+
return readFileSync(join(ROOT, relativePath), "utf8");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const core = read("assets/orchestrator.md");
|
|
16
|
+
const delegation = read("assets/orchestrator-delegation.md");
|
|
17
|
+
const staticPrompts = `${core}\n${delegation}`;
|
|
18
|
+
|
|
19
|
+
test("static prompts omit stale native RDD lifecycle mirrors", () => {
|
|
20
|
+
for (const marker of [
|
|
21
|
+
"Authority-First Terminal Procedure",
|
|
22
|
+
"reconcile-terminal-mirrors",
|
|
23
|
+
"Native Bounded Review Orchestration",
|
|
24
|
+
"Continue after a stop reason code",
|
|
25
|
+
"gentle-ai review status",
|
|
26
|
+
"next_transition",
|
|
27
|
+
"start -> finalize -> validate",
|
|
28
|
+
"review.capture-result",
|
|
29
|
+
"review.validate",
|
|
30
|
+
"reviewGate.result",
|
|
31
|
+
]) {
|
|
32
|
+
assert.ok(!staticPrompts.includes(marker), `stale RDD marker remains: ${marker}`);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("lossless blocking prompts route every closed single-select envelope through the native closed tool", () => {
|
|
37
|
+
for (const clause of [
|
|
38
|
+
"For every strictly closed single-select envelope",
|
|
39
|
+
"ask_user_choice",
|
|
40
|
+
"envelope-owned canonical option token as opaque `value`",
|
|
41
|
+
"returns exactly one `value`",
|
|
42
|
+
"externally owned open/free-text questionnaire",
|
|
43
|
+
"never for a closed domain",
|
|
44
|
+
"exact captured provider-owned choice invocation",
|
|
45
|
+
]) {
|
|
46
|
+
assert.ok(delegation.includes(clause), `lossless prompt is missing: ${clause}`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("static prompts declare one dynamic Gentle AI RDD ownership boundary", () => {
|
|
51
|
+
assert.equal(staticPrompts.split(BOUNDARY).length - 1, 1, "expected one dynamic RDD ownership boundary");
|
|
52
|
+
assert.ok(core.includes(BOUNDARY), "the Pi parent prompt owns the single boundary");
|
|
53
|
+
assert.ok(!delegation.includes(BOUNDARY), "generic delegation detail must not gain RDD text");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("rendered parent prompt keeps the RDD boundary while omitting lifecycle mirrors", async () => {
|
|
57
|
+
const { __testing } = await import("../extensions/gentle-ai.ts");
|
|
58
|
+
const rendered = __testing.getOrchestratorPrompt();
|
|
59
|
+
assert.ok(rendered.includes(BOUNDARY));
|
|
60
|
+
for (const marker of ["Authority-First Terminal Procedure", "reconcile-terminal-mirrors", "next_transition"]) {
|
|
61
|
+
assert.ok(!rendered.includes(marker), `rendered parent prompt leaked: ${marker}`);
|
|
62
|
+
}
|
|
63
|
+
assert.ok(Buffer.byteLength(rendered, "utf8") <= 8192, "the rendered parent prompt must stay below the reduced 8 KiB budget");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("static prompts retain normal SDD and delegated-work guidance", () => {
|
|
67
|
+
for (const heading of ["## SDD Workflow (lazy-loaded)", "## Memory Contract"]) {
|
|
68
|
+
assert.ok(core.includes(heading), `core lost ${heading}`);
|
|
69
|
+
}
|
|
70
|
+
for (const heading of [
|
|
71
|
+
"### Delegation Rules",
|
|
72
|
+
"#### Background Subagent Policy",
|
|
73
|
+
"#### Allowed edit surfaces (MANDATORY)",
|
|
74
|
+
"### 3. SDD (optional)",
|
|
75
|
+
]) {
|
|
76
|
+
assert.ok(delegation.includes(heading), `delegation lost ${heading}`);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("always-on parent prompt requires a narrow writer edit surface before launch", () => {
|
|
81
|
+
assert.match(core, /Before launching (?:a )?bounded writer/i);
|
|
82
|
+
assert.match(core, /`gentle-ai-worker`/);
|
|
83
|
+
assert.match(core, /`worker`/);
|
|
84
|
+
assert.match(core, /## Allowed edit surfaces/);
|
|
85
|
+
assert.match(core, /repository-relative/i);
|
|
86
|
+
assert.match(core, /never `\.`|never a bare repository root/i);
|
|
87
|
+
assert.match(core, /do not ask the human to author paths or globs/i);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("review integration documents the opaque Pi adapter and Go-owned authority boundary", () => {
|
|
91
|
+
const docs = read("docs/review-integration.md");
|
|
92
|
+
for (const marker of [
|
|
93
|
+
"Buffer → Buffer/error",
|
|
94
|
+
"exact Go-issued materialize/submission tokens",
|
|
95
|
+
"typed Pi transport refusal fails closed",
|
|
96
|
+
"Go owns worktree, lineage, candidate freeze, lens selection, correction, validator, approval burn, and review semantics",
|
|
97
|
+
"Delivery commands remain ordinary repository-policy operations.",
|
|
98
|
+
"package has no durable receipt or policy authority",
|
|
99
|
+
"static assets intentionally omit lifecycle instructions",
|
|
100
|
+
]) {
|
|
101
|
+
assert.ok(docs.includes(marker), `review integration doc is missing: ${marker}`);
|
|
102
|
+
}
|
|
103
|
+
});
|