@tiphys/kernel 0.0.0 → 0.2.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/AGENTS.md +663 -0
- package/LICENSE +202 -0
- package/assurance-modes.yaml +299 -0
- package/checklists/clean-room.yaml +325 -0
- package/checklists/env-failure-diagnosis.yaml +68 -0
- package/checklists/flake-playbook.yaml +68 -0
- package/checklists/hazard-review.yaml +144 -0
- package/checklists/plan-review.yaml +103 -0
- package/dist/bin/tiphys.d.ts +2 -0
- package/dist/bin/tiphys.js +92 -0
- package/dist/src/adapters/load.d.ts +202 -0
- package/dist/src/adapters/load.js +440 -0
- package/dist/src/brief.d.ts +32 -0
- package/dist/src/brief.js +66 -0
- package/dist/src/checklists.d.ts +169 -0
- package/dist/src/checklists.js +310 -0
- package/dist/src/checks.d.ts +1539 -0
- package/dist/src/checks.js +5025 -0
- package/dist/src/cli.d.ts +9 -0
- package/dist/src/cli.js +68 -0
- package/dist/src/commands/brief.d.ts +92 -0
- package/dist/src/commands/brief.js +343 -0
- package/dist/src/commands/checklist.d.ts +42 -0
- package/dist/src/commands/checklist.js +168 -0
- package/dist/src/commands/cutover.d.ts +35 -0
- package/dist/src/commands/cutover.js +448 -0
- package/dist/src/commands/doctor.d.ts +264 -0
- package/dist/src/commands/doctor.js +1546 -0
- package/dist/src/commands/gates.d.ts +9 -0
- package/dist/src/commands/gates.js +360 -0
- package/dist/src/commands/init.d.ts +30 -0
- package/dist/src/commands/init.js +177 -0
- package/dist/src/commands/lock.d.ts +34 -0
- package/dist/src/commands/lock.js +340 -0
- package/dist/src/commands/mode.d.ts +40 -0
- package/dist/src/commands/mode.js +134 -0
- package/dist/src/commands/next.d.ts +130 -0
- package/dist/src/commands/next.js +597 -0
- package/dist/src/commands/plan.d.ts +20 -0
- package/dist/src/commands/plan.js +105 -0
- package/dist/src/commands/pool.d.ts +1 -0
- package/dist/src/commands/pool.js +139 -0
- package/dist/src/commands/resume.d.ts +1 -0
- package/dist/src/commands/resume.js +88 -0
- package/dist/src/commands/spawn.d.ts +1 -0
- package/dist/src/commands/spawn.js +195 -0
- package/dist/src/commands/status.d.ts +21 -0
- package/dist/src/commands/status.js +122 -0
- package/dist/src/commands/sync.d.ts +47 -0
- package/dist/src/commands/sync.js +341 -0
- package/dist/src/commands/teardown.d.ts +1 -0
- package/dist/src/commands/teardown.js +87 -0
- package/dist/src/commands/tuition.d.ts +21 -0
- package/dist/src/commands/tuition.js +218 -0
- package/dist/src/commands/validate.d.ts +78 -0
- package/dist/src/commands/validate.js +430 -0
- package/dist/src/commands/watch.d.ts +1 -0
- package/dist/src/commands/watch.js +172 -0
- package/dist/src/cutover.d.ts +584 -0
- package/dist/src/cutover.js +1444 -0
- package/dist/src/exclusion.d.ts +389 -0
- package/dist/src/exclusion.js +843 -0
- package/dist/src/exec/env.d.ts +278 -0
- package/dist/src/exec/env.js +334 -0
- package/dist/src/fleet.d.ts +223 -0
- package/dist/src/fleet.js +298 -0
- package/dist/src/gates/adapters/http-json.d.ts +5 -0
- package/dist/src/gates/adapters/http-json.js +283 -0
- package/dist/src/gates/adapters/migrations-command.d.ts +1 -0
- package/dist/src/gates/adapters/migrations-command.js +373 -0
- package/dist/src/gates/citations.d.ts +408 -0
- package/dist/src/gates/citations.js +1169 -0
- package/dist/src/gates/coverage.d.ts +375 -0
- package/dist/src/gates/coverage.js +836 -0
- package/dist/src/gates/credentials.d.ts +233 -0
- package/dist/src/gates/credentials.js +752 -0
- package/dist/src/gates/deploy.d.ts +1 -0
- package/dist/src/gates/deploy.js +33 -0
- package/dist/src/gates/gate-classes.d.ts +56 -0
- package/dist/src/gates/gate-classes.js +633 -0
- package/dist/src/gates/manifest.d.ts +99 -0
- package/dist/src/gates/manifest.js +208 -0
- package/dist/src/gates/merge-preconditions.d.ts +319 -0
- package/dist/src/gates/merge-preconditions.js +932 -0
- package/dist/src/gates/migrations.d.ts +1 -0
- package/dist/src/gates/migrations.js +36 -0
- package/dist/src/gates/pin.d.ts +114 -0
- package/dist/src/gates/pin.js +154 -0
- package/dist/src/gates/red-witness.d.ts +22 -0
- package/dist/src/gates/red-witness.js +482 -0
- package/dist/src/gates/release.d.ts +283 -0
- package/dist/src/gates/release.js +820 -0
- package/dist/src/gates/result.d.ts +116 -0
- package/dist/src/gates/result.js +91 -0
- package/dist/src/gates/run.d.ts +614 -0
- package/dist/src/gates/run.js +1614 -0
- package/dist/src/gates/schemas/citation-config.schema.json +59 -0
- package/dist/src/gates/schemas/coverage-config.schema.json +77 -0
- package/dist/src/gates/schemas/gate-manifest.schema.json +125 -0
- package/dist/src/gates/schemas/gate-result.schema.json +160 -0
- package/dist/src/gates/schemas/phase-declaration.schema.json +87 -0
- package/dist/src/gates/schemas/release-record.schema.json +119 -0
- package/dist/src/gates/schemas/verifier-config.schema.json +101 -0
- package/dist/src/gates/schemas/witness-spec.schema.json +110 -0
- package/dist/src/gates/scope.d.ts +131 -0
- package/dist/src/gates/scope.js +1018 -0
- package/dist/src/gates/suite.d.ts +217 -0
- package/dist/src/gates/suite.js +968 -0
- package/dist/src/gates/validate.d.ts +121 -0
- package/dist/src/gates/validate.js +414 -0
- package/dist/src/hooks.d.ts +84 -0
- package/dist/src/hooks.js +125 -0
- package/dist/src/index.d.ts +31 -0
- package/dist/src/index.js +30 -0
- package/dist/src/liveness.d.ts +321 -0
- package/dist/src/liveness.js +396 -0
- package/dist/src/lock.d.ts +256 -0
- package/dist/src/lock.js +792 -0
- package/dist/src/model-resolution.d.ts +159 -0
- package/dist/src/model-resolution.js +307 -0
- package/dist/src/modes.d.ts +149 -0
- package/dist/src/modes.js +258 -0
- package/dist/src/path-identity.d.ts +34 -0
- package/dist/src/path-identity.js +48 -0
- package/dist/src/plan.d.ts +73 -0
- package/dist/src/plan.js +153 -0
- package/dist/src/pool.d.ts +326 -0
- package/dist/src/pool.js +988 -0
- package/dist/src/roles.d.ts +461 -0
- package/dist/src/roles.js +776 -0
- package/dist/src/spawn.d.ts +482 -0
- package/dist/src/spawn.js +1003 -0
- package/dist/src/status.d.ts +116 -0
- package/dist/src/status.js +148 -0
- package/dist/src/task.d.ts +504 -0
- package/dist/src/task.js +307 -0
- package/dist/src/teardown.d.ts +39 -0
- package/dist/src/teardown.js +422 -0
- package/dist/src/tuition.d.ts +159 -0
- package/dist/src/tuition.js +311 -0
- package/dist/src/validate.d.ts +263 -0
- package/dist/src/validate.js +742 -0
- package/dist/src/version.d.ts +3 -0
- package/dist/src/version.js +38 -0
- package/dist/src/watcher.d.ts +275 -0
- package/dist/src/watcher.js +849 -0
- package/dist/src/witness/run.d.ts +299 -0
- package/dist/src/witness/run.js +1373 -0
- package/dist/src/witness/spec.d.ts +270 -0
- package/dist/src/witness/spec.js +475 -0
- package/dist/tsconfig.src.tsbuildinfo +1 -0
- package/gate-registry.yaml +526 -0
- package/gates.manifest.json +257 -0
- package/package.json +72 -3
- package/role-model-config.yaml +88 -0
- package/roles/README.md +128 -0
- package/roles/_shared-dispatch-contract.md +87 -0
- package/roles/adversarial-plan-reviewer.md +80 -0
- package/roles/clean-room-reviewer.md +140 -0
- package/roles/implementer.md +463 -0
- package/roles/investigator.md +138 -0
- package/roles/plan-writer.md +95 -0
- package/schemas/README.md +82 -0
- package/schemas/assurance-modes.schema.json +264 -0
- package/schemas/charter.schema.json +185 -0
- package/schemas/checklist.schema.json +114 -0
- package/schemas/cutover-state.schema.json +64 -0
- package/schemas/decision-record.schema.json +88 -0
- package/schemas/executor-record.schema.json +36 -0
- package/schemas/final-report.schema.json +90 -0
- package/schemas/finding.schema.json +106 -0
- package/schemas/gate-registry.schema.json +260 -0
- package/schemas/mechanism-index.schema.json +94 -0
- package/schemas/model-resolution.schema.json +362 -0
- package/schemas/plan.schema.json +300 -0
- package/schemas/report.schema.json +579 -0
- package/schemas/role-brief.schema.json +105 -0
- package/schemas/role-model-config.schema.json +90 -0
- package/schemas/status-line.schema.json +40 -0
- package/schemas/tuition.schema.json +191 -0
- package/schemas/verdict.schema.json +295 -0
- package/schemas/work-history.schema.json +183 -0
- package/schemas/write-bypass.schema.json +69 -0
- package/templates/charter.example.yaml +54 -0
- package/templates/decision-record.example.yaml +27 -0
- package/templates/final-report.example.yaml +80 -0
- package/templates/plan.example.yaml +87 -0
- package/templates/report.example.yaml +236 -0
- package/templates/warnings.md +74 -0
- package/templates/work-history.example.yaml +185 -0
- package/tuition/README.md +76 -0
- package/tuition/T-001.yaml +48 -0
- package/tuition/T-002.yaml +51 -0
- package/tuition/T-003.yaml +100 -0
- package/tuition/T-004.yaml +52 -0
- package/tuition/T-005.yaml +72 -0
- package/tuition/T-006.yaml +81 -0
- package/tuition/T-007.yaml +56 -0
- package/tuition/T-008.yaml +111 -0
- package/tuition/T-009.yaml +50 -0
- package/tuition/T-015.yaml +36 -0
- package/tuition/T-016.yaml +36 -0
- package/tuition/T-017.yaml +46 -0
- package/tuition/T-018.yaml +84 -0
- package/tuition/T-021.yaml +40 -0
- package/tuition/T-022.yaml +36 -0
- package/tuition/mechanism-index.yaml +256 -0
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import type { ChildEnvExtension } from "./exec/env.ts";
|
|
2
|
+
import type { Fleet } from "./fleet.ts";
|
|
3
|
+
import type { CredentialHandoverRecord, GuardResult, PayloadClass, TaskMeta, TaskShape } from "./task.ts";
|
|
4
|
+
/**
|
|
5
|
+
* tiphys spawn (kernel plan v1, M1-P4 step 4): worktree, brief, turn-end
|
|
6
|
+
* hook, task meta and the executor launch in ONE command.
|
|
7
|
+
*
|
|
8
|
+
* Order, exactly as the plan states it: liveness-guard check (M1-P5; a
|
|
9
|
+
* documented no-op seam in this phase), holdership check, pool create,
|
|
10
|
+
* brief assembly, meta write, executor launch. The holdership check runs
|
|
11
|
+
* before pool create because its refusal must create nothing
|
|
12
|
+
* (criterion 12).
|
|
13
|
+
*
|
|
14
|
+
* Rollback contract, stated narrowly because the broad version would not
|
|
15
|
+
* be honest (the lesson M1-P3's destroy paid for four times over):
|
|
16
|
+
*
|
|
17
|
+
* - A failure BEFORE pool create removes nothing, because nothing was
|
|
18
|
+
* created. In particular a duplicate task id leaves any pre-existing
|
|
19
|
+
* tasks/<id>/ byte-identical: this command writes nothing under
|
|
20
|
+
* tasks/ until pool create has succeeded (criterion 4, PR-005).
|
|
21
|
+
* - A failure AFTER pool create and BEFORE the payload starts removes
|
|
22
|
+
* exactly what this invocation created (the files it wrote, the task
|
|
23
|
+
* directory when it created it, and the pool worktree) and nothing
|
|
24
|
+
* else (criterion 5). This holds for a step that RETURNS a failure
|
|
25
|
+
* and for one that THROWS: every write in that window goes through
|
|
26
|
+
* runStep, because an unwrapped raise walked past the rollback
|
|
27
|
+
* entirely and orphaned the worktree, the branch and the pool record
|
|
28
|
+
* (F-2). The worktree is untouched at that point, so
|
|
29
|
+
* the removal passes the ordinary pool destroy gates and needs no
|
|
30
|
+
* force flag: --discard and --delete-branch-force are deliberately
|
|
31
|
+
* NOT passed, so a worktree that somehow is not pristine refuses and
|
|
32
|
+
* survives rather than being destroyed by a cleanup path.
|
|
33
|
+
* - Once the PAYLOAD HAS STARTED, nothing is ever rolled back. The
|
|
34
|
+
* worktree may hold real work by then, and a cleanup that removed it
|
|
35
|
+
* would be M1-P3's V-1 data-loss defect with a different name. A
|
|
36
|
+
* failure after that point reports what happened and changes
|
|
37
|
+
* nothing.
|
|
38
|
+
*
|
|
39
|
+
* Substrate: everything here is substrate-neutral except the executor,
|
|
40
|
+
* which sits behind ExecutorAdapter (DR-0007). M1 ships exactly one
|
|
41
|
+
* adapter, the local subprocess one.
|
|
42
|
+
*/
|
|
43
|
+
/** What the adapter is asked to do. Everything crosses as files and exit codes. */
|
|
44
|
+
export interface ExecutorRequest {
|
|
45
|
+
taskId: string;
|
|
46
|
+
/** cwd for the payload: the task worktree. */
|
|
47
|
+
worktree: string;
|
|
48
|
+
/** argv of the payload, argv[0] being the program. */
|
|
49
|
+
command: string[];
|
|
50
|
+
/** Script the adapter invokes with the payload exit code when it exits. */
|
|
51
|
+
hookPath: string;
|
|
52
|
+
/** Where the adapter writes its launch record. */
|
|
53
|
+
recordPath: string;
|
|
54
|
+
/** Optional non-completion deadline in seconds (PR-207). */
|
|
55
|
+
deadlineSeconds: number | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* The EXACT environment for BOTH children this launch produces: the
|
|
58
|
+
* payload and the turn-end hook (M2-P8, M2R-004 edit 4). Built by
|
|
59
|
+
* `buildChildEnv` (src/exec/env.ts): allowlisted names only, with the
|
|
60
|
+
* five credential-store pointers redirected to harness-owned paths.
|
|
61
|
+
* `undefined` means the children inherit the parent's environment
|
|
62
|
+
* UNCHANGED, and is only ever passed under `allowPrCredentials`, the
|
|
63
|
+
* declared escape hatch; an adapter must never widen it on its own.
|
|
64
|
+
*/
|
|
65
|
+
env: Record<string, string> | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* THE ASSEMBLED BRIEF, and it is NOT optional (M4-P3 criterion 1).
|
|
68
|
+
*
|
|
69
|
+
* The brief is the agent payload's entire input, and until this phase the
|
|
70
|
+
* request did not carry it at all, although the call site already had it:
|
|
71
|
+
* `assembleBrief` returns the path and `spawnTask` pushes it onto
|
|
72
|
+
* `createdFiles` before the launch. So an optional `briefPath` would be an
|
|
73
|
+
* optionality the kernel never exercises, which is a field that cannot go
|
|
74
|
+
* red: every production path supplies it and no test could construct the
|
|
75
|
+
* absent case without inventing one.
|
|
76
|
+
*
|
|
77
|
+
* The three fields below it are `string | undefined` for the opposite
|
|
78
|
+
* reason: nothing in the kernel produces them, they arrive from the caller,
|
|
79
|
+
* and an adapter that needs one says so through `requires` rather than
|
|
80
|
+
* hoping.
|
|
81
|
+
*/
|
|
82
|
+
briefPath: string;
|
|
83
|
+
/**
|
|
84
|
+
* The role the payload is being asked to play, verbatim as the caller named
|
|
85
|
+
* it. The kernel neither interprets it nor holds a vocabulary for it; the
|
|
86
|
+
* role briefs are a shipped artifact and the mapping from a role to a brief
|
|
87
|
+
* is the plugin's business.
|
|
88
|
+
*/
|
|
89
|
+
role: string | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* THE DECLARED TIER, VERBATIM, AND NEVER A MODEL NAME (M4-P3, the
|
|
92
|
+
* zero-vendor-names requirement). Whatever `role-model-config.yaml`
|
|
93
|
+
* declares, `strongest` or `cheaper` or anything else, crosses this seam
|
|
94
|
+
* unaltered. The tier-to-model mapping lives in the plugin: a mapping in
|
|
95
|
+
* `src/` is what would close off every harness that is not the one it names
|
|
96
|
+
* (delivery/plan/m4-intake.md:377).
|
|
97
|
+
*/
|
|
98
|
+
declaredTier: string | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* The delivery phase this task belongs to, CARRIED and never DERIVED.
|
|
101
|
+
*
|
|
102
|
+
* The scope gate derives a phase id from a branch name, and M4-D-22 leaves
|
|
103
|
+
* open whether that convention is the kernel's or the delivering project's.
|
|
104
|
+
* A kernel that derived the phase id from a branch here would settle
|
|
105
|
+
* M4-D-22 by accident, and a shipped constant is the hardest kind of
|
|
106
|
+
* decision to renumber.
|
|
107
|
+
*/
|
|
108
|
+
phaseId: string | undefined;
|
|
109
|
+
}
|
|
110
|
+
/** The closed set of names an adapter may name in `requires`, in field order. */
|
|
111
|
+
export declare function requirableRequestFields(): readonly string[];
|
|
112
|
+
/**
|
|
113
|
+
* THE ADAPTER CONTRACT CHECK (M4-P3 criterion 3): a requirement naming a
|
|
114
|
+
* field that does not exist is a DEFECT IN THE ADAPTER, refused when the
|
|
115
|
+
* adapter is taken up and before anything is created.
|
|
116
|
+
*
|
|
117
|
+
* IT IS A DIFFERENT QUESTION FROM `checkAdapterRequirements` BELOW, AND THE
|
|
118
|
+
* ORDER IS LOAD-BEARING. The presence test there answers "is this field
|
|
119
|
+
* absent", and an unknown key is absent too, so a single check written that
|
|
120
|
+
* way would answer a defect in the adapter with a message about a missing
|
|
121
|
+
* flag: an operator would go looking for a `--modelName` that the kernel has
|
|
122
|
+
* no field for and could never accept. Running this one FIRST is what keeps
|
|
123
|
+
* the two answers distinct, and `test/spawn.test.ts` asserts that they say
|
|
124
|
+
* structurally different things rather than merely both refusing.
|
|
125
|
+
*/
|
|
126
|
+
export declare function checkAdapterContract(adapter: ExecutorAdapter): {
|
|
127
|
+
ok: true;
|
|
128
|
+
} | {
|
|
129
|
+
ok: false;
|
|
130
|
+
reason: string;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* THE DECLARED-REQUIREMENT CHECK (M4-P3 criterion 2): a field the adapter
|
|
134
|
+
* declared it needs, and the spawn was not given, is a USAGE ERROR, and a
|
|
135
|
+
* usage error creates nothing.
|
|
136
|
+
*
|
|
137
|
+
* THE DANGEROUS STATE THIS EXISTS FOR is not "an adapter gets undefined". It
|
|
138
|
+
* is an adapter DISCOVERING that it got undefined, and raising, after pool
|
|
139
|
+
* create has already made a worktree, a branch and a pool record. That is the
|
|
140
|
+
* measured `--deadline` defect at src/commands/spawn.ts:81 with a new field:
|
|
141
|
+
* a value the kernel could not represent used to raise inside the adapter,
|
|
142
|
+
* after the creation, and the repair was to refuse at parse time. This is the
|
|
143
|
+
* same repair one field along, and it is the reason the check runs at the top
|
|
144
|
+
* of `spawnTask` rather than beside the launch where the request is built.
|
|
145
|
+
*/
|
|
146
|
+
export declare function checkAdapterRequirements(adapter: ExecutorAdapter, options: SpawnOptions): {
|
|
147
|
+
ok: true;
|
|
148
|
+
} | {
|
|
149
|
+
ok: false;
|
|
150
|
+
reason: string;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* THE CREDENTIAL POLICY CHECK (M4-P8 steps 2, 3 and 5), and it runs before
|
|
154
|
+
* ANYTHING is resolved, loaded or created.
|
|
155
|
+
*
|
|
156
|
+
* Three refusals, in this order, and the order is the fail-closed one:
|
|
157
|
+
*
|
|
158
|
+
* 1. an absent or unrecognised `payloadClass`. Checked first so that
|
|
159
|
+
* refusal 2 never has to reason about an unknown value: without this,
|
|
160
|
+
* `payloadClass !== "project"` would read an omission as permission.
|
|
161
|
+
* 2. the declared escape hatch asked for on a PROJECT payload. This is
|
|
162
|
+
* the pairing the phase exists to refuse: `allowPrCredentials` hands
|
|
163
|
+
* the parent environment over UNCHANGED (see ExecutorRequest.env),
|
|
164
|
+
* credentials and all, and M2-P8 criterion 1 wrote it for the
|
|
165
|
+
* orchestrator's own spawns only. Until this phase the option was
|
|
166
|
+
* reachable from the library seam with nothing between it and a
|
|
167
|
+
* project payload.
|
|
168
|
+
* 3. an extension entry the child must not carry, which is the same
|
|
169
|
+
* vocabulary check `buildChildEnv` makes, made EARLIER. The
|
|
170
|
+
* duplication is deliberate and is not two implementations: both call
|
|
171
|
+
* `refuseExtraAllowlist`. Making it here as well is what keeps a
|
|
172
|
+
* rejected widening from costing a worktree, a branch and a pool
|
|
173
|
+
* record, because `buildChildEnv` does not run until after pool
|
|
174
|
+
* create.
|
|
175
|
+
*
|
|
176
|
+
* It returns a reason rather than throwing, because every refusal on this
|
|
177
|
+
* path must be able to say "nothing was created" in the same sentence.
|
|
178
|
+
*/
|
|
179
|
+
export declare function checkCredentialPolicy(options: SpawnOptions): {
|
|
180
|
+
ok: true;
|
|
181
|
+
} | {
|
|
182
|
+
ok: false;
|
|
183
|
+
reason: string;
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Pointer evidence: what the five credential-store redirections actually
|
|
187
|
+
* were where the payload ran, and where that observation came from.
|
|
188
|
+
*/
|
|
189
|
+
export interface RedirectionEvidence {
|
|
190
|
+
source: "turn-end-record" | "adapter";
|
|
191
|
+
/** Observed value per name; `null` for a name that was unset. */
|
|
192
|
+
values: Readonly<Record<string, string | null>>;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* COMPARE THE HANDOVER (M4-P8 criterion 6, repaired for CR-B-001).
|
|
196
|
+
*
|
|
197
|
+
* `handed` is what the kernel built and passed, `reported` is the name set
|
|
198
|
+
* the adapter says it launched with, `pointers` is what the five
|
|
199
|
+
* CREDENTIAL_STORE_REDIRECTIONS actually were where the payload ran.
|
|
200
|
+
*
|
|
201
|
+
* TWO PROPERTIES, AND THE STATUS SAYS WHICH WERE CHECKED. The name-set
|
|
202
|
+
* comparison alone used to be written down as `compared`, which an operator
|
|
203
|
+
* reads as "the handover was verified"; an adapter that keeps the name set
|
|
204
|
+
* byte-identical and puts `HOME` and `XDG_CONFIG_HOME` back to their real
|
|
205
|
+
* paths defeats the M2R-004 defense entirely and was recorded as clean. See
|
|
206
|
+
* `CredentialHandoverRecord` for the five status values and for why the
|
|
207
|
+
* VALUES are still never written into the record.
|
|
208
|
+
*
|
|
209
|
+
* The pointer comparison is by value and the values are DISCARDED: only the
|
|
210
|
+
* names that differ survive into `changedRedirections`. A name the kernel
|
|
211
|
+
* never handed over is not compared, because there is no handed value to
|
|
212
|
+
* compare it against, and the name-set arms are what speak to that case.
|
|
213
|
+
*/
|
|
214
|
+
export declare function compareHandover(handed: Record<string, string> | undefined, reported: readonly string[] | undefined, pointers?: RedirectionEvidence): CredentialHandoverRecord;
|
|
215
|
+
/**
|
|
216
|
+
* Launch outcomes. The distinction between a payload that never started
|
|
217
|
+
* and one that did is load-bearing: only the first authorizes rollback.
|
|
218
|
+
*/
|
|
219
|
+
export type LaunchOutcome = {
|
|
220
|
+
kind: "completed";
|
|
221
|
+
exitCode: number;
|
|
222
|
+
/**
|
|
223
|
+
* THE NAMES THE ADAPTER REPORTS IT ACTUALLY LAUNCHED WITH (M4-P8
|
|
224
|
+
* criterion 6). Optional, and the optionality is honest rather than
|
|
225
|
+
* lenient: an adapter written before this phase reports nothing, and
|
|
226
|
+
* a kernel that refused every silent adapter would be refusing on an
|
|
227
|
+
* absence of evidence. What the kernel DOES refuse is a reported set
|
|
228
|
+
* that DIFFERS from the one it handed over, which is the adapter
|
|
229
|
+
* saying, in its own record, that it widened the environment.
|
|
230
|
+
*
|
|
231
|
+
* It is NOT on `ExecutorRecord`: that document has a shipped schema
|
|
232
|
+
* with `additionalProperties: false`, and this value is a report to
|
|
233
|
+
* the kernel rather than a durable launch fact for an operator.
|
|
234
|
+
*
|
|
235
|
+
* A DISHONEST ADAPTER IS NOT CAUGHT HERE, and nothing in this field
|
|
236
|
+
* pretends otherwise: an adapter that widens `env` and reports the
|
|
237
|
+
* kernel's set is caught by the child-written probe instead, which
|
|
238
|
+
* is why criterion 5 asserts on a file the CHILD wrote.
|
|
239
|
+
*/
|
|
240
|
+
launchedEnvNames?: readonly string[];
|
|
241
|
+
/**
|
|
242
|
+
* THE FIVE CREDENTIAL-STORE POINTERS AS THE ADAPTER LAUNCHED THEM
|
|
243
|
+
* (CR-B-001). Optional for the same honest reason `launchedEnvNames`
|
|
244
|
+
* is, and WEAKER than the kernel's own evidence: it is the adapter's
|
|
245
|
+
* word about its own behaviour. The kernel prefers the turn-end record
|
|
246
|
+
* the generated hook normally writes and falls back to this, and the
|
|
247
|
+
* record says which ARTIFACT it read (`redirectionSource`). That is a
|
|
248
|
+
* weaker claim than which PARTY observed the values, and it used to be
|
|
249
|
+
* spelled as the stronger one; see CredentialHandoverRecord in
|
|
250
|
+
* src/task.ts for the measurement that changed the word.
|
|
251
|
+
*/
|
|
252
|
+
launchedRedirections?: Readonly<Record<string, string | null>>;
|
|
253
|
+
} | {
|
|
254
|
+
kind: "launch-failed";
|
|
255
|
+
reason: string;
|
|
256
|
+
} | {
|
|
257
|
+
kind: "incomplete";
|
|
258
|
+
reason: string;
|
|
259
|
+
/**
|
|
260
|
+
* WHAT AN ADAPTER THAT COULD NOT CONFIRM COMPLETION STILL LAUNCHED
|
|
261
|
+
* WITH (CR-B-003). The payload RAN on this arm, so the handover is a
|
|
262
|
+
* real question here and the kernel now asks it; before this round the
|
|
263
|
+
* comparison sat after the `incomplete` return and `meta.json` carried
|
|
264
|
+
* no `handover` key at all, so a widening on this arm was recorded
|
|
265
|
+
* nowhere. Optional for the same reason as on the `completed` arm.
|
|
266
|
+
*/
|
|
267
|
+
launchedEnvNames?: readonly string[];
|
|
268
|
+
launchedRedirections?: Readonly<Record<string, string | null>>;
|
|
269
|
+
};
|
|
270
|
+
/**
|
|
271
|
+
* The ExecutorAdapter interface (DR-0007, M1-P4 grounding). The ENTIRE
|
|
272
|
+
* contract is: write the launch record tasks/<id>/executor.json at
|
|
273
|
+
* launch, launch the payload in the task worktree, and ensure the
|
|
274
|
+
* turn-end file is written with the payload exit code on completion. All
|
|
275
|
+
* state crosses this boundary through files and exit codes, never
|
|
276
|
+
* through terminal inspection (FM-055: pane scraping is a race farm;
|
|
277
|
+
* FM-060: every toolbelt boundary is a subprocess with an exit code).
|
|
278
|
+
* A multiplexer-window adapter and a cloud-session adapter are further
|
|
279
|
+
* adapters against this same interface, not kernel changes (M4 era).
|
|
280
|
+
*/
|
|
281
|
+
export interface ExecutorAdapter {
|
|
282
|
+
readonly name: string;
|
|
283
|
+
/**
|
|
284
|
+
* WHAT THIS ADAPTER CANNOT LAUNCH WITHOUT (M4-P3 criteria 2 and 3).
|
|
285
|
+
*
|
|
286
|
+
* Every name is a field of `ExecutorRequest`. The kernel cannot know what
|
|
287
|
+
* a given adapter needs, so the adapter DECLARES it and the kernel refuses
|
|
288
|
+
* BEFORE it creates anything, rather than handing over an `undefined` that
|
|
289
|
+
* the adapter discovers once a worktree, a branch and a pool record exist.
|
|
290
|
+
*
|
|
291
|
+
* REQUIRED, never optional: an optional declaration would let an adapter
|
|
292
|
+
* omit it and get the old behaviour back silently, which is the thing this
|
|
293
|
+
* field exists to stop. An adapter that needs nothing declares `[]`, and
|
|
294
|
+
* that is a statement rather than a default.
|
|
295
|
+
*/
|
|
296
|
+
readonly requires: readonly string[];
|
|
297
|
+
/**
|
|
298
|
+
* ASYNCHRONOUS since M4-P2. An agent turn is long and a subprocess is
|
|
299
|
+
* short: a window adapter or a cloud-session adapter cannot express
|
|
300
|
+
* "the turn ended" in a synchronous return, so the signature that only
|
|
301
|
+
* ever fitted the local subprocess case is the one that changes.
|
|
302
|
+
*
|
|
303
|
+
* This is NOT permission to background (constraint C-3). The kernel
|
|
304
|
+
* AWAITS this promise inside `spawnTask`, so the command still ends
|
|
305
|
+
* after the payload does; awaiting a call is not outliving it, and
|
|
306
|
+
* delivery/plan/kernel-plan-v1.md:311 already puts process ownership in
|
|
307
|
+
* the harness rather than the kernel.
|
|
308
|
+
*
|
|
309
|
+
* The three-armed outcome is unchanged and is still the whole contract:
|
|
310
|
+
* only `launch-failed` authorises rollback, because only `launch-failed`
|
|
311
|
+
* asserts that the payload never started. An adapter that cannot tell
|
|
312
|
+
* returns `incomplete` and the kernel touches nothing. What DID change
|
|
313
|
+
* is that `completed` is no longer taken on the adapter's word: see the
|
|
314
|
+
* completion precondition in `spawnTask`.
|
|
315
|
+
*/
|
|
316
|
+
launch(request: ExecutorRequest): Promise<LaunchOutcome>;
|
|
317
|
+
}
|
|
318
|
+
/** The launch record (JSON per DR-0006, shape per PR-207). */
|
|
319
|
+
export interface ExecutorRecord {
|
|
320
|
+
adapter: string;
|
|
321
|
+
launchedAt: string;
|
|
322
|
+
/**
|
|
323
|
+
* Absolute ISO-8601 instant by which the task must have completed,
|
|
324
|
+
* present only when --deadline was passed. Recorded as an instant
|
|
325
|
+
* rather than as the raw seconds so the M1-P5 watcher compares it
|
|
326
|
+
* against the clock directly, the way it already compares lease
|
|
327
|
+
* expiry, instead of re-deriving it from launchedAt. The plan fixes
|
|
328
|
+
* the field name and its optionality, not its units; this is the
|
|
329
|
+
* choice, recorded rather than assumed.
|
|
330
|
+
*/
|
|
331
|
+
deadline?: string;
|
|
332
|
+
/**
|
|
333
|
+
* WHAT WAS REQUESTED, NOT WHAT WAS RESOLVED (M4-P3 criterion 6).
|
|
334
|
+
*
|
|
335
|
+
* The declared tier the request carried, copied verbatim. Optional in the
|
|
336
|
+
* same sense `deadline` is: present exactly when the request carried one,
|
|
337
|
+
* absent otherwise, never the string "undefined".
|
|
338
|
+
*
|
|
339
|
+
* THERE IS NO RESOLVED MODEL HERE, and the absence is a decision rather
|
|
340
|
+
* than an omission. This record is written BEFORE the payload starts,
|
|
341
|
+
* which is the whole basis of the launch-failed-versus-incomplete
|
|
342
|
+
* distinction, while a harness that requests one model and is served
|
|
343
|
+
* another resolves mid-turn. A resolved model in a launch record would
|
|
344
|
+
* therefore be a value nobody could have observed at the moment it was
|
|
345
|
+
* written. M4-P7 carries the resolved half, at turn end, where it can be
|
|
346
|
+
* true.
|
|
347
|
+
*/
|
|
348
|
+
requestedTier?: string;
|
|
349
|
+
/** The role the request carried, copied verbatim. See `requestedTier`. */
|
|
350
|
+
requestedRole?: string;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* The local subprocess adapter, the one M1 ships (and the one the exit
|
|
354
|
+
* test's stub payload uses).
|
|
355
|
+
*
|
|
356
|
+
* The payload runs to COMPLETION before this returns: the kernel never
|
|
357
|
+
* auto-backgrounds anything (plan constraint C-3, FM-054), so there is
|
|
358
|
+
* no daemonize path here to forget to guard.
|
|
359
|
+
*
|
|
360
|
+
* `async` since M4-P2, and its BODY IS UNCHANGED: every statement below
|
|
361
|
+
* is still synchronous, `spawnSync` is still what runs both children, and
|
|
362
|
+
* the promise this now returns is already settled by the time the first
|
|
363
|
+
* `await` on it runs. The keyword is there because the INTERFACE is async
|
|
364
|
+
* for the adapters that need it, not because this adapter gained a
|
|
365
|
+
* concurrency path to get wrong.
|
|
366
|
+
*
|
|
367
|
+
* It runs without a shell on purpose. Under a shell a missing payload
|
|
368
|
+
* binary arrives as an ordinary exit code 127, indistinguishable from a
|
|
369
|
+
* payload that ran and failed, and spawn's rollback rule turns on
|
|
370
|
+
* exactly that distinction.
|
|
371
|
+
*/
|
|
372
|
+
export declare const subprocessAdapter: ExecutorAdapter;
|
|
373
|
+
/**
|
|
374
|
+
* Liveness-guard seam (plan step 4). The guard itself is M1-P5 work; in
|
|
375
|
+
* this phase it is a documented no-op, so that P5 adds a body here
|
|
376
|
+
* rather than a new call site in the middle of the spawn sequence.
|
|
377
|
+
*/
|
|
378
|
+
export declare function livenessGuard(fleet: Fleet): GuardResult;
|
|
379
|
+
/**
|
|
380
|
+
* Tokenise --exec. M1 supports a program plus plain arguments separated
|
|
381
|
+
* by whitespace; there is no shell and no quoting. Anything richer is an
|
|
382
|
+
* adapter's business (M4 era), not a string this kernel re-parses.
|
|
383
|
+
*/
|
|
384
|
+
export declare function parseExecCommand(command: string): string[];
|
|
385
|
+
export interface SpawnOptions {
|
|
386
|
+
taskId: string;
|
|
387
|
+
project: string;
|
|
388
|
+
briefFile: string;
|
|
389
|
+
shape: TaskShape;
|
|
390
|
+
exec: string;
|
|
391
|
+
deadlineSeconds: number | undefined;
|
|
392
|
+
/** Passed straight through to pool create (EXT-F-03); see spawnTask. */
|
|
393
|
+
offline: boolean;
|
|
394
|
+
/**
|
|
395
|
+
* DECLARED ESCAPE HATCH from the credential scrub (M2-P8 criterion 1).
|
|
396
|
+
* When true, both children inherit the parent environment unchanged,
|
|
397
|
+
* including any pull-request-capable credential the parent holds. This
|
|
398
|
+
* exists for the orchestrator's own spawns, never for an implementer
|
|
399
|
+
* payload; default is false and the scrub is on.
|
|
400
|
+
*/
|
|
401
|
+
allowPrCredentials?: boolean;
|
|
402
|
+
/**
|
|
403
|
+
* WHOSE AUTHORITY THIS PAYLOAD RUNS UNDER (M4-P8 step 2). REQUIRED, and
|
|
404
|
+
* there is NO DEFAULT anywhere on this path, in the type or at runtime.
|
|
405
|
+
*
|
|
406
|
+
* A default would be the whole defect: `allowPrCredentials` is reachable
|
|
407
|
+
* from the library seam, which is where the plugin sits, and the pairing
|
|
408
|
+
* this field exists to refuse is the escape hatch on a project payload.
|
|
409
|
+
* If omission meant "orchestrator", a caller would acquire the
|
|
410
|
+
* orchestrator's authority by leaving a field out, which is the quietest
|
|
411
|
+
* way there is to reach a credential. `spawnTask` therefore refuses an
|
|
412
|
+
* absent or unrecognised value before it creates or loads anything,
|
|
413
|
+
* rather than trusting the type: TypeScript is a compile-time promise and
|
|
414
|
+
* the consumer that matters here is a JavaScript plugin.
|
|
415
|
+
*/
|
|
416
|
+
payloadClass: PayloadClass;
|
|
417
|
+
/**
|
|
418
|
+
* PER-INVOCATION ALLOWLIST EXTENSIONS, EACH WITH THE REASON IT WAS
|
|
419
|
+
* GRANTED (M4-P8 step 3). Absent means none, which is the measured
|
|
420
|
+
* minimum for model authentication in the probed container
|
|
421
|
+
* (delivery/verification/m4-prototype-probes.md:33).
|
|
422
|
+
*
|
|
423
|
+
* The reason is DATA and a blank one is refused, so a widening cannot be
|
|
424
|
+
* granted without leaving behind something a later reader can check; the
|
|
425
|
+
* granted set is copied into meta.json verbatim. The kernel refuses any
|
|
426
|
+
* entry naming a variable in the walked gh-token or dangerous vocabulary,
|
|
427
|
+
* so this field cannot be used to re-admit a credential.
|
|
428
|
+
*/
|
|
429
|
+
extraAllowlist?: readonly ChildEnvExtension[];
|
|
430
|
+
/**
|
|
431
|
+
* The three caller-supplied request fields (M4-P3 criterion 1, M4-D-05).
|
|
432
|
+
* Each is `string | undefined` because nothing in the kernel produces one;
|
|
433
|
+
* `briefPath` is not here because `assembleBrief` does produce it.
|
|
434
|
+
*/
|
|
435
|
+
role: string | undefined;
|
|
436
|
+
declaredTier: string | undefined;
|
|
437
|
+
phaseId: string | undefined;
|
|
438
|
+
/**
|
|
439
|
+
* AN ADAPTER OBJECT SUPPLIED DIRECTLY, which only the kernel's own tests
|
|
440
|
+
* do. It outranks `adapterSpecifier` because it is not a request to
|
|
441
|
+
* resolve anything: there is nothing to root, nothing to load, and no
|
|
442
|
+
* trust boundary to cross.
|
|
443
|
+
*/
|
|
444
|
+
adapter?: ExecutorAdapter;
|
|
445
|
+
/**
|
|
446
|
+
* THE `--adapter` SPECIFIER, verbatim as the operator typed it (M4-P4
|
|
447
|
+
* criterion 1). `undefined` means the flag was absent, which is NOT the
|
|
448
|
+
* same as an empty one: an absent flag falls through to the fleet home's
|
|
449
|
+
* declared default and then to the built-in adapter, and each of those
|
|
450
|
+
* three outcomes is named in the launch record rather than being silent
|
|
451
|
+
* (criterion 6).
|
|
452
|
+
*
|
|
453
|
+
* The specifier is not resolved here. It is handed to `selectAdapter`,
|
|
454
|
+
* which roots Node module resolution at the FLEET HOME and never at the
|
|
455
|
+
* project clone; see src/adapters/load.ts for why that root is the whole
|
|
456
|
+
* security property of this phase.
|
|
457
|
+
*/
|
|
458
|
+
adapterSpecifier?: string;
|
|
459
|
+
}
|
|
460
|
+
export interface SpawnSuccess {
|
|
461
|
+
meta: TaskMeta;
|
|
462
|
+
exitCode: number;
|
|
463
|
+
}
|
|
464
|
+
export type SpawnResult = {
|
|
465
|
+
ok: true;
|
|
466
|
+
value: SpawnSuccess;
|
|
467
|
+
} | {
|
|
468
|
+
ok: false;
|
|
469
|
+
reason: string;
|
|
470
|
+
};
|
|
471
|
+
/**
|
|
472
|
+
* One spawn. See the module docs for the rollback contract.
|
|
473
|
+
*
|
|
474
|
+
* --offline is passed straight through to pool create and is the only
|
|
475
|
+
* way a fleet can reach an offline base. meta.baseOffline is then COPIED
|
|
476
|
+
* from the pool record the create returned, never recomputed from this
|
|
477
|
+
* flag: pool create attempts the fetch even under --offline and records
|
|
478
|
+
* offline false when it succeeds, so a spawn that trusted its own flag
|
|
479
|
+
* would mark a perfectly fetched base as offline (PR-212, and the
|
|
480
|
+
* provenance inversion measured as V-2 in M1-P3).
|
|
481
|
+
*/
|
|
482
|
+
export declare function spawnTask(fleet: Fleet, options: SpawnOptions): Promise<SpawnResult>;
|