tickmarkr 2.6.6 → 2.6.8
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/adapters/claude-code.js +8 -2
- package/dist/adapters/codex-commit-check.d.ts +3 -2
- package/dist/adapters/codex-commit-check.js +37 -10
- package/dist/adapters/codex.js +10 -4
- package/dist/cli/commands/beat.d.ts +7 -2
- package/dist/cli/commands/beat.js +144 -77
- package/dist/cli/commands/fleet.js +66 -21
- package/dist/cli/commands/init.js +18 -7
- package/dist/cli/commands/plan.js +16 -18
- package/dist/cli/commands/verify.js +4 -2
- package/dist/cli/help.d.ts +1 -0
- package/dist/cli/help.js +14 -6
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/drivers/herdr.js +2 -2
- package/dist/drivers/orca.d.ts +12 -4
- package/dist/drivers/orca.js +200 -39
- package/dist/gates/baseline.d.ts +9 -0
- package/dist/gates/baseline.js +14 -3
- package/dist/gates/cache.js +1 -1
- package/dist/gates/evidence.js +3 -3
- package/dist/gates/review.d.ts +1 -1
- package/dist/gates/review.js +77 -13
- package/dist/gates/run-gates.d.ts +21 -6
- package/dist/gates/run-gates.js +439 -224
- package/dist/gates/test-manifest.d.ts +42 -0
- package/dist/gates/test-manifest.js +203 -118
- package/dist/run/beat-lifecycle.d.ts +239 -0
- package/dist/run/beat-lifecycle.js +1782 -0
- package/dist/run/daemon.d.ts +4 -0
- package/dist/run/daemon.js +129 -40
- package/dist/run/git-trust.d.ts +102 -0
- package/dist/run/git-trust.js +334 -0
- package/dist/run/git.d.ts +24 -3
- package/dist/run/git.js +169 -30
- package/dist/run/journal.js +15 -3
- package/dist/run/lease.d.ts +23 -0
- package/dist/run/lease.js +232 -38
- package/dist/run/merge.js +4 -4
- package/dist/run/stall.js +20 -1
- package/dist/run/supervision.d.ts +8 -0
- package/dist/run/supervision.js +24 -4
- package/dist/run/verification-job.d.ts +53 -0
- package/dist/run/verification-job.js +159 -0
- package/dist/tui/ink/fleet-app.d.ts +16 -2
- package/dist/tui/ink/fleet-app.js +265 -141
- package/package.json +1 -1
- package/skills/tickmarkr-auto/SKILL.md +80 -27
- package/skills/tickmarkr-loop/SKILL.md +87 -27
- package/skills/tickmarkr-overseer/SKILL.md +125 -47
- package/skills/tickmarkr-overseer/scripts/watch-journal.sh +9 -7
package/dist/gates/review.js
CHANGED
|
@@ -5,7 +5,7 @@ import { criticalPathHits, DEFAULT_DIFF_CAP, DEFAULT_REVIEW_CRITICAL_PATHS, decl
|
|
|
5
5
|
import { filesGlob } from "../graph/files-glob.js";
|
|
6
6
|
import { renderAcceptanceItem, TIERS } from "../graph/schema.js";
|
|
7
7
|
import { getAdapter } from "../adapters/registry.js";
|
|
8
|
-
import {
|
|
8
|
+
import { shGitOk } from "../run/git.js";
|
|
9
9
|
import { carryReviewFindings, isDeferredFinding, observedReviewFingerprints, reviewFingerprintMatches, structuredFindings, UNIDENTIFIED } from "../run/journal.js";
|
|
10
10
|
import { redactSecrets } from "../run/redact.js";
|
|
11
11
|
import { rankPreferredChannels, reviewPreferenceTieBreak } from "../route/role-pick.js";
|
|
@@ -81,7 +81,7 @@ const DIFF_CAP_REMEDY = "split the task, or raise gates.diffCap";
|
|
|
81
81
|
* the leaf class must be visible to the promotion test, and rename detection would hide the old side.
|
|
82
82
|
*/
|
|
83
83
|
export async function changedPaths(worktree, baseRef) {
|
|
84
|
-
const out = await
|
|
84
|
+
const out = await shGitOk(`git diff --name-only --no-renames -z '${baseRef}..HEAD'`, worktree);
|
|
85
85
|
return [...new Set(out.split("\0").map((p) => p.trim()).filter(Boolean))].sort();
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
@@ -95,7 +95,7 @@ const VERSION_FIELD_LINE_RE = /^[+-]\s*"version":\s*"[^"]*",?\s*$/;
|
|
|
95
95
|
export async function mirrorsVersionOnly(worktree, baseRef, path) {
|
|
96
96
|
let diff;
|
|
97
97
|
try {
|
|
98
|
-
diff = await
|
|
98
|
+
diff = await shGitOk(`git diff --full-index -U0 '${baseRef}..HEAD' -- ${shq(path)}`, worktree);
|
|
99
99
|
}
|
|
100
100
|
catch {
|
|
101
101
|
return false;
|
|
@@ -109,8 +109,8 @@ export async function fetchTaskDiff(worktree, baseRef, files = []) {
|
|
|
109
109
|
const matched = files.length ? (await changedPaths(worktree, baseRef)).filter(filesGlob([...files])) : [];
|
|
110
110
|
const pathspec = matched.length ? ` -- ${matched.map(shq).join(" ")}` : "";
|
|
111
111
|
const [rawFull, rawForCap] = files.length && matched.length === 0 ? ["", ""] : await Promise.all([
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
shGitOk(`git diff --full-index '${baseRef}..HEAD'${pathspec}`, worktree),
|
|
113
|
+
shGitOk(`git diff --full-index -U0 '${baseRef}..HEAD'${pathspec}`, worktree),
|
|
114
114
|
]);
|
|
115
115
|
const fullMeasurement = measureArtifactDiff(rawFull);
|
|
116
116
|
const capMeasurement = measureArtifactDiff(rawForCap);
|
|
@@ -324,6 +324,52 @@ export function renderDeclaredWriteScope(files) {
|
|
|
324
324
|
The task DECLARED these write-scope patterns:
|
|
325
325
|
${files.map((path) => `- ${path}`).join("\n")}`;
|
|
326
326
|
}
|
|
327
|
+
// v2.6.8 T7: syntax only, never a filesystem glob. Explicit alternatives are finite at any count.
|
|
328
|
+
// ponytail: no expansion ceiling; the operator authors files[], so its product of alternatives is theirs to size.
|
|
329
|
+
const TEST_FILE_RE = /(?:^|\/)[^/]*\.(?:test|spec)\.[cm]?[jt]sx?$/;
|
|
330
|
+
/** Every finite, explicit `{a,b}` alternative of one entry, deduplicated; null when any part is not finite. */
|
|
331
|
+
function expandFiniteBraces(pattern) {
|
|
332
|
+
const open = pattern.indexOf("{");
|
|
333
|
+
if (open < 0)
|
|
334
|
+
return pattern.includes("}") ? null : [pattern];
|
|
335
|
+
if (pattern.slice(0, open).includes("}"))
|
|
336
|
+
return null;
|
|
337
|
+
const cuts = [open];
|
|
338
|
+
let depth = 0;
|
|
339
|
+
for (let i = open; i < pattern.length; i++) {
|
|
340
|
+
const c = pattern[i];
|
|
341
|
+
if (c === "{")
|
|
342
|
+
depth++;
|
|
343
|
+
else if (c === "," && depth === 1)
|
|
344
|
+
cuts.push(i);
|
|
345
|
+
else if (c === "}" && --depth === 0) {
|
|
346
|
+
if (cuts.length < 2)
|
|
347
|
+
return null; // `{}`, `{a}`, `{1..3}`: no finite alternation
|
|
348
|
+
cuts.push(i);
|
|
349
|
+
const out = new Set();
|
|
350
|
+
for (let k = 0; k + 1 < cuts.length; k++) {
|
|
351
|
+
const alt = pattern.slice(cuts[k] + 1, cuts[k + 1]);
|
|
352
|
+
const sub = alt ? expandFiniteBraces(pattern.slice(0, open) + alt + pattern.slice(i + 1)) : null;
|
|
353
|
+
if (!sub)
|
|
354
|
+
return null;
|
|
355
|
+
for (const path of sub)
|
|
356
|
+
out.add(path);
|
|
357
|
+
}
|
|
358
|
+
return [...out];
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return null; // unclosed brace
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* The test files one files[] entry names explicitly. A wildcard, escape, malformed or empty brace, or
|
|
365
|
+
* a path leaving the repository anywhere in the expansion grants nothing for the whole entry.
|
|
366
|
+
*/
|
|
367
|
+
function explicitSuitePaths(entry) {
|
|
368
|
+
const paths = expandFiniteBraces(entry);
|
|
369
|
+
const explicit = paths?.every((path) => !/[*?[\]{}()!\\]/.test(path)
|
|
370
|
+
&& path.split("/").every((segment) => segment !== "" && segment !== "." && segment !== ".."));
|
|
371
|
+
return explicit ? paths.filter((path) => TEST_FILE_RE.test(path)) : [];
|
|
372
|
+
}
|
|
327
373
|
/**
|
|
328
374
|
* OBS-1033: the vendors of the seats that authored commits inside the accumulated diff. A seat is
|
|
329
375
|
* never handed its own earlier work to approve. Unresolved channels are refused by reviewGate.
|
|
@@ -433,7 +479,10 @@ artifactDir, reviewHistory, demotedReviewers, carriedFindings = [],
|
|
|
433
479
|
// never the run-wide rotation history nor excludeReviewers; the seat holds the highest of their tiers.
|
|
434
480
|
priorReviewers = [],
|
|
435
481
|
// Closed list of actual subject authors; empty preserves legacy callers' single-author contract.
|
|
436
|
-
carriedAuthors = [],
|
|
482
|
+
carriedAuthors = [],
|
|
483
|
+
// v2.6.8 T7: kept for compatible callers and read as empty. An approve reason is the repair worker's
|
|
484
|
+
// standing instruction; a reviewer handed "the previous finding is resolved" graded the reason, not the diff.
|
|
485
|
+
_operatorContext) {
|
|
437
486
|
// R3 (OBS-186): participation is keyed on PATHS. The compiler's assignment comes from the DECLARED
|
|
438
487
|
// files[]; the operator's floor may RAISE it to full and can never lower it. `complexityThreshold` is
|
|
439
488
|
// retired — the branch that returned a green skip on a complexity comparison is gone, and with it the
|
|
@@ -529,12 +578,20 @@ carriedAuthors = [], operatorContext) {
|
|
|
529
578
|
return capFail;
|
|
530
579
|
const nonce = generateVerdictNonce();
|
|
531
580
|
const repoRoot = daemonRepoRoot(worktree, artifactDir);
|
|
532
|
-
// OBS-880 add.1: guidance only. Do not expand scope globs into permission to run suites.
|
|
533
|
-
|
|
581
|
+
// OBS-880 add.1: guidance only. Do not expand scope globs into permission to run suites; v2.6.8 T7:
|
|
582
|
+
// finite explicit brace alternatives are explicit files and each one is named.
|
|
583
|
+
const ownTestFiles = [...new Set(task.files.flatMap(explicitSuitePaths))];
|
|
534
584
|
const suiteBudget = ownTestFiles.length
|
|
535
585
|
? `You may run at most the task's own test files explicitly named in files[]; these are the only suites you may run: ${ownTestFiles.map((file) => `\`${file}\``).join(", ")}.`
|
|
536
586
|
: "No suite may be run: files[] names no explicit test file owned by this task.";
|
|
537
587
|
const responseRequirement = reviewResponseRequirement(nonce);
|
|
588
|
+
// D-966 (T3 E): a reviewer that stopped at the first example of a class drip-fed it one round at a
|
|
589
|
+
// time — T5's rounds carried 2→1→1→1→2→1 findings and T10's 3→2→1→1→1, each round's repair fixing
|
|
590
|
+
// the case it was shown while its same-class siblings waited for the next review. The closed note
|
|
591
|
+
// tuple asks for every counterexample ACTUALLY FOUND in scope at once, plus the boundary searched and
|
|
592
|
+
// what stays uncertain, so the repair sees the class and the next round knows what was covered. It
|
|
593
|
+
// rides the existing note text (details → repair brief unchanged) and never asks for an exhaustive
|
|
594
|
+
// search the reviewer cannot honestly make; uncertainty alone stays out of the material bar.
|
|
538
595
|
const prompt = `TICKMARKR-REVIEW
|
|
539
596
|
${responseRequirement}
|
|
540
597
|
|
|
@@ -555,10 +612,6 @@ ${suiteBudget} Never run the whole suite (including an unfiltered npm test or vi
|
|
|
555
612
|
|
|
556
613
|
${priorMaterials.length ? `${renderPriorMaterials(priorMaterials)}
|
|
557
614
|
|
|
558
|
-
` : ""}${operatorContext?.trim() ? `## Operator context
|
|
559
|
-
Context only: this never substitutes for an acceptance criterion or closes a prior material.
|
|
560
|
-
${operatorContext.trim()}
|
|
561
|
-
|
|
562
615
|
` : ""}${task.outOfScope?.length ? `## Out of scope
|
|
563
616
|
The task declares these items out of scope. A finding inside these declared bounds is not material and must not block approval.
|
|
564
617
|
${task.outOfScope.map((item) => `- ${item}`).join("\n")}
|
|
@@ -580,6 +633,14 @@ acceptance criterion it violates (or to the regression this diff introduces), st
|
|
|
580
633
|
and marks its evidence executed (you ran the reproducer), static (you traced it by reading) or blocked (it
|
|
581
634
|
could not run here). Blocked evidence never turns a finding into a pass, and a worker's own case table or
|
|
582
635
|
enumeration never resolves a finding: judge the diff itself.
|
|
636
|
+
Report the whole class in this one review, never only its first example. Each material finding's "note" is one
|
|
637
|
+
line carrying the closed tuple "rule: <the goal clause, criterion or regressed behaviour violated> | found:
|
|
638
|
+
<every counterexample you ACTUALLY FOUND inside the declared scope, each as path:line input → consequence,
|
|
639
|
+
joined by "; "> | searched: <the boundary you actually searched: files, symbols, call sites> | uncertain:
|
|
640
|
+
<what lies outside that boundary or could not be established inside it>". Found one counterexample, list one;
|
|
641
|
+
found several, list every one in the same finding. Never list a case you did not find. Your search is bounded:
|
|
642
|
+
never claim it covered every input, caller or path beyond the boundary you name, and remaining uncertainty
|
|
643
|
+
alone is never a material finding — record it under uncertain, or as a deferred minor with its rationale.
|
|
583
644
|
|
|
584
645
|
Respond with ONLY this JSON:
|
|
585
646
|
{"nonce": "${nonce}", "approve": true|false, "resolved": [], "reraised": [], "findings": [{"note": "...", "severity": "material"|"minor", "defer": false, "rationale": ""}], "comments": [{"path": "path/to/file", "line": 42, "body": "actionable feedback", "finding": 1}]}
|
|
@@ -668,7 +729,10 @@ ${responseRequirement}
|
|
|
668
729
|
// a genuinely wrapped verdict behind it is reconstructed here, exactly as llm.ts would have.
|
|
669
730
|
const echoFree = withoutExampleEcho(raw, nonce);
|
|
670
731
|
const seat = via ? dewrapPaneVerdict(echoFree, nonce) : echoFree;
|
|
671
|
-
const
|
|
732
|
+
const parsed = extractVerdictJson(seat, nonce);
|
|
733
|
+
// v2.6.8 T7: with zero carried ids nothing was asked to close, so volunteered closure ids are ignored —
|
|
734
|
+
// a material red stays red, never no-verdict. With carried ids the closure protocol binds unchanged.
|
|
735
|
+
const v = parsed && !priorMaterials.length ? { ...parsed, resolved: undefined, reraised: undefined } : parsed;
|
|
672
736
|
const findings = v && Array.isArray(v.findings) ? v.findings : null;
|
|
673
737
|
const priorIds = priorMaterials;
|
|
674
738
|
const closureInvalid = isReviewClosureInvalid(v, priorIds);
|
|
@@ -73,6 +73,9 @@ export interface GateContext {
|
|
|
73
73
|
excludeReviewers?: string[];
|
|
74
74
|
demotedReviewers?: Set<string>;
|
|
75
75
|
reviewNoVerdicts?: Map<string, string[]>;
|
|
76
|
+
/** v2.6.8 T1: review seats whose one same-seat launch retry this candidate already spent (the daemon
|
|
77
|
+
* replays them from the journal), so a resume or recheck never re-grants it by forgetting. */
|
|
78
|
+
launchRetried?: readonly string[];
|
|
76
79
|
recheck?: boolean;
|
|
77
80
|
/** Explicit worker funding requires fresh red measurements, never a gate waiver. OBS-1106: so does
|
|
78
81
|
* a retry that landed nothing on a timeout-class red — its one fresh re-observation. C: and one whose
|
|
@@ -98,14 +101,26 @@ export interface GateContext {
|
|
|
98
101
|
* a command that already has `--` takes them directly. Every path is quoted — config flows into a shell.
|
|
99
102
|
*/
|
|
100
103
|
export declare function testCommandForFiles(testCmd: string, files: string[]): string;
|
|
101
|
-
/**
|
|
102
|
-
export declare const
|
|
104
|
+
/** v2.6.7 T1 (closed order table): an attributed test-red diagnostic is admitted only when BOTH hold. */
|
|
105
|
+
export declare const DIAGNOSTIC_MAX_RATIO = 0.15;
|
|
106
|
+
export declare const DIAGNOSTIC_MAX_ESTIMATE_MS = 60000;
|
|
107
|
+
export interface DiagnosticAdmission {
|
|
108
|
+
admitted: boolean;
|
|
109
|
+
reason: "diagnostic-admitted" | "diagnostic-unknown-cost" | "diagnostic-capacity-mismatch" | "diagnostic-cost-ratio" | "diagnostic-cost-estimate";
|
|
110
|
+
costRatio?: number;
|
|
111
|
+
estimatedMs?: number;
|
|
112
|
+
}
|
|
103
113
|
/**
|
|
104
|
-
* The
|
|
105
|
-
*
|
|
106
|
-
*
|
|
114
|
+
* The diagnostic's admission evidence, from the per-file durations the harness measured at baseline
|
|
115
|
+
* capture — never a worker's timing. Unknown (any selected file unmeasured, any measurement that is not a
|
|
116
|
+
* finite number > 0 ms, an infra baseline, or no positive total) skips: an expensive or unknown screen must
|
|
117
|
+
* never become a full suite before semantics.
|
|
118
|
+
* So does timing recorded under a malformed or different capacity (git.ts sameCapacity): it divided the
|
|
119
|
+
* machine by another number, so it is not comparable evidence about this one.
|
|
120
|
+
* `estimatedMs` is the serial sum of those files: admission evidence, not a kill ceiling and not a
|
|
121
|
+
* claim about the parallel-plus-serial wall time the runner will actually take.
|
|
107
122
|
*/
|
|
108
|
-
export declare function
|
|
123
|
+
export declare function diagnosticAdmission(baseline: Baseline, selected: readonly string[]): DiagnosticAdmission;
|
|
109
124
|
/** A retry base no runner invocation parses. evaluateManifestedTest builds its stranded single-fork
|
|
110
125
|
* retry from the base it is handed, and one it cannot parse throws before any spawn — so this base
|
|
111
126
|
* disables that inner recovery: a worker-RPC-stranded re-observation comes back infra (the caller
|