instar 1.3.937 → 1.3.939
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +7 -2
- package/dist/commands/server.js.map +1 -1
- package/dist/core/githubRuntime.d.ts +96 -0
- package/dist/core/githubRuntime.d.ts.map +1 -0
- package/dist/core/githubRuntime.js +213 -0
- package/dist/core/githubRuntime.js.map +1 -0
- package/dist/core/ropeHealth.d.ts +15 -0
- package/dist/core/ropeHealth.d.ts.map +1 -1
- package/dist/core/ropeHealth.js +17 -0
- package/dist/core/ropeHealth.js.map +1 -1
- package/dist/monitoring/CiFailurePoller.d.ts +30 -1
- package/dist/monitoring/CiFailurePoller.d.ts.map +1 -1
- package/dist/monitoring/CiFailurePoller.js +5 -2
- package/dist/monitoring/CiFailurePoller.js.map +1 -1
- package/dist/monitoring/MergeRunner.d.ts +5 -0
- package/dist/monitoring/MergeRunner.d.ts.map +1 -1
- package/dist/monitoring/MergeRunner.js +10 -2
- package/dist/monitoring/MergeRunner.js.map +1 -1
- package/dist/monitoring/greenPrAutomergeWiring.d.ts +3 -0
- package/dist/monitoring/greenPrAutomergeWiring.d.ts.map +1 -1
- package/dist/monitoring/greenPrAutomergeWiring.js +15 -9
- package/dist/monitoring/greenPrAutomergeWiring.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +2 -1
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/throughputRoutes.d.ts +11 -7
- package/dist/server/throughputRoutes.d.ts.map +1 -1
- package/dist/server/throughputRoutes.js +99 -29
- package/dist/server/throughputRoutes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +3 -3
- package/upgrades/1.3.938.md +22 -0
- package/upgrades/1.3.939.md +33 -0
- package/upgrades/side-effects/mesh-handback-rope-health-wiring.md +38 -0
- package/upgrades/side-effects/throughput-github-runtime-repair.md +155 -0
|
@@ -6,17 +6,18 @@ type Weights = {
|
|
|
6
6
|
quality: number;
|
|
7
7
|
output: number;
|
|
8
8
|
};
|
|
9
|
-
type
|
|
10
|
-
code: number;
|
|
11
|
-
stdout: string;
|
|
12
|
-
stderr: string;
|
|
13
|
-
}>;
|
|
9
|
+
export type ThroughputGraphql = (query: string, variables: Record<string, unknown>) => Promise<unknown>;
|
|
14
10
|
export declare const DEFAULT_THROUGHPUT_WEIGHTS: Weights;
|
|
11
|
+
export declare function pacificDay(iso: string): string;
|
|
15
12
|
/** Canonical server-owned implementation of Echo's throughput-metrics.mjs contract. */
|
|
16
13
|
export declare function buildThroughputSeries(opts: {
|
|
17
14
|
days: 7 | 14 | 30;
|
|
18
15
|
now?: Date;
|
|
19
|
-
|
|
16
|
+
graphql?: ThroughputGraphql;
|
|
17
|
+
stateDir?: string;
|
|
18
|
+
env?: NodeJS.ProcessEnv;
|
|
19
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
20
|
+
resolveToken?: () => string | null;
|
|
20
21
|
weights?: Weights;
|
|
21
22
|
}): Promise<{
|
|
22
23
|
repo: string;
|
|
@@ -46,7 +47,10 @@ export declare function buildThroughputSeries(opts: {
|
|
|
46
47
|
}[];
|
|
47
48
|
}>;
|
|
48
49
|
export declare function createThroughputRoutes(options?: {
|
|
49
|
-
|
|
50
|
+
graphql?: ThroughputGraphql;
|
|
51
|
+
stateDir?: string;
|
|
52
|
+
env?: NodeJS.ProcessEnv;
|
|
53
|
+
fetchImpl?: typeof globalThis.fetch;
|
|
50
54
|
weights?: Weights;
|
|
51
55
|
}): Router;
|
|
52
56
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throughputRoutes.d.ts","sourceRoot":"","sources":["../../src/server/throughputRoutes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"throughputRoutes.d.ts","sourceRoot":"","sources":["../../src/server/throughputRoutes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA+B,MAAM,SAAS,CAAC;AAgB9D,KAAK,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AACzC,KAAK,OAAO,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACpF,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAqBxG,eAAO,MAAM,0BAA0B,EAAE,OAAkE,CAAC;AAsC5G,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG9C;AAiDD,uFAAuF;AACvF,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;IAClB,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCA;AAED,wBAAgB,sBAAsB,CAAC,OAAO,GAAE;IAC9C,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;CACd,GAAG,MAAM,CAwBd"}
|
|
@@ -1,11 +1,30 @@
|
|
|
1
|
-
import { execFile } from 'node:child_process';
|
|
2
1
|
import { Router } from 'express';
|
|
2
|
+
import { createGitHubTokenResolver, fetchGitHubGraphql, GitHubAuthUnavailableError, resolveGitHubToken, } from '../core/githubRuntime.js';
|
|
3
3
|
export const DEFAULT_THROUGHPUT_WEIGHTS = { velocity: .40, speed: .20, quality: .25, output: .15 };
|
|
4
4
|
const WINDOWS = [7, 14, 30];
|
|
5
|
+
const MAX_SEARCH_PAGES = 10;
|
|
6
|
+
const THROUGHPUT_QUERY = `
|
|
7
|
+
query ThroughputPullRequests($query: String!, $cursor: String) {
|
|
8
|
+
search(query: $query, type: ISSUE, first: 100, after: $cursor) {
|
|
9
|
+
issueCount
|
|
10
|
+
nodes {
|
|
11
|
+
... on PullRequest {
|
|
12
|
+
number
|
|
13
|
+
title
|
|
14
|
+
author { login }
|
|
15
|
+
mergedAt
|
|
16
|
+
createdAt
|
|
17
|
+
additions
|
|
18
|
+
deletions
|
|
19
|
+
reviews(first: 30) { nodes { state } }
|
|
20
|
+
commits { totalCount }
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
pageInfo { hasNextPage endCursor }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
5
27
|
const ZERO = () => ({ merges: 0, medianLatencyH: 0, reworkLoops: 0, reverts: 0, medianPushIters: 0, medianLoc: 0 });
|
|
6
|
-
function gh(args) {
|
|
7
|
-
return new Promise(resolve => execFile('gh', args, { timeout: 30_000, maxBuffer: 32 * 1024 * 1024 }, (err, stdout, stderr) => resolve({ code: err ? 1 : 0, stdout: stdout ?? '', stderr: stderr ?? '' })));
|
|
8
|
-
}
|
|
9
28
|
function median(values) {
|
|
10
29
|
if (!values.length)
|
|
11
30
|
return 0;
|
|
@@ -14,7 +33,16 @@ function median(values) {
|
|
|
14
33
|
return Math.round((a.length % 2 ? a[m] : (a[m - 1] + a[m]) / 2) * 10) / 10;
|
|
15
34
|
}
|
|
16
35
|
function authorOf(login) { return login === 'JKHeadley' ? 'codey' : login === 'EchoOfDawn' ? 'echo' : 'other'; }
|
|
17
|
-
|
|
36
|
+
const PACIFIC_DAY = new Intl.DateTimeFormat('en-US', {
|
|
37
|
+
timeZone: 'America/Los_Angeles',
|
|
38
|
+
year: 'numeric',
|
|
39
|
+
month: '2-digit',
|
|
40
|
+
day: '2-digit',
|
|
41
|
+
});
|
|
42
|
+
export function pacificDay(iso) {
|
|
43
|
+
const parts = Object.fromEntries(PACIFIC_DAY.formatToParts(new Date(iso)).map((part) => [part.type, part.value]));
|
|
44
|
+
return `${parts.year}-${parts.month}-${parts.day}`;
|
|
45
|
+
}
|
|
18
46
|
function metrics(prs, details) {
|
|
19
47
|
return {
|
|
20
48
|
merges: prs.length,
|
|
@@ -25,38 +53,68 @@ function metrics(prs, details) {
|
|
|
25
53
|
medianLoc: median(prs.map(p => p.additions + p.deletions)),
|
|
26
54
|
};
|
|
27
55
|
}
|
|
28
|
-
async function
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
continue;
|
|
41
|
-
out.set(n, { reworkLoops: (p.reviews?.nodes ?? []).filter((x) => x.state === 'CHANGES_REQUESTED').length, commits: Number(p.commits?.totalCount ?? 0) });
|
|
56
|
+
async function listMergedPullRequests(graphql, cutoff, now) {
|
|
57
|
+
const searchQuery = `repo:JKHeadley/instar is:pr is:merged merged:>=${new Date(cutoff).toISOString().slice(0, 10)} sort:updated-desc`;
|
|
58
|
+
const prs = [];
|
|
59
|
+
let expectedCount = null;
|
|
60
|
+
let fetchedCount = 0;
|
|
61
|
+
let cursor = null;
|
|
62
|
+
for (let page = 0; page < MAX_SEARCH_PAGES; page += 1) {
|
|
63
|
+
const data = await graphql(THROUGHPUT_QUERY, { query: searchQuery, cursor });
|
|
64
|
+
const search = data.search;
|
|
65
|
+
if (!search || !Number.isSafeInteger(search.issueCount) || search.issueCount < 0
|
|
66
|
+
|| !Array.isArray(search.nodes) || !search.pageInfo) {
|
|
67
|
+
throw new Error('github-throughput-invalid-response');
|
|
42
68
|
}
|
|
69
|
+
if (search.issueCount > 1_000)
|
|
70
|
+
throw new Error('github-throughput-result-cap-exceeded');
|
|
71
|
+
if (expectedCount === null)
|
|
72
|
+
expectedCount = search.issueCount;
|
|
73
|
+
if (search.issueCount !== expectedCount)
|
|
74
|
+
throw new Error('github-throughput-count-changed');
|
|
75
|
+
fetchedCount += search.nodes.length;
|
|
76
|
+
prs.push(...search.nodes.filter((pr) => typeof pr?.mergedAt === 'string'
|
|
77
|
+
&& Date.parse(pr.mergedAt) >= cutoff
|
|
78
|
+
&& Date.parse(pr.mergedAt) <= now));
|
|
79
|
+
if (!search.pageInfo.hasNextPage) {
|
|
80
|
+
if (fetchedCount !== expectedCount)
|
|
81
|
+
throw new Error('github-throughput-result-truncated');
|
|
82
|
+
return prs;
|
|
83
|
+
}
|
|
84
|
+
if (typeof search.pageInfo.endCursor !== 'string' || !search.pageInfo.endCursor) {
|
|
85
|
+
throw new Error('github-throughput-invalid-cursor');
|
|
86
|
+
}
|
|
87
|
+
cursor = search.pageInfo.endCursor;
|
|
43
88
|
}
|
|
44
|
-
|
|
89
|
+
throw new Error('github-throughput-page-cap-exceeded');
|
|
45
90
|
}
|
|
46
91
|
/** Canonical server-owned implementation of Echo's throughput-metrics.mjs contract. */
|
|
47
92
|
export async function buildThroughputSeries(opts) {
|
|
48
93
|
const now = opts.now ?? new Date();
|
|
49
|
-
const run = opts.run ?? gh;
|
|
50
94
|
const weights = opts.weights ?? DEFAULT_THROUGHPUT_WEIGHTS;
|
|
51
95
|
const cutoff = now.getTime() - opts.days * 86_400_000;
|
|
52
|
-
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
96
|
+
let graphql = opts.graphql;
|
|
97
|
+
if (!graphql) {
|
|
98
|
+
const token = opts.resolveToken
|
|
99
|
+
? opts.resolveToken()
|
|
100
|
+
: resolveGitHubToken({ stateDir: opts.stateDir, env: opts.env });
|
|
101
|
+
if (!token)
|
|
102
|
+
throw new GitHubAuthUnavailableError();
|
|
103
|
+
graphql = (query, variables) => fetchGitHubGraphql({
|
|
104
|
+
token,
|
|
105
|
+
query,
|
|
106
|
+
variables,
|
|
107
|
+
fetchImpl: opts.fetchImpl,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const prs = await listMergedPullRequests(graphql, cutoff, now.getTime());
|
|
111
|
+
const details = new Map(prs.map((pr) => [pr.number, {
|
|
112
|
+
reworkLoops: (pr.reviews?.nodes ?? []).filter((review) => review.state === 'CHANGES_REQUESTED').length,
|
|
113
|
+
commits: Number(pr.commits?.totalCount ?? 0),
|
|
114
|
+
}]));
|
|
57
115
|
const days = new Map();
|
|
58
116
|
for (const p of prs)
|
|
59
|
-
days.set(
|
|
117
|
+
days.set(pacificDay(p.mergedAt), [...(days.get(pacificDay(p.mergedAt)) ?? []), p]);
|
|
60
118
|
const rows = [...days].sort(([a], [b]) => a.localeCompare(b)).map(([day, all]) => {
|
|
61
119
|
const authors = {};
|
|
62
120
|
for (const a of ['codey', 'echo', 'other']) {
|
|
@@ -80,6 +138,10 @@ export async function buildThroughputSeries(opts) {
|
|
|
80
138
|
}
|
|
81
139
|
export function createThroughputRoutes(options = {}) {
|
|
82
140
|
const router = Router();
|
|
141
|
+
const resolveToken = createGitHubTokenResolver({
|
|
142
|
+
stateDir: options.stateDir,
|
|
143
|
+
env: options.env,
|
|
144
|
+
});
|
|
83
145
|
router.get('/throughput/series', async (req, res) => {
|
|
84
146
|
const days = Number(req.query.days ?? 14);
|
|
85
147
|
if (!WINDOWS.includes(days)) {
|
|
@@ -87,9 +149,17 @@ export function createThroughputRoutes(options = {}) {
|
|
|
87
149
|
return;
|
|
88
150
|
}
|
|
89
151
|
try {
|
|
90
|
-
res.set('Cache-Control', 'private, max-age=60').json(await buildThroughputSeries({
|
|
152
|
+
res.set('Cache-Control', 'private, max-age=60').json(await buildThroughputSeries({
|
|
153
|
+
days: days,
|
|
154
|
+
...options,
|
|
155
|
+
resolveToken,
|
|
156
|
+
}));
|
|
91
157
|
}
|
|
92
|
-
catch {
|
|
158
|
+
catch (error) {
|
|
159
|
+
if (error instanceof GitHubAuthUnavailableError) {
|
|
160
|
+
res.status(503).json({ error: 'github-auth-unavailable' });
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
93
163
|
res.status(503).json({ error: 'throughput-series-unavailable' });
|
|
94
164
|
}
|
|
95
165
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throughputRoutes.js","sourceRoot":"","sources":["../../src/server/throughputRoutes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"throughputRoutes.js","sourceRoot":"","sources":["../../src/server/throughputRoutes.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-07-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-07-24T15:21:21.763Z",
|
|
5
|
+
"instarVersion": "1.3.939",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -1530,7 +1530,7 @@
|
|
|
1530
1530
|
"type": "subsystem",
|
|
1531
1531
|
"domain": "server",
|
|
1532
1532
|
"sourcePath": "src/server/AgentServer.ts",
|
|
1533
|
-
"contentHash": "
|
|
1533
|
+
"contentHash": "212bac437dfd2ea5df615070a4956d6f3fbd892674913dbc9676aea8fd4a1ed6",
|
|
1534
1534
|
"since": "2025-01-01"
|
|
1535
1535
|
},
|
|
1536
1536
|
"subsystem:session-manager": {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Preferred-captain hand-back now reads the real per-rope mesh health snapshot. Previously, production never registered that snapshot with the hand-back reconciler, so a healthy preferred machine remained permanently “unknown” even though synthetic tests passed.
|
|
9
|
+
|
|
10
|
+
## What to Tell Your User
|
|
11
|
+
|
|
12
|
+
When your agent runs on a stationary machine and a traveling laptop, this closes the production wiring gap that prevented serving from returning to the preferred machine. The health check uses fresh authenticated mesh traffic and refuses to transfer when reachability has not been observed. A real two-machine failover and return drill remains the release acceptance gate.
|
|
13
|
+
|
|
14
|
+
## Summary of New Capabilities
|
|
15
|
+
|
|
16
|
+
- Connects the production mesh resolver’s health snapshot to preferred-captain hand-back.
|
|
17
|
+
- Distinguishes never-observed ropes from observed healthy and observed dead ropes.
|
|
18
|
+
- Preserves fail-closed behavior when health evidence is absent.
|
|
19
|
+
|
|
20
|
+
## Evidence
|
|
21
|
+
|
|
22
|
+
The focused hand-back suite passes 27 tests, including never-observed, healthy, dead, throwing-provider, and missing-provider boundaries. The full TypeScript build passes.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The Throughput server now calls GitHub GraphQL directly with an explicit
|
|
9
|
+
agent-owned token instead of starting a bare `gh` subprocess. The remaining
|
|
10
|
+
server-side CLI consumers share one absolute-executable, explicit-token runtime,
|
|
11
|
+
including the guarded Green-PR merge child.
|
|
12
|
+
|
|
13
|
+
## What to Tell Your User
|
|
14
|
+
|
|
15
|
+
The Throughput tab can load real chart data when the agent has a GitHub token in
|
|
16
|
+
its environment or vault, even when the server runs in the background with launchd's
|
|
17
|
+
restricted PATH. It will report authentication unavailable instead of silently
|
|
18
|
+
using another person's GitHub login.
|
|
19
|
+
|
|
20
|
+
## Summary of New Capabilities
|
|
21
|
+
|
|
22
|
+
- Uses direct authenticated GraphQL for Throughput.
|
|
23
|
+
- Fails closed on missing identity, incomplete Search pagination, or provider
|
|
24
|
+
result ceilings.
|
|
25
|
+
- Uses real Pacific timezone boundaries in both standard and daylight time.
|
|
26
|
+
- Gives CI polling and Green-PR reads/actuation one shared explicit GitHub runtime.
|
|
27
|
+
|
|
28
|
+
## Evidence
|
|
29
|
+
|
|
30
|
+
The focused runtime, route, pagination, timezone, CI, and Green-PR suites pass 73
|
|
31
|
+
tests. TypeScript and repository lint pass. Independent security, integration, and
|
|
32
|
+
throughput reviews were folded into the converged design. Final release evidence
|
|
33
|
+
also requires post-deployment desktop and phone verification with real chart data.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Side-Effects Review — mesh hand-back rope-health wiring
|
|
2
|
+
|
|
3
|
+
## Change and defect class
|
|
4
|
+
|
|
5
|
+
Production now injects a server-scoped adapter over `PeerEndpointResolver.snapshot()` directly into the U4.4 hand-back reconciler. The defect class is **synthetic-only dependency injection**: tests supplied an authority input manually, but the production composition root never supplied it, allowing an action-bearing feature to appear complete while remaining permanently inert.
|
|
6
|
+
|
|
7
|
+
Class-level correction: an adapter converts the resolver’s single-authority rows into a per-peer verdict with explicit three-valued and temporal semantics. No row or only never-dialed rows is `undefined`; a successful dial is `true` only when it is newer than that rope’s latest failure and fresher than one lease TTL; observed rows with no current successful rope are `false`. The focused test exercises all three states through the same exported adapter production uses.
|
|
8
|
+
|
|
9
|
+
## Signal versus authority
|
|
10
|
+
|
|
11
|
+
The adapter is a signal source, not transfer authority. The existing hand-back reconciler still requires every independent gate: holder status, preferred identity, heartbeat freshness, lease eligibility, quota, continuous health window, clean boundary, no split-brain, no churn latch, valid signed consent, and successful fenced claim. Missing or throwing health input remains fail-closed.
|
|
12
|
+
|
|
13
|
+
## Over-fire and under-fire
|
|
14
|
+
|
|
15
|
+
- Over-fire is bounded by requiring a real successful dial (`lastOkAt > 0`) newer than the rope’s last failure and fresher than one lease TTL. Merely advertising an endpoint, allocating a resolver row, retaining an old success, or remaining below the resolver’s three-failure demotion threshold is not health.
|
|
16
|
+
- Under-fire remains possible until real mesh traffic produces a result; this is deliberate. The lease holder keeps serving rather than transferring on inference.
|
|
17
|
+
|
|
18
|
+
## Cross-machine and rollout posture
|
|
19
|
+
|
|
20
|
+
The provider is scoped directly to one server’s hand-back reconciler and reads that server’s per-machine resolver authority. It is not installed into the module-global synthetic-test seam, so an embedded restart or second server lifecycle cannot inherit another resolver. Nothing new is replicated and no new route or credential surface is added. Single-machine installs have no peer rows and therefore remain a no-op. Hand-back remains controlled by its existing enable/dry-run chokepoint and requires live poll-follows-lease.
|
|
21
|
+
|
|
22
|
+
## External effects and rollback
|
|
23
|
+
|
|
24
|
+
The only new effect is that an already-enabled hand-back reconciler can progress past its health gate using real evidence. Disable `multiMachine.leaseSelfHeal.preferredCaptainHandback` to return to sticky leases. Removing the provider registration returns to the prior fail-closed inert posture; there is no migration or durable state.
|
|
25
|
+
|
|
26
|
+
## Verification
|
|
27
|
+
|
|
28
|
+
- `tests/unit/LeaseHandbackReconciler.test.ts`: 27/27 pass.
|
|
29
|
+
- `npm run build`: TypeScript and generated-manifest build pass.
|
|
30
|
+
- Real two-host proof is the release acceptance gate: paired baseline, laptop drop, bounded Mini takeover, real served reply, laptop rejoin, clean preferred hand-back, and no paired-read double-serving.
|
|
31
|
+
|
|
32
|
+
## Second-pass review
|
|
33
|
+
|
|
34
|
+
**Reviewer:** independent lease-handback reviewer
|
|
35
|
+
|
|
36
|
+
The first pass raised two concrete concerns: historical success could remain healthy indefinitely or survive newer sub-threshold failures, and a process-global provider could leak across server lifecycles. Both were folded before commit: health now requires strict success-after-failure ordering plus a one-lease-TTL freshness bound, with old-success, newer-failure, and same-millisecond ambiguity tests; production now injects a server-scoped adapter directly into its reconciler. Upgrade wording was also narrowed until the live pair proof passes.
|
|
37
|
+
|
|
38
|
+
**Independent verdict:** Concur with the review. The folded implementation fails closed on never-observed, stale, newer-failure, and same-millisecond ambiguity; repeated reads cannot manufacture continuous health; production authority is server-scoped; and the live two-host proof remains the release gate.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Side-Effects Review — Throughput GitHub runtime repair
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `throughput-github-runtime-repair`
|
|
4
|
+
**Date:** `2026-07-24`
|
|
5
|
+
**Author:** `instar-codey`
|
|
6
|
+
**Second-pass reviewer:** `Aquinas (review_security_identity)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
The Throughput route moves from a bare GitHub CLI subprocess to authenticated
|
|
11
|
+
GraphQL, while `src/core/githubRuntime.ts` becomes the shared explicit-token,
|
|
12
|
+
absolute-executable boundary for the CI poller and Green-PR watcher. The same
|
|
13
|
+
runtime environment is threaded through the real `safe-merge` child. Search
|
|
14
|
+
cardinality and Pacific timezone correctness are made explicit invariants.
|
|
15
|
+
|
|
16
|
+
## Decision-point inventory
|
|
17
|
+
|
|
18
|
+
- `buildThroughputSeries` identity resolution — **modify** — only environment or
|
|
19
|
+
agent-vault identity is accepted.
|
|
20
|
+
- Throughput Search pagination — **modify** — reported and fetched counts must agree
|
|
21
|
+
and remain at or below the provider ceiling.
|
|
22
|
+
- `resolveGhExecutable` — **add** — only known absolute, executable files qualify.
|
|
23
|
+
- `DefaultMergeRunner` process admission — **modify** — explicit GitHub runtime is
|
|
24
|
+
required before contract probing or actuation.
|
|
25
|
+
- `CiFailurePoller` GitHub read — **modify** — uses the shared cached runtime.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. Over-block
|
|
30
|
+
|
|
31
|
+
A legitimate install with a working machine-global `gh auth login` but no
|
|
32
|
+
`GITHUB_TOKEN` and no vault `github_token` is now refused. This is intentional:
|
|
33
|
+
the ambient login cannot prove agent identity. A 30-day window with more than 1,000
|
|
34
|
+
merged PRs is also refused rather than partially charted; a different data source
|
|
35
|
+
would be needed to support that volume honestly.
|
|
36
|
+
|
|
37
|
+
## 2. Under-block
|
|
38
|
+
|
|
39
|
+
An explicit token can still belong to the wrong GitHub principal if the operator
|
|
40
|
+
stores the wrong value. This layer proves explicit selection, not semantic
|
|
41
|
+
ownership. GitHub may also change its GraphQL schema or Search ceiling; those
|
|
42
|
+
changes fail the route closed through schema/count validation rather than render
|
|
43
|
+
incorrect data.
|
|
44
|
+
|
|
45
|
+
## 3. Level-of-abstraction fit
|
|
46
|
+
|
|
47
|
+
Identity and executable selection are centralized at the server process boundary,
|
|
48
|
+
below all three consumers. Throughput uses the higher-level GraphQL interface
|
|
49
|
+
because it needs structured read data, while the two legacy CLI consumers reuse the
|
|
50
|
+
lower-level runtime primitive. The existing `safe-merge` authority continues to own
|
|
51
|
+
merge judgment and execution; this change does not create a parallel merge gate.
|
|
52
|
+
|
|
53
|
+
## 4. Signal vs authority compliance
|
|
54
|
+
|
|
55
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
56
|
+
|
|
57
|
+
- [ ] No — this change produces a signal consumed by an existing smart gate.
|
|
58
|
+
- [ ] No — this change has no block/allow surface.
|
|
59
|
+
- [ ] Yes — but the logic is a smart gate with full conversational context (LLM-backed with recent history or equivalent).
|
|
60
|
+
- [x] Yes, with deterministic structural invariants — explicit identity,
|
|
61
|
+
executable-file status, and complete provider cardinality are enumerable safety
|
|
62
|
+
floors, not brittle proxies for intent.
|
|
63
|
+
|
|
64
|
+
The new refusals answer structural questions with exact evidence. They do not infer
|
|
65
|
+
user intent or choose among competing live signals. Green-PR judgment remains with
|
|
66
|
+
the existing eligibility ladder and `safe-merge`.
|
|
67
|
+
|
|
68
|
+
## 4b. Judgment-point check (Judgment Within Floors standard)
|
|
69
|
+
|
|
70
|
+
No new static heuristic is added at a competing-signals decision point. Token
|
|
71
|
+
presence, executable path shape, HTTP/schema validity, Search cardinality, and
|
|
72
|
+
timezone conversion are hard invariants with enumerable outcomes.
|
|
73
|
+
|
|
74
|
+
## 5. Interactions
|
|
75
|
+
|
|
76
|
+
- **Shadowing:** explicit-runtime admission runs before GitHub reads or merge
|
|
77
|
+
contract probing. It intentionally shadows ambient CLI identity; later safety
|
|
78
|
+
checks run unchanged once admission succeeds.
|
|
79
|
+
- **Double-fire:** no new scheduler or action is added. The Green-PR watcher and CI
|
|
80
|
+
poller retain their existing cadence and lease gates.
|
|
81
|
+
- **Races:** the five-minute cache is process-local. A token rotation can coexist
|
|
82
|
+
with the old value until the TTL expires; GitHub rejects a revoked value, and no
|
|
83
|
+
caller falls back to ambient auth.
|
|
84
|
+
- **Feedback loops:** Throughput is read-only. CI writes the existing failure ledger
|
|
85
|
+
and Green-PR retains the existing act path; this change adds no feedback edge.
|
|
86
|
+
|
|
87
|
+
## 6. External surfaces
|
|
88
|
+
|
|
89
|
+
GitHub receives direct GraphQL requests from Throughput with an explicit bearer
|
|
90
|
+
identity. The route's unauthenticated failure is now specifically
|
|
91
|
+
`github-auth-unavailable`; other failures retain the generic unavailable response.
|
|
92
|
+
No secret value is logged or returned. There is no new database, file format, URL,
|
|
93
|
+
notification, or operator action. Existing installs must supply `GITHUB_TOKEN` or
|
|
94
|
+
the vault secret for live data.
|
|
95
|
+
|
|
96
|
+
## 6b. Operator-surface quality (Operator-Surface Quality standard)
|
|
97
|
+
|
|
98
|
+
No dashboard renderer, form, or operator action is changed. The existing Throughput
|
|
99
|
+
tab is verified separately after deployment at desktop and phone widths.
|
|
100
|
+
|
|
101
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
102
|
+
|
|
103
|
+
**Machine-local BY DESIGN:** executable location and server environment are
|
|
104
|
+
machine-specific security truths. Each fleet server independently requires its
|
|
105
|
+
agent-scoped explicit identity and resolves its own executable. The output contract
|
|
106
|
+
is identical across machines; a misconfigured peer fails closed rather than
|
|
107
|
+
borrowing that host's global GitHub seat. No user-facing notices are emitted, no new
|
|
108
|
+
durable state can strand during topic transfer, and no URLs are generated.
|
|
109
|
+
|
|
110
|
+
## 8. Rollback cost
|
|
111
|
+
|
|
112
|
+
Pure code rollback: revert and ship a patch. No migration, state cleanup, or agent
|
|
113
|
+
reset is required. The rollback window restores the known Throughput 503 and ambient
|
|
114
|
+
CLI-identity hazard on affected machines, but does not corrupt data.
|
|
115
|
+
|
|
116
|
+
## Conclusion
|
|
117
|
+
|
|
118
|
+
The first review found that fixing only Throughput left the actual `safe-merge`
|
|
119
|
+
child outside the identity boundary. It also found Search truncation, repeated vault
|
|
120
|
+
resolution, relative-PATH acceptance, and fixed-offset day bucketing. All were
|
|
121
|
+
folded into this change with behavioral tests. The design is clear to ship subject
|
|
122
|
+
to the independent second-pass reread and green ceremony.
|
|
123
|
+
|
|
124
|
+
## Second-pass review (if required)
|
|
125
|
+
|
|
126
|
+
**Reviewer:** Aquinas (`review_security_identity`)
|
|
127
|
+
**Independent read of the artifact: concur**
|
|
128
|
+
|
|
129
|
+
Concur with the review: the shared runtime closes the prior identity and PATH
|
|
130
|
+
gaps through the real `safe-merge` act path, all three consumers fail safely, and
|
|
131
|
+
the cadence, lease, rollback, multi-machine, and self-action conclusions match the
|
|
132
|
+
final code and behavioral tests.
|
|
133
|
+
|
|
134
|
+
## Evidence pointers
|
|
135
|
+
|
|
136
|
+
- `tests/unit/github-runtime.test.ts`
|
|
137
|
+
- `tests/integration/throughput-github-auth.test.ts`
|
|
138
|
+
- `tests/unit/throughput-routes.test.ts`
|
|
139
|
+
- `tests/unit/green-pr-automerge-wiring.test.ts`
|
|
140
|
+
- `tests/unit/merge-runner.test.ts`
|
|
141
|
+
- `tests/unit/CiFailurePoller.test.ts`
|
|
142
|
+
|
|
143
|
+
## Class-Closure Declaration (display-only mirror)
|
|
144
|
+
|
|
145
|
+
`defectClass: unbounded-self-action`, `closure: guard`,
|
|
146
|
+
`guardEvidence: { enforcementType: ratchet, citation:
|
|
147
|
+
tests/unit/self-action-convergence.test.ts, howCaught: the touched CI and Green-PR
|
|
148
|
+
controllers retain lease/cadence admission and no new trigger edge; missing identity
|
|
149
|
+
settles each tick to a bounded no-action refusal, while the existing convergence
|
|
150
|
+
ratchet detects a controller whose steady-state action can grow without a settling
|
|
151
|
+
brake }`.
|
|
152
|
+
|
|
153
|
+
The production incident is an ordinary runtime identity defect, not an
|
|
154
|
+
agent-authored prompt/config/skill defect. The declaration is present because this
|
|
155
|
+
repair modifies existing self-triggered controllers.
|