project-tiny-context-harness 0.2.81 → 0.2.83
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 +11 -3
- package/assets/README.md +11 -3
- package/assets/README.zh-CN.md +9 -1
- package/assets/protected-harness-baseline.json +18 -0
- package/assets/skills/composite-long-task-workflow/SKILL.md +21 -1
- package/assets/skills/composite-long-task-workflow/assets/execution-binding.template.md +10 -0
- package/assets/skills/composite-long-task-workflow/assets/goal-objective.template.md +6 -15
- package/assets/skills/composite-long-task-workflow/references/composite-long-task-workflow-protocol.md +32 -15
- package/dist/commands/composite-long-task.js +45 -2
- package/dist/lib/superpowers-task-ac010.d.ts +6 -0
- package/dist/lib/superpowers-task-ac010.js +26 -0
- package/dist/lib/superpowers-task-assertion-normalizers.js +8 -1
- package/dist/lib/superpowers-task-assertions.js +35 -20
- package/dist/lib/superpowers-task-attempt.d.ts +4 -0
- package/dist/lib/superpowers-task-attempt.js +102 -0
- package/dist/lib/superpowers-task-command-specs.d.ts +3 -0
- package/dist/lib/superpowers-task-command-specs.js +52 -0
- package/dist/lib/superpowers-task-compile.d.ts +4 -1
- package/dist/lib/superpowers-task-compile.js +7 -1
- package/dist/lib/superpowers-task-contradictions.d.ts +6 -0
- package/dist/lib/superpowers-task-contradictions.js +126 -0
- package/dist/lib/superpowers-task-current-evidence.d.ts +3 -0
- package/dist/lib/superpowers-task-current-evidence.js +154 -0
- package/dist/lib/superpowers-task-delivery.js +30 -18
- package/dist/lib/superpowers-task-derive.d.ts +1 -0
- package/dist/lib/superpowers-task-derive.js +76 -1
- package/dist/lib/superpowers-task-evidence-kernel.d.ts +12 -0
- package/dist/lib/superpowers-task-evidence-kernel.js +351 -0
- package/dist/lib/superpowers-task-evidence-records.d.ts +2 -0
- package/dist/lib/superpowers-task-evidence-records.js +55 -0
- package/dist/lib/superpowers-task-evidence.d.ts +10 -0
- package/dist/lib/superpowers-task-evidence.js +141 -0
- package/dist/lib/superpowers-task-fields.d.ts +22 -0
- package/dist/lib/superpowers-task-fields.js +276 -0
- package/dist/lib/superpowers-task-gates.js +36 -24
- package/dist/lib/superpowers-task-harness-drift.d.ts +11 -0
- package/dist/lib/superpowers-task-harness-drift.js +86 -0
- package/dist/lib/superpowers-task-protected-baseline.d.ts +10 -0
- package/dist/lib/superpowers-task-protected-baseline.js +47 -0
- package/dist/lib/superpowers-task-source-compile.js +93 -95
- package/dist/lib/superpowers-task-source-parser.js +1 -3
- package/dist/lib/superpowers-task-state-schema.d.ts +158 -3
- package/dist/lib/superpowers-task-state-schema.js +23 -1
- package/dist/lib/superpowers-task-state-shape.d.ts +3 -0
- package/dist/lib/superpowers-task-state-shape.js +50 -0
- package/dist/lib/superpowers-task-state.js +19 -39
- package/dist/lib/superpowers-task-status.js +11 -1
- package/dist/lib/superpowers-task-under-specified.d.ts +7 -0
- package/dist/lib/superpowers-task-under-specified.js +61 -0
- package/dist/lib/superpowers-task-validator.js +11 -37
- package/package.json +69 -69
- package/source-mappings.yaml +3 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isRecord } from "./superpowers-task-state-schema.js";
|
|
2
|
+
export function validateShape(state, errors) {
|
|
3
|
+
if (state.meta?.schema_version !== "superpowers-task-state-v1") {
|
|
4
|
+
errors.push("task-state.json schema_version must be superpowers-task-state-v1");
|
|
5
|
+
}
|
|
6
|
+
for (const key of [
|
|
7
|
+
"meta",
|
|
8
|
+
"sources",
|
|
9
|
+
"context",
|
|
10
|
+
"delivery",
|
|
11
|
+
"graph",
|
|
12
|
+
"attempts",
|
|
13
|
+
"current_attempt_id",
|
|
14
|
+
"required_command_specs",
|
|
15
|
+
"command_runs",
|
|
16
|
+
"negative_evidence_records",
|
|
17
|
+
"slices",
|
|
18
|
+
"evidence",
|
|
19
|
+
"gates",
|
|
20
|
+
"progress",
|
|
21
|
+
"blockers",
|
|
22
|
+
"final"
|
|
23
|
+
]) {
|
|
24
|
+
if (!(key in state)) {
|
|
25
|
+
errors.push(`task-state.json is missing section: ${key}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function hasUsableShape(state) {
|
|
30
|
+
const candidate = state;
|
|
31
|
+
return (isRecord(candidate.meta) &&
|
|
32
|
+
isRecord(candidate.sources) &&
|
|
33
|
+
isRecord(candidate.context) &&
|
|
34
|
+
isRecord(candidate.delivery) &&
|
|
35
|
+
isRecord(candidate.graph) &&
|
|
36
|
+
isRecord(candidate.graph.plan_items) &&
|
|
37
|
+
isRecord(candidate.graph.acceptance_criteria) &&
|
|
38
|
+
isRecord(candidate.graph.proof_layers) &&
|
|
39
|
+
Array.isArray(candidate.attempts) &&
|
|
40
|
+
typeof candidate.current_attempt_id === "string" &&
|
|
41
|
+
Array.isArray(candidate.required_command_specs) &&
|
|
42
|
+
Array.isArray(candidate.command_runs) &&
|
|
43
|
+
Array.isArray(candidate.negative_evidence_records) &&
|
|
44
|
+
Array.isArray(candidate.slices) &&
|
|
45
|
+
Array.isArray(candidate.evidence) &&
|
|
46
|
+
isRecord(candidate.gates) &&
|
|
47
|
+
isRecord(candidate.progress) &&
|
|
48
|
+
Array.isArray(candidate.blockers) &&
|
|
49
|
+
isRecord(candidate.final));
|
|
50
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { ensureDir, pathExists, readText, writeTextIfChanged } from "./fs.js";
|
|
4
|
+
import { normalizeProofLayerId } from "./superpowers-task-fields.js";
|
|
4
5
|
import { appendSuperpowersEvent } from "./superpowers-task-events.js";
|
|
5
|
-
import { evaluateProofLayerAssertions, isMachineVerifiableLayer
|
|
6
|
+
import { evaluateProofLayerAssertions, isMachineVerifiableLayer } from "./superpowers-task-assertions.js";
|
|
7
|
+
import { readEvidenceRecords } from "./superpowers-task-evidence-records.js";
|
|
6
8
|
import { SUPERPOWERS_TASK_STATE_JSON_SCHEMA, SUPERPOWERS_TASK_STATE_SCHEMA_VERSION, asStringArray, isRecord } from "./superpowers-task-state-schema.js";
|
|
7
9
|
const SOURCE_FILES = {
|
|
8
10
|
product_architecture_source: {
|
|
@@ -54,7 +56,15 @@ export async function initializeSuperpowersTask(workdir, options = {}) {
|
|
|
54
56
|
full_population_required: null,
|
|
55
57
|
representative_samples_validate: [],
|
|
56
58
|
representative_samples_do_not_validate: [],
|
|
57
|
-
out_of_scope_backlog: []
|
|
59
|
+
out_of_scope_backlog: [],
|
|
60
|
+
scope_fit_decision: "",
|
|
61
|
+
selected_scope_fit_slice: "",
|
|
62
|
+
owner_boundary: "",
|
|
63
|
+
primary_capability_path: "",
|
|
64
|
+
non_completing_outcomes: [],
|
|
65
|
+
assertion_policy: "",
|
|
66
|
+
source_authority: "",
|
|
67
|
+
product_goal: ""
|
|
58
68
|
},
|
|
59
69
|
scope_conflicts: []
|
|
60
70
|
},
|
|
@@ -64,6 +74,11 @@ export async function initializeSuperpowersTask(workdir, options = {}) {
|
|
|
64
74
|
proof_layers: {},
|
|
65
75
|
edges: []
|
|
66
76
|
},
|
|
77
|
+
attempts: [],
|
|
78
|
+
current_attempt_id: "",
|
|
79
|
+
required_command_specs: [],
|
|
80
|
+
command_runs: [],
|
|
81
|
+
negative_evidence_records: [],
|
|
67
82
|
slices: [],
|
|
68
83
|
evidence: [],
|
|
69
84
|
gates: {},
|
|
@@ -121,8 +136,8 @@ export async function applySliceDelta(workdir, deltaFile) {
|
|
|
121
136
|
missing_layer_classes: asStringArray(delta.missing_layer_classes),
|
|
122
137
|
code_changes: asStringArray(delta.code_changes),
|
|
123
138
|
evidence_records: evidenceRecords.map((item) => item.evidence_id),
|
|
124
|
-
closed_layers: asStringArray(delta.closed_layers),
|
|
125
|
-
remaining_layers: asStringArray(delta.remaining_layers),
|
|
139
|
+
closed_layers: asStringArray(delta.closed_layers).map(normalizeProofLayerId),
|
|
140
|
+
remaining_layers: asStringArray(delta.remaining_layers).map(normalizeProofLayerId),
|
|
126
141
|
blockers: Array.isArray(delta.blockers) ? delta.blockers : [],
|
|
127
142
|
cleanup_assertions: asStringArray(delta.cleanup_assertions),
|
|
128
143
|
progress_value: {
|
|
@@ -205,41 +220,6 @@ export function sha256(value) {
|
|
|
205
220
|
export function stableJson(value) {
|
|
206
221
|
return JSON.stringify(sortJson(value), null, 2);
|
|
207
222
|
}
|
|
208
|
-
function readEvidenceRecords(value) {
|
|
209
|
-
if (!Array.isArray(value)) {
|
|
210
|
-
return [];
|
|
211
|
-
}
|
|
212
|
-
return value.filter(isRecord).map((item) => ({
|
|
213
|
-
evidence_id: String(item.evidence_id ?? item.evidenceId ?? ""),
|
|
214
|
-
slice_id: String(item.slice_id ?? item.sliceId ?? ""),
|
|
215
|
-
type: String(item.type ?? ""),
|
|
216
|
-
freshness: isRecord(item.freshness)
|
|
217
|
-
? {
|
|
218
|
-
created_at: String(item.freshness.created_at ?? ""),
|
|
219
|
-
valid_for: String(item.freshness.valid_for ?? ""),
|
|
220
|
-
stale_after: item.freshness.stale_after === null ? null : item.freshness.stale_after === undefined ? null : String(item.freshness.stale_after)
|
|
221
|
-
}
|
|
222
|
-
: { created_at: "", valid_for: "", stale_after: null },
|
|
223
|
-
command: item.command === undefined ? undefined : String(item.command),
|
|
224
|
-
command_exit_code: item.command_exit_code === undefined ? undefined : Number(item.command_exit_code),
|
|
225
|
-
artifact_paths: asStringArray(item.artifact_paths),
|
|
226
|
-
proves: asStringArray(item.proves),
|
|
227
|
-
does_not_prove: asStringArray(item.does_not_prove),
|
|
228
|
-
redaction: isRecord(item.redaction)
|
|
229
|
-
? { checked: item.redaction.checked === true, contains_secret: item.redaction.contains_secret === true }
|
|
230
|
-
: { checked: false, contains_secret: false },
|
|
231
|
-
reviewability: isRecord(item.reviewability)
|
|
232
|
-
? {
|
|
233
|
-
external_reviewer_can_reproduce: item.reviewability.external_reviewer_can_reproduce === true,
|
|
234
|
-
reproduction_steps: String(item.reviewability.reproduction_steps ?? "")
|
|
235
|
-
}
|
|
236
|
-
: { external_reviewer_can_reproduce: false, reproduction_steps: "" },
|
|
237
|
-
assertion_result: normalizeAssertionResult(item.assertion_result),
|
|
238
|
-
negative_evidence_scan: normalizeNegativeEvidenceScan(item.negative_evidence_scan),
|
|
239
|
-
sibling_substitution_used: item.sibling_substitution_used === true,
|
|
240
|
-
sibling_substitution_approval_source: item.sibling_substitution_approval_source === undefined ? undefined : String(item.sibling_substitution_approval_source)
|
|
241
|
-
}));
|
|
242
|
-
}
|
|
243
223
|
function sortJson(value) {
|
|
244
224
|
if (Array.isArray(value)) {
|
|
245
225
|
return value.map(sortJson);
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
const CANONICAL_PLAN_STATUSES = new Set(["not_started", "in_progress", "partial", "blocked", "invalidated", "complete", "out_of_scope_NA"]);
|
|
2
|
-
const CANONICAL_AC_STATUSES = new Set([
|
|
2
|
+
const CANONICAL_AC_STATUSES = new Set([
|
|
3
|
+
"not_started",
|
|
4
|
+
"not_run",
|
|
5
|
+
"in_progress",
|
|
6
|
+
"partial",
|
|
7
|
+
"blocked",
|
|
8
|
+
"invalidated",
|
|
9
|
+
"under_specified",
|
|
10
|
+
"complete",
|
|
11
|
+
"out_of_scope_NA"
|
|
12
|
+
]);
|
|
3
13
|
export function validateCanonicalStatuses(state, errors) {
|
|
4
14
|
for (const [planId, item] of Object.entries(state.graph?.plan_items ?? {})) {
|
|
5
15
|
if (!CANONICAL_PLAN_STATUSES.has(item.status)) {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SuperpowersAcceptanceCriterion, SuperpowersTaskState } from "./superpowers-task-state-schema.js";
|
|
2
|
+
export interface UnderSpecifiedAc {
|
|
3
|
+
ac_id: string;
|
|
4
|
+
reasons: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function findUnderSpecifiedAcs(state: SuperpowersTaskState): UnderSpecifiedAc[];
|
|
7
|
+
export declare function underSpecifiedReasons(acId: string, ac: SuperpowersAcceptanceCriterion): string[];
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { isMachineVerifiableLayer } from "./superpowers-task-assertions.js";
|
|
2
|
+
const GENERATED_ONLY_EVIDENCE = /\b(matrix|verdict|validator|final[-_ ]?card|final[-_ ]?summary|evidence[-_ ]?index|derived\/)/i;
|
|
3
|
+
const MACHINE_UI_PROOF = /\b(browser|ui_browser|e2e|smoke|trace|playwright|route|owner surface)\b/i;
|
|
4
|
+
const MANUAL_ONLY_TEST = /\b(查看页面|人工确认|manual confirm|manually inspect|visual check only)\b/i;
|
|
5
|
+
export function findUnderSpecifiedAcs(state) {
|
|
6
|
+
return Object.entries(state.graph?.acceptance_criteria ?? {})
|
|
7
|
+
.map(([acId, ac]) => ({ ac_id: acId, reasons: underSpecifiedReasons(acId, ac) }))
|
|
8
|
+
.filter((item) => item.reasons.length > 0);
|
|
9
|
+
}
|
|
10
|
+
export function underSpecifiedReasons(acId, ac) {
|
|
11
|
+
if (ac.machine_blocking !== true && ac.assertion_result_required !== true) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const reasons = [];
|
|
15
|
+
if (!trimmed(ac.assertion_command)) {
|
|
16
|
+
reasons.push(`${acId} under_specified: assertion_command is required for machine_blocking AC`);
|
|
17
|
+
}
|
|
18
|
+
if ((ac.assertion_artifacts ?? []).length === 0) {
|
|
19
|
+
reasons.push(`${acId} under_specified: assertion_artifacts are required for machine_blocking AC`);
|
|
20
|
+
}
|
|
21
|
+
if ((ac.positive_assertions ?? []).length === 0) {
|
|
22
|
+
reasons.push(`${acId} under_specified: positive_assertions are required for machine_blocking AC`);
|
|
23
|
+
}
|
|
24
|
+
if ((ac.negative_assertions ?? []).length === 0) {
|
|
25
|
+
reasons.push(`${acId} under_specified: negative_assertions are required for machine_blocking AC`);
|
|
26
|
+
}
|
|
27
|
+
if ((ac.invalid_completion_signals ?? []).length === 0) {
|
|
28
|
+
reasons.push(`${acId} under_specified: invalid_completion_signals are required for machine_blocking AC`);
|
|
29
|
+
}
|
|
30
|
+
if (ac.assertion_result_required !== true) {
|
|
31
|
+
reasons.push(`${acId} under_specified: machine_blocking AC must require assertion_result`);
|
|
32
|
+
}
|
|
33
|
+
const requiredLayers = ac.required_proof_layers ?? [];
|
|
34
|
+
if (requiredLayers.some((layer) => isMachineVerifiableLayer(`${acId}.${layer}`)) && !trimmed(ac.assertion_command)) {
|
|
35
|
+
reasons.push(`${acId} under_specified: machine proof layers cannot produce assertion_result without assertion_command`);
|
|
36
|
+
}
|
|
37
|
+
if (requiredLayers.includes("ui_browser") && !MACHINE_UI_PROOF.test(acEvidenceText(ac))) {
|
|
38
|
+
reasons.push(`${acId} under_specified: ui_browser AC requires browser/e2e/smoke/trace-backed proof`);
|
|
39
|
+
}
|
|
40
|
+
const finalEvidence = ac.final_evidence_expected ?? [];
|
|
41
|
+
if (finalEvidence.length > 0 && finalEvidence.every((item) => GENERATED_ONLY_EVIDENCE.test(item))) {
|
|
42
|
+
reasons.push(`${acId} under_specified: final_evidence_expected only names generated summary artifacts`);
|
|
43
|
+
}
|
|
44
|
+
const testCases = ac.test_cases ?? [];
|
|
45
|
+
if (testCases.length > 0 && testCases.every((item) => MANUAL_ONLY_TEST.test(item))) {
|
|
46
|
+
reasons.push(`${acId} under_specified: test_cases are manual-only`);
|
|
47
|
+
}
|
|
48
|
+
return reasons;
|
|
49
|
+
}
|
|
50
|
+
function acEvidenceText(ac) {
|
|
51
|
+
return [
|
|
52
|
+
ac.assertion_command ?? "",
|
|
53
|
+
...(ac.assertion_artifacts ?? []),
|
|
54
|
+
...(ac.verification_method ?? []),
|
|
55
|
+
...(ac.test_cases ?? []),
|
|
56
|
+
...(ac.final_evidence_expected ?? [])
|
|
57
|
+
].join("\n");
|
|
58
|
+
}
|
|
59
|
+
function trimmed(value) {
|
|
60
|
+
return Boolean(value && value.trim());
|
|
61
|
+
}
|
|
@@ -4,11 +4,14 @@ import { findSensitiveEvidence } from "./plan-acceptance-evidence.js";
|
|
|
4
4
|
import { primitiveText, repoRelative, resolveInputDir } from "./plan-validator-common.js";
|
|
5
5
|
import { derivedMatchesState } from "./superpowers-task-derive.js";
|
|
6
6
|
import { validatePlanCompletionConformance } from "./superpowers-task-conformance.js";
|
|
7
|
+
import { scanSuperpowersContradictions } from "./superpowers-task-contradictions.js";
|
|
8
|
+
import { evaluateTrustedEvidenceKernel } from "./superpowers-task-evidence-kernel.js";
|
|
7
9
|
import { fullPopulationRequired, validateDeliveryContract, validateScopeConflicts } from "./superpowers-task-delivery.js";
|
|
10
|
+
import { hasUsableShape, validateShape } from "./superpowers-task-state-shape.js";
|
|
8
11
|
import { loadSuperpowersState, sha256 } from "./superpowers-task-state.js";
|
|
9
12
|
import { validateCanonicalStatuses } from "./superpowers-task-status.js";
|
|
10
13
|
import { isRecord } from "./superpowers-task-state-schema.js";
|
|
11
|
-
import { evaluateProofLayerAssertions, isUiBrowserLayer } from "./superpowers-task-assertions.js";
|
|
14
|
+
import { evaluateProofLayerAssertions, isUiBrowserLayer, proofLayerName } from "./superpowers-task-assertions.js";
|
|
12
15
|
export async function validateSuperpowersState(projectRoot, args = []) {
|
|
13
16
|
const info = [];
|
|
14
17
|
const warnings = [];
|
|
@@ -24,12 +27,7 @@ export async function validateSuperpowersState(projectRoot, args = []) {
|
|
|
24
27
|
state = await loadSuperpowersState(targetDir);
|
|
25
28
|
}
|
|
26
29
|
catch (error) {
|
|
27
|
-
return {
|
|
28
|
-
info,
|
|
29
|
-
warnings,
|
|
30
|
-
hygiene,
|
|
31
|
-
errors: [`${repoRelative(projectRoot, statePath)} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`]
|
|
32
|
-
};
|
|
30
|
+
return { info, warnings, hygiene, errors: [`${repoRelative(projectRoot, statePath)} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`] };
|
|
33
31
|
}
|
|
34
32
|
validateShape(state, errors);
|
|
35
33
|
if (!hasUsableShape(state)) {
|
|
@@ -44,6 +42,8 @@ export async function validateSuperpowersState(projectRoot, args = []) {
|
|
|
44
42
|
validateScopeConflicts(state, errors);
|
|
45
43
|
validateEvidenceRecords(state, errors);
|
|
46
44
|
validateProofLayers(state, errors);
|
|
45
|
+
errors.push(...(await evaluateTrustedEvidenceKernel(targetDir, state)).errors);
|
|
46
|
+
errors.push(...(await scanSuperpowersContradictions(targetDir, state)).errors);
|
|
47
47
|
validateAuditor(state, errors);
|
|
48
48
|
validateFinalCompletion(state, errors);
|
|
49
49
|
errors.push(...(await derivedMatchesState(targetDir, state)));
|
|
@@ -66,33 +66,6 @@ async function validateSourceHashes(workdir, state, errors) {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
-
function validateShape(state, errors) {
|
|
70
|
-
if (state.meta?.schema_version !== "superpowers-task-state-v1") {
|
|
71
|
-
errors.push("task-state.json schema_version must be superpowers-task-state-v1");
|
|
72
|
-
}
|
|
73
|
-
for (const key of ["meta", "sources", "context", "delivery", "graph", "slices", "evidence", "gates", "progress", "blockers", "final"]) {
|
|
74
|
-
if (!(key in state)) {
|
|
75
|
-
errors.push(`task-state.json is missing section: ${key}`);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function hasUsableShape(state) {
|
|
80
|
-
const candidate = state;
|
|
81
|
-
return (isRecord(candidate.meta) &&
|
|
82
|
-
isRecord(candidate.sources) &&
|
|
83
|
-
isRecord(candidate.context) &&
|
|
84
|
-
isRecord(candidate.delivery) &&
|
|
85
|
-
isRecord(candidate.graph) &&
|
|
86
|
-
isRecord(candidate.graph.plan_items) &&
|
|
87
|
-
isRecord(candidate.graph.acceptance_criteria) &&
|
|
88
|
-
isRecord(candidate.graph.proof_layers) &&
|
|
89
|
-
Array.isArray(candidate.slices) &&
|
|
90
|
-
Array.isArray(candidate.evidence) &&
|
|
91
|
-
isRecord(candidate.gates) &&
|
|
92
|
-
isRecord(candidate.progress) &&
|
|
93
|
-
Array.isArray(candidate.blockers) &&
|
|
94
|
-
isRecord(candidate.final));
|
|
95
|
-
}
|
|
96
69
|
function validateGraphReferences(state, errors) {
|
|
97
70
|
const planIds = new Set(Object.keys(state.graph?.plan_items ?? {}));
|
|
98
71
|
const acIds = new Set(Object.keys(state.graph?.acceptance_criteria ?? {}));
|
|
@@ -165,10 +138,11 @@ function validateEvidenceRecords(state, errors) {
|
|
|
165
138
|
errors.push(`${label} uses sibling substitution without approval`);
|
|
166
139
|
}
|
|
167
140
|
for (const proofLayer of evidence.proves ?? []) {
|
|
168
|
-
|
|
169
|
-
|
|
141
|
+
const layerName = proofLayerName(proofLayer);
|
|
142
|
+
if (layerName === "worker_runtime" && /\b(mock|unit|viewmodel)\b/i.test(evidence.type)) {
|
|
143
|
+
errors.push(`${label} worker_runtime proof cannot be mock/unit/viewmodel only`);
|
|
170
144
|
}
|
|
171
|
-
if (
|
|
145
|
+
if (layerName === "ui_browser" && !/(browser|ui_browser|screenshot|playwright)/i.test(evidence.type)) {
|
|
172
146
|
errors.push(`${label} UI proof must use browser owner surface evidence`);
|
|
173
147
|
}
|
|
174
148
|
}
|
package/package.json
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "project-tiny-context-harness",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Minimal project memory and validation harness for AI coding agents.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "Seven128",
|
|
7
|
-
"homepage": "https://github.com/Seven128/project-tiny-context-harness#readme",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/Seven128/project-tiny-context-harness.git",
|
|
11
|
-
"directory": "packages/ty-context"
|
|
12
|
-
},
|
|
13
|
-
"bugs": {
|
|
14
|
-
"url": "https://github.com/Seven128/project-tiny-context-harness/issues"
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"ai-agents",
|
|
18
|
-
"coding-agent",
|
|
19
|
-
"codex",
|
|
20
|
-
"claude-code",
|
|
21
|
-
"cursor",
|
|
22
|
-
"gemini-cli",
|
|
23
|
-
"opencode",
|
|
24
|
-
"agent-context",
|
|
25
|
-
"context-engineering",
|
|
26
|
-
"context-management",
|
|
27
|
-
"agents-md",
|
|
28
|
-
"project-memory",
|
|
29
|
-
"agent-memory",
|
|
30
|
-
"ai-coding",
|
|
31
|
-
"multi-agent",
|
|
32
|
-
"llm",
|
|
33
|
-
"developer-tools",
|
|
34
|
-
"developer-productivity",
|
|
35
|
-
"cli",
|
|
36
|
-
"ty-context",
|
|
37
|
-
"workflow"
|
|
38
|
-
],
|
|
39
|
-
"type": "module",
|
|
40
|
-
"bin": {
|
|
41
|
-
"ty-context": "dist/cli.js"
|
|
42
|
-
},
|
|
43
|
-
"files": [
|
|
44
|
-
"README.md",
|
|
45
|
-
"dist",
|
|
46
|
-
"assets",
|
|
47
|
-
"migrations",
|
|
48
|
-
"source-mappings.yaml"
|
|
49
|
-
],
|
|
50
|
-
"scripts": {
|
|
51
|
-
"build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
|
|
52
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
53
|
-
"test:built": "node --test ../../tests/ty-context/*.test.mjs",
|
|
54
|
-
"test": "npm run build && node --test ../../tests/ty-context/*.test.mjs",
|
|
55
|
-
"prepack": "npm run build"
|
|
56
|
-
},
|
|
57
|
-
"engines": {
|
|
58
|
-
"node": ">=24"
|
|
59
|
-
},
|
|
60
|
-
"dependencies": {
|
|
61
|
-
"@google/design.md": "^0.3.0",
|
|
62
|
-
"impeccable": "^3.1.0",
|
|
63
|
-
"yaml": "^2.9.0"
|
|
64
|
-
},
|
|
65
|
-
"devDependencies": {
|
|
66
|
-
"@types/node": "^26.0.0",
|
|
67
|
-
"typescript": "^5.5.0"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "project-tiny-context-harness",
|
|
3
|
+
"version": "0.2.83",
|
|
4
|
+
"description": "Minimal project memory and validation harness for AI coding agents.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Seven128",
|
|
7
|
+
"homepage": "https://github.com/Seven128/project-tiny-context-harness#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/Seven128/project-tiny-context-harness.git",
|
|
11
|
+
"directory": "packages/ty-context"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/Seven128/project-tiny-context-harness/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ai-agents",
|
|
18
|
+
"coding-agent",
|
|
19
|
+
"codex",
|
|
20
|
+
"claude-code",
|
|
21
|
+
"cursor",
|
|
22
|
+
"gemini-cli",
|
|
23
|
+
"opencode",
|
|
24
|
+
"agent-context",
|
|
25
|
+
"context-engineering",
|
|
26
|
+
"context-management",
|
|
27
|
+
"agents-md",
|
|
28
|
+
"project-memory",
|
|
29
|
+
"agent-memory",
|
|
30
|
+
"ai-coding",
|
|
31
|
+
"multi-agent",
|
|
32
|
+
"llm",
|
|
33
|
+
"developer-tools",
|
|
34
|
+
"developer-productivity",
|
|
35
|
+
"cli",
|
|
36
|
+
"ty-context",
|
|
37
|
+
"workflow"
|
|
38
|
+
],
|
|
39
|
+
"type": "module",
|
|
40
|
+
"bin": {
|
|
41
|
+
"ty-context": "dist/cli.js"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"README.md",
|
|
45
|
+
"dist",
|
|
46
|
+
"assets",
|
|
47
|
+
"migrations",
|
|
48
|
+
"source-mappings.yaml"
|
|
49
|
+
],
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
|
|
52
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
53
|
+
"test:built": "node --test ../../tests/ty-context/*.test.mjs",
|
|
54
|
+
"test": "npm run build && node --test ../../tests/ty-context/*.test.mjs",
|
|
55
|
+
"prepack": "npm run build"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=24"
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@google/design.md": "^0.3.0",
|
|
62
|
+
"impeccable": "^3.1.0",
|
|
63
|
+
"yaml": "^2.9.0"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@types/node": "^26.0.0",
|
|
67
|
+
"typescript": "^5.5.0"
|
|
68
|
+
}
|
|
69
|
+
}
|
package/source-mappings.yaml
CHANGED
|
@@ -17,6 +17,9 @@ source_mappings:
|
|
|
17
17
|
- source: ".codex/ty-context-managed/make/ty-context.mk"
|
|
18
18
|
target: "packages/ty-context/assets/make/ty-context.mk"
|
|
19
19
|
mode: "copy-file"
|
|
20
|
+
- source: ".codex/ty-context-managed/protected-harness-baseline.json"
|
|
21
|
+
target: "packages/ty-context/assets/protected-harness-baseline.json"
|
|
22
|
+
mode: "copy-file"
|
|
20
23
|
- source: ".codex/ty-context-managed/minimal_tools"
|
|
21
24
|
target: "packages/ty-context/assets/tools"
|
|
22
25
|
mode: "copy-tree"
|