project-tiny-context-harness 0.7.3 → 0.7.5

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.
Files changed (105) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +355 -343
  3. package/assets/README.md +539 -494
  4. package/assets/README.zh-CN.md +300 -273
  5. package/assets/agents/.gitkeep +1 -1
  6. package/assets/agents/AGENTS_CORE.md +55 -53
  7. package/assets/context_templates/architecture.md +33 -33
  8. package/assets/context_templates/area.md +39 -39
  9. package/assets/context_templates/context.toml +30 -30
  10. package/assets/context_templates/deployment.md +35 -35
  11. package/assets/context_templates/global.md +51 -51
  12. package/assets/context_templates/product-surface-contract.md +64 -57
  13. package/assets/context_templates/screen-contract.md +180 -0
  14. package/assets/context_templates/verification.md +32 -32
  15. package/assets/github/.gitkeep +1 -1
  16. package/assets/github/harness.yml +41 -41
  17. package/assets/make/.gitkeep +1 -1
  18. package/assets/make/ty-context.mk +48 -48
  19. package/assets/skills/context_development_engineer/SKILL.md +92 -90
  20. package/assets/skills/context_full_project_export/SKILL.md +70 -70
  21. package/assets/skills/context_harness_upgrade/SKILL.md +60 -60
  22. package/assets/skills/context_product_plan/SKILL.md +77 -76
  23. package/assets/skills/context_surface_contract/SKILL.md +177 -162
  24. package/assets/skills/context_uiux_design/SKILL.md +108 -91
  25. package/assets/skills/long-task-workflow/SKILL.md +83 -83
  26. package/assets/skills/long-task-workflow/agents/openai.yaml +4 -4
  27. package/assets/skills/long-task-workflow/references/authority-lifecycle.md +57 -53
  28. package/assets/skills/long-task-workflow/references/contract-authoring.md +95 -77
  29. package/assets/skills/long-task-workflow/references/evidence-design.md +71 -58
  30. package/assets/skills/normal-long-task/SKILL.md +12 -12
  31. package/assets/skills/source-plan-authoring/SKILL.md +293 -290
  32. package/dist/commands/long-task-authoring.js +25 -0
  33. package/dist/commands/long-task.js +3 -0
  34. package/dist/lib/design-md.d.ts +7 -0
  35. package/dist/lib/design-md.js +47 -6
  36. package/dist/lib/doctor.js +19 -4
  37. package/dist/lib/long-task-activation-validation.js +13 -2
  38. package/dist/lib/long-task-authoring-authority-preview.js +1 -0
  39. package/dist/lib/long-task-authority-material-diff.js +54 -0
  40. package/dist/lib/long-task-authority-materials.d.ts +2 -2
  41. package/dist/lib/long-task-authority-materials.js +20 -0
  42. package/dist/lib/long-task-authority-policy.d.ts +26 -0
  43. package/dist/lib/long-task-authority-policy.js +23 -0
  44. package/dist/lib/long-task-authority-revision-analysis.d.ts +33 -0
  45. package/dist/lib/long-task-authority-revision-analysis.js +91 -0
  46. package/dist/lib/long-task-authority-revision.js +93 -158
  47. package/dist/lib/long-task-authority-types.d.ts +21 -0
  48. package/dist/lib/long-task-authority.js +32 -3
  49. package/dist/lib/long-task-check-evidence-decoder.d.ts +2 -2
  50. package/dist/lib/long-task-check-evidence-decoder.js +11 -1
  51. package/dist/lib/long-task-check-execution-policy.d.ts +3 -0
  52. package/dist/lib/long-task-check-execution-policy.js +5 -0
  53. package/dist/lib/long-task-check-runner.js +2 -0
  54. package/dist/lib/long-task-check-shape.js +33 -3
  55. package/dist/lib/long-task-claim-definitions.js +14 -0
  56. package/dist/lib/long-task-conformance-policy.d.ts +5 -0
  57. package/dist/lib/long-task-conformance-policy.js +35 -0
  58. package/dist/lib/long-task-contract-types.d.ts +28 -4
  59. package/dist/lib/long-task-delivery-compiler.js +1 -0
  60. package/dist/lib/long-task-delivery-parser.js +5 -2
  61. package/dist/lib/long-task-delivery-types.d.ts +2 -0
  62. package/dist/lib/long-task-delivery-types.js +2 -0
  63. package/dist/lib/long-task-delivery-validation.js +11 -0
  64. package/dist/lib/long-task-evidence-capability-codec.d.ts +2 -0
  65. package/dist/lib/long-task-evidence-capability-codec.js +231 -0
  66. package/dist/lib/long-task-evidence-capability-policy.d.ts +8 -0
  67. package/dist/lib/long-task-evidence-capability-policy.js +147 -0
  68. package/dist/lib/long-task-evidence-capability-runtime.d.ts +2 -0
  69. package/dist/lib/long-task-evidence-capability-runtime.js +86 -0
  70. package/dist/lib/long-task-evidence-capability-types.d.ts +74 -0
  71. package/dist/lib/long-task-evidence-capability-types.js +1 -0
  72. package/dist/lib/long-task-evidence-findings.js +5 -1
  73. package/dist/lib/long-task-evidence-v2.js +38 -23
  74. package/dist/lib/long-task-final-v2.js +42 -1
  75. package/dist/lib/long-task-outcome-parser.js +14 -3
  76. package/dist/lib/long-task-playwright-evidence.d.ts +2 -1
  77. package/dist/lib/long-task-playwright-evidence.js +70 -2
  78. package/dist/lib/long-task-product-shape.js +28 -0
  79. package/dist/lib/long-task-progress.js +4 -0
  80. package/dist/lib/long-task-root-shape.d.ts +1 -0
  81. package/dist/lib/long-task-root-shape.js +84 -3
  82. package/dist/lib/long-task-runner-environment.js +1 -1
  83. package/dist/lib/long-task-runner-freeze.d.ts +2 -2
  84. package/dist/lib/long-task-runner-freeze.js +3 -1
  85. package/dist/lib/long-task-runtime-types.d.ts +13 -0
  86. package/dist/lib/long-task-semantic-contract-types.d.ts +36 -0
  87. package/dist/lib/long-task-semantic-contract-types.js +1 -0
  88. package/dist/lib/long-task-semantic-drift-migration.d.ts +3 -0
  89. package/dist/lib/long-task-semantic-drift-migration.js +68 -0
  90. package/dist/lib/long-task-shape-primitives.d.ts +3 -0
  91. package/dist/lib/long-task-shape-primitives.js +25 -0
  92. package/dist/lib/long-task-source-target-index.js +14 -0
  93. package/dist/lib/long-task-stage-policy.d.ts +4 -0
  94. package/dist/lib/long-task-stage-policy.js +120 -0
  95. package/dist/lib/long-task-status-projection.d.ts +4 -1
  96. package/dist/lib/long-task-status-projection.js +63 -3
  97. package/dist/lib/long-task-status-v2.d.ts +11 -1
  98. package/dist/lib/long-task-status-v2.js +25 -3
  99. package/dist/lib/long-task-target-policy.d.ts +6 -0
  100. package/dist/lib/long-task-target-policy.js +127 -0
  101. package/dist/lib/migrations.js +29 -0
  102. package/dist/schemas/long-task-delivery-v2/long-task-delivery-v2.schema.json +62 -8
  103. package/migrations/README.md +15 -8
  104. package/package.json +2 -2
  105. package/source-mappings.yaml +25 -25
@@ -1,13 +1,21 @@
1
1
  import { progressRecordFresh } from "./long-task-progress.js";
2
2
  export function projectDeliveryStatus(input) {
3
3
  const outcomes = projectOutcomes(input);
4
+ const stages = projectStages(input.compiled, outcomes);
4
5
  return {
5
6
  finalResult: projectFinalResult(input),
6
7
  finalWorkflowStatus: receiptFresh(input)
7
8
  ? input.receipt.workflow_status
8
9
  : null,
10
+ targetState: receiptFresh(input)
11
+ ? (input.receipt.target_state ?? legacyTargetState(input.receipt))
12
+ : "not_accepted",
9
13
  outcomes,
10
- readyOutcomes: readyOutcomes(input.compiled, outcomes),
14
+ stages,
15
+ readyStages: Object.entries(stages)
16
+ .filter(([, status]) => status === "ready")
17
+ .map(([key]) => key),
18
+ readyOutcomes: readyOutcomes(input.compiled, outcomes, stages),
11
19
  needsReverify: Object.entries(outcomes)
12
20
  .filter(([, status]) => ["unverified", "progress_stale", "progress_failing"].includes(status))
13
21
  .map(([key]) => key),
@@ -88,12 +96,64 @@ function projectFindings(input) {
88
96
  }
89
97
  return findings;
90
98
  }
91
- function readyOutcomes(compiled, outcomes) {
99
+ function readyOutcomes(compiled, outcomes, stages) {
92
100
  return compiled.outcomes
93
- .filter((outcome) => outcomes[outcome.key] !== "progress_passing" &&
101
+ .filter((outcome) => stages[outcome.stage] !== "locked" &&
102
+ stages[outcome.stage] !== "progress_passing" &&
103
+ outcomes[outcome.key] !== "progress_passing" &&
94
104
  outcome.depends_on.every((dependency) => outcomes[dependency] === "progress_passing"))
95
105
  .map((outcome) => outcome.key);
96
106
  }
107
+ function legacyTargetState(receipt) {
108
+ if (receipt.workflow_status === "machine_accepted" ||
109
+ receipt.workflow_status === "machine_accepted_external_pending")
110
+ return receipt.target_profile.required_state;
111
+ return receipt.workflow_status === "blocked_external"
112
+ ? "blocked_external"
113
+ : "not_accepted";
114
+ }
115
+ function projectStages(compiled, outcomes) {
116
+ const result = {};
117
+ const remaining = new Set(compiled.stages.map((stage) => stage.key));
118
+ while (remaining.size) {
119
+ let advanced = false;
120
+ for (const stage of compiled.stages) {
121
+ if (!remaining.has(stage.key))
122
+ continue;
123
+ if (stage.depends_on.some((dependency) => remaining.has(dependency)))
124
+ continue;
125
+ const prerequisitesPassing = stage.depends_on.every((dependency) => result[dependency] === "progress_passing");
126
+ if (!prerequisitesPassing)
127
+ result[stage.key] = "locked";
128
+ else {
129
+ const owned = compiled.outcomes
130
+ .filter((outcome) => outcome.stage === stage.key)
131
+ .map((outcome) => outcomes[outcome.key]);
132
+ const gate = outcomes[stage.gate_outcome];
133
+ result[stage.key] = owned.includes("progress_failing")
134
+ ? "progress_failing"
135
+ : owned.includes("blocked_external")
136
+ ? "blocked_external"
137
+ : owned.includes("progress_stale")
138
+ ? "progress_stale"
139
+ : gate === "progress_passing" &&
140
+ owned.every((status) => status === "progress_passing")
141
+ ? "progress_passing"
142
+ : owned.every((status) => status === "unverified")
143
+ ? "ready"
144
+ : "unverified";
145
+ }
146
+ remaining.delete(stage.key);
147
+ advanced = true;
148
+ }
149
+ if (!advanced) {
150
+ for (const stage of remaining)
151
+ result[stage] = "locked";
152
+ break;
153
+ }
154
+ }
155
+ return result;
156
+ }
97
157
  function projectFinalResult(input) {
98
158
  if (!input.receipt)
99
159
  return "no_final_gate";
@@ -1,5 +1,5 @@
1
1
  import type { AuthorityRevisionDecisionV2 } from "./long-task-authority-revision-types.js";
2
- import type { ExternalConfirmationV2, FinalReceiptV2, LongTaskFindingV2, OutcomeStatusV2 } from "./long-task-delivery-types.js";
2
+ import type { ExternalConfirmationV2, FinalReceiptV2, LongTaskFindingV2, OutcomeStatusV2, StageStatusV2, TargetProfileV2 } from "./long-task-delivery-types.js";
3
3
  import { type AuditGateStatusV2 } from "./long-task-status-projection.js";
4
4
  export interface DeliveryStatusV2 {
5
5
  schema_version: "long-task-status-v2";
@@ -13,7 +13,11 @@ export interface DeliveryStatusV2 {
13
13
  final_result: AuditGateStatusV2;
14
14
  final_workflow_status: FinalReceiptV2["workflow_status"] | null;
15
15
  external_confirmations: ExternalConfirmationV2[];
16
+ target_profile: TargetProfileV2;
17
+ target_state: FinalReceiptV2["target_state"];
16
18
  outcomes: Record<string, OutcomeStatusV2>;
19
+ stages: Record<string, StageStatusV2>;
20
+ ready_stages: string[];
17
21
  ready_outcomes: string[];
18
22
  ready_for_implementation: string[];
19
23
  needs_reverify: string[];
@@ -31,6 +35,9 @@ export interface StopCheckDeliveryResultV2 {
31
35
  reason: string;
32
36
  workflow_status?: FinalReceiptV2["workflow_status"];
33
37
  external_confirmations?: ExternalConfirmationV2[];
38
+ target_profile?: TargetProfileV2;
39
+ target_state?: FinalReceiptV2["target_state"];
40
+ stage_results?: FinalReceiptV2["stage_results"];
34
41
  acceptance_scope?: "declared_machine_authority";
35
42
  native_goal_effect?: "none";
36
43
  message?: string;
@@ -39,6 +46,9 @@ export interface CloseDeliveryResultV2 {
39
46
  status: "closed";
40
47
  workflow_status: Extract<FinalReceiptV2["workflow_status"], "machine_accepted" | "machine_accepted_external_pending">;
41
48
  external_confirmations: ExternalConfirmationV2[];
49
+ target_profile: TargetProfileV2;
50
+ target_state: FinalReceiptV2["target_state"];
51
+ stage_results: FinalReceiptV2["stage_results"];
42
52
  acceptance_scope: "declared_machine_authority";
43
53
  closed_scope: "machine_authority";
44
54
  native_goal_effect: "none";
@@ -53,7 +53,11 @@ async function readDeliveryStatusForAuthority(active) {
53
53
  final_result: projection.finalResult,
54
54
  final_workflow_status: projection.finalWorkflowStatus,
55
55
  external_confirmations: compiled.global.acceptance.external_confirmations,
56
+ target_profile: compiled.task.target_profile,
57
+ target_state: projection.targetState,
56
58
  outcomes: projection.outcomes,
59
+ stages: projection.stages,
60
+ ready_stages: projection.readyStages,
57
61
  ready_outcomes: projection.readyOutcomes,
58
62
  ready_for_implementation: projection.readyOutcomes,
59
63
  needs_reverify: projection.needsReverify,
@@ -89,6 +93,8 @@ export async function resumeDeliveryTask(workdir) {
89
93
  id: compiled.task.id,
90
94
  title: compiled.task.title,
91
95
  goal: compiled.task.goal,
96
+ target_profile: compiled.task.target_profile,
97
+ execution_targets: compiled.task.execution_targets,
92
98
  },
93
99
  contract_identity: compiled.compiled_identity,
94
100
  authority_revision: compiled.authority_revision,
@@ -101,7 +107,11 @@ export async function resumeDeliveryTask(workdir) {
101
107
  last_gate: status.final_result,
102
108
  final_workflow_status: status.final_workflow_status,
103
109
  external_confirmations: status.external_confirmations,
110
+ target_profile: status.target_profile,
111
+ target_state: status.target_state,
104
112
  outcomes: status.outcomes,
113
+ stages: status.stages,
114
+ ready_stages: status.ready_stages,
105
115
  ready_outcomes: status.ready_outcomes,
106
116
  ready_for_implementation: status.ready_for_implementation,
107
117
  needs_reverify: status.needs_reverify,
@@ -216,6 +226,9 @@ export async function stopCheckDeliveryTask(workdirInput, messageText = "") {
216
226
  reason: "active_authority_changed_after_final_gate",
217
227
  workflow_status: result.workflow_status,
218
228
  external_confirmations: result.external_confirmations,
229
+ target_profile: result.target_profile,
230
+ target_state: result.target_state,
231
+ stage_results: result.stage_results,
219
232
  message: "Active Authority changed after the Live Final Gate; the accepted identity was not cleared.",
220
233
  };
221
234
  throw error;
@@ -225,9 +238,12 @@ export async function stopCheckDeliveryTask(workdirInput, messageText = "") {
225
238
  reason: result.workflow_status,
226
239
  workflow_status: result.workflow_status,
227
240
  external_confirmations: result.external_confirmations,
241
+ target_profile: result.target_profile,
242
+ target_state: result.target_state,
243
+ stage_results: result.stage_results,
228
244
  acceptance_scope: "declared_machine_authority",
229
245
  native_goal_effect: "none",
230
- message: acceptedScopeMessage(result.workflow_status, result.external_confirmations),
246
+ message: acceptedScopeMessage(result.workflow_status, result.external_confirmations, result.target_profile),
231
247
  };
232
248
  }
233
249
  return {
@@ -235,6 +251,9 @@ export async function stopCheckDeliveryTask(workdirInput, messageText = "") {
235
251
  reason: `live_final_gate_${result.workflow_status}`,
236
252
  workflow_status: result.workflow_status,
237
253
  external_confirmations: result.external_confirmations,
254
+ target_profile: result.target_profile,
255
+ target_state: result.target_state,
256
+ stage_results: result.stage_results,
238
257
  message: messageText ||
239
258
  result.findings.at(-1)?.next_action ||
240
259
  "Repair the failing Check and rerun Stop.",
@@ -274,13 +293,16 @@ export async function closeDeliveryTask(workdir) {
274
293
  status: "closed",
275
294
  workflow_status: result.workflow_status,
276
295
  external_confirmations: result.external_confirmations,
296
+ target_profile: result.target_profile,
297
+ target_state: result.target_state,
298
+ stage_results: result.stage_results,
277
299
  acceptance_scope: "declared_machine_authority",
278
300
  closed_scope: "machine_authority",
279
301
  native_goal_effect: "none",
280
302
  };
281
303
  }
282
- function acceptedScopeMessage(workflowStatus, confirmations) {
283
- const scope = "Declared machine Authority accepted and cleared. This result has no direct effect on the platform-native Goal; before completing it, confirm current Goal/user meaning is fully represented by accepted Source and no revision, blocker, or omitted requirement remains.";
304
+ function acceptedScopeMessage(workflowStatus, confirmations, targetProfile) {
305
+ const scope = `Declared machine Authority accepted for target ${targetProfile.key}:${targetProfile.required_state} and cleared. This result has no direct effect on the platform-native Goal; before completing it, confirm current Goal/user meaning is fully represented by accepted Source and no revision, blocker, or omitted requirement remains.`;
284
306
  if (workflowStatus === "machine_accepted")
285
307
  return scope;
286
308
  const pending = confirmations
@@ -0,0 +1,6 @@
1
+ import type { CompiledClaimsV2 } from "./long-task-claims.js";
2
+ import type { DeliveryContractV2 } from "./long-task-delivery-types.js";
3
+ type Reporter = (message: string) => void;
4
+ export declare function validateExecutionTargets(contract: DeliveryContractV2, report?: Reporter): void;
5
+ export declare function validateExternalConfirmationImpacts(contract: DeliveryContractV2, claims: CompiledClaimsV2, report?: Reporter): void;
6
+ export {};
@@ -0,0 +1,127 @@
1
+ export function validateExecutionTargets(contract, report) {
2
+ const targets = indexExecutionTargets(contract, report);
3
+ const requiredTargetRefs = contract.task.target_profile.required_target_refs;
4
+ validateRequiredTargetRefs(contract, targets, report);
5
+ for (const [outcomeKey, check] of allChecks(contract))
6
+ validateCheckTarget(outcomeKey, check, targets, report);
7
+ validateCriticalPathTargets(contract, requiredTargetRefs, report);
8
+ }
9
+ function indexExecutionTargets(contract, report) {
10
+ const targets = new Map();
11
+ for (const target of contract.task.execution_targets) {
12
+ if (targets.has(target.key))
13
+ issue(report, "execution_target_key_duplicate", target.key);
14
+ targets.set(target.key, target);
15
+ }
16
+ if (![...targets.values()].some((target) => target.role === "product"))
17
+ issue(report, "product_execution_target_required", contract.task.id);
18
+ return targets;
19
+ }
20
+ function validateRequiredTargetRefs(contract, targets, report) {
21
+ const required = contract.task.target_profile.required_target_refs;
22
+ if (!required.length)
23
+ issue(report, "target_profile_required_target_refs_required", contract.task.id);
24
+ if (new Set(required).size !== required.length)
25
+ issue(report, "target_profile_required_target_refs_duplicate", contract.task.id);
26
+ for (const targetRef of required) {
27
+ const target = targets.get(targetRef);
28
+ if (!target)
29
+ issue(report, "target_profile_required_target_ref_unknown", targetRef);
30
+ else if (target.role !== "product")
31
+ issue(report, "target_profile_required_target_must_be_product", targetRef);
32
+ }
33
+ }
34
+ function validateCheckTarget(outcomeKey, check, targets, report) {
35
+ const target = targets.get(check.execution_target.target_ref);
36
+ const label = `${outcomeKey ?? "GLOBAL"}:${check.key}`;
37
+ if (!target) {
38
+ issue(report, "check_execution_target_unknown", `${label}:${check.execution_target.target_ref}`);
39
+ return;
40
+ }
41
+ if ((check.runner.type === "playwright_test" ||
42
+ check.proof_surface === "ui_browser") &&
43
+ target.runtime_family !== "browser")
44
+ issue(report, "browser_check_target_mismatch", `${label}:${target.key}`);
45
+ if (provesTargetRuntime(check) &&
46
+ target.runtime_family === "browser" &&
47
+ check.runner.type !== "playwright_test")
48
+ issue(report, "browser_target_runtime_requires_playwright", `${label}:${target.key}`);
49
+ if (provesTargetRuntime(check) &&
50
+ ["native", "desktop"].includes(target.runtime_family) &&
51
+ check.runner.type !== "project_binary")
52
+ issue(report, "native_target_runtime_requires_project_binary", `${label}:${target.key}`);
53
+ validateStageGateTarget(label, check, target, report);
54
+ validateConformanceTarget(outcomeKey, check, target, report);
55
+ }
56
+ function validateStageGateTarget(label, check, target, report) {
57
+ if (!check.journey_roles.includes("stage_gate"))
58
+ return;
59
+ if (target.role !== "product")
60
+ issue(report, "stage_gate_product_target_required", `${label}:${target.key}`);
61
+ if (check.execution_target.entrypoint !== "root")
62
+ issue(report, "stage_gate_root_entrypoint_required", label);
63
+ }
64
+ function validateConformanceTarget(outcomeKey, check, target, report) {
65
+ if (!check.journey_roles.includes("conformance"))
66
+ return;
67
+ if (outcomeKey !== null)
68
+ issue(report, "conformance_check_must_be_global", `${outcomeKey}:${check.key}`);
69
+ if (target.role !== "product" || check.execution_target.entrypoint !== "root")
70
+ issue(report, "conformance_root_product_target_required", check.key);
71
+ }
72
+ function validateCriticalPathTargets(contract, requiredTargetRefs, report) {
73
+ for (const outcomeKey of contract.risk.facts.critical_user_path) {
74
+ const outcome = contract.outcomes.find((candidate) => candidate.key === outcomeKey);
75
+ if (!outcome)
76
+ continue;
77
+ for (const targetRef of requiredTargetRefs)
78
+ if (!outcome.acceptance.checks.some((check) => provesSuccess(check, targetRef)))
79
+ issue(report, "critical_path_required_target_proof_missing", `${outcome.key}:${targetRef}`);
80
+ }
81
+ }
82
+ function provesSuccess(check, targetRef) {
83
+ return (check.execution_target.target_ref === targetRef &&
84
+ check.journey_roles.includes("success") &&
85
+ check.execution_target.entrypoint === "root" &&
86
+ provesTargetRuntime(check));
87
+ }
88
+ function provesTargetRuntime(check) {
89
+ return [...check.positive_assertions, ...check.negative_assertions].some((assertion) => assertion.evidence_capabilities.includes("target_runtime"));
90
+ }
91
+ export function validateExternalConfirmationImpacts(contract, claims, report) {
92
+ const claimRefs = new Set();
93
+ for (const [outcomeKey, values] of Object.entries(claims.by_outcome))
94
+ for (const claim of values)
95
+ claimRefs.add(`${outcomeKey}.${claim.local_key}`);
96
+ for (const claim of claims.by_global)
97
+ claimRefs.add(`GLOBAL.${claim.local_key}`);
98
+ for (const confirmation of contract.global.acceptance
99
+ .external_confirmations) {
100
+ if (!confirmation.impact_claims.length)
101
+ issue(report, "external_confirmation_impact_required", confirmation.key);
102
+ for (const claim of confirmation.impact_claims)
103
+ if (!claimRefs.has(claim))
104
+ issue(report, "external_confirmation_impact_unknown", `${confirmation.key}:${claim}`);
105
+ if (confirmation.kind === "functional_prerequisite" &&
106
+ !confirmation.blocks_target)
107
+ issue(report, "functional_prerequisite_must_block_target", confirmation.key);
108
+ if (confirmation.kind === "production_release_gate" &&
109
+ contract.task.target_profile.required_state ===
110
+ "production_release_ready" &&
111
+ !confirmation.blocks_target)
112
+ issue(report, "production_gate_must_block_release_target", confirmation.key);
113
+ }
114
+ }
115
+ function allChecks(contract) {
116
+ return [
117
+ ...contract.global.acceptance.checks.map((check) => [null, check]),
118
+ ...contract.outcomes.flatMap((outcome) => outcome.acceptance.checks.map((check) => [outcome.key, check])),
119
+ ];
120
+ }
121
+ function issue(report, code, detail) {
122
+ const message = `delivery_contract_invalid:${code}:${detail}`;
123
+ if (report)
124
+ report(message);
125
+ else
126
+ throw new Error(message);
127
+ }
@@ -9,11 +9,22 @@ import { ensureDir, listFiles, pathExists, readText, writeTextIfChanged, } from
9
9
  import { harnessConfigPath, harnessRoot } from "./harness-root.js";
10
10
  import { legacySdlcHarnessMigration } from "./legacy-sdlc-migration.js";
11
11
  import { parseYaml, stringifyYaml } from "./yaml.js";
12
+ import { semanticDriftMigrationFields } from "./long-task-semantic-drift-migration.js";
12
13
  async function verifyNoop() {
13
14
  return;
14
15
  }
15
16
  export const migrations = [
16
17
  legacySdlcHarnessMigration,
18
+ {
19
+ id: "long-task-v2-semantic-drift-authority",
20
+ introducedIn: "0.7.2",
21
+ description: "Require explicit Stage, target profile/root runtime, journey scenario and evidence-capability authority in V2 Long-Task Contracts.",
22
+ scope: ".long-task/delivery-contract.yaml",
23
+ risk: "manual",
24
+ manualMessage: "These product and proof semantics cannot be inferred safely. Preserve Source, then explicitly author stages, vertical Outcome membership, target profile and execution targets, success/degradation requirements, Given/When scenarios, evidence capabilities and typed external-confirmation impact before recompiling. Historical Progress and Receipts remain audit-only and must not be imported as acceptance.",
25
+ detect: detectLongTaskSemanticDriftAuthority,
26
+ verify: verifyNoop,
27
+ },
17
28
  {
18
29
  id: "long-task-v1-retirement",
19
30
  introducedIn: "0.6.0",
@@ -102,6 +113,24 @@ export const migrations = [
102
113
  verify: verifyNoop,
103
114
  },
104
115
  ];
116
+ async function detectLongTaskSemanticDriftAuthority(projectRoot, _root, migration) {
117
+ const contract = path.join(projectRoot, ".long-task", "delivery-contract.yaml");
118
+ if (!(await pathExists(contract)))
119
+ return [];
120
+ let decoded;
121
+ try {
122
+ decoded = parseYaml(await readText(contract));
123
+ }
124
+ catch {
125
+ return [];
126
+ }
127
+ const fields = semanticDriftMigrationFields(decoded);
128
+ if (!fields.length)
129
+ return [];
130
+ return [
131
+ item(migration, "manual_required", ".long-task/delivery-contract.yaml", `The active/draft V2 Contract predates semantic-drift authority and is missing: ${fields.slice(0, 12).join(", ")}${fields.length > 12 ? `, +${fields.length - 12} more` : ""}. Re-author these meanings from Source; do not synthesize them from old passing evidence.`),
132
+ ];
133
+ }
105
134
  async function detectLongTaskV1Retirement(projectRoot, root, migration) {
106
135
  const items = [];
107
136
  const hook = path.join(projectRoot, root, "hooks", "long-task-hook.mjs");
@@ -4,17 +4,19 @@
4
4
  "title": "Single-Goal Delivery Contract V2",
5
5
  "type": "object",
6
6
  "additionalProperties": false,
7
- "required": ["schema_version", "task", "source_claims", "risk", "global"],
7
+ "required": ["schema_version", "task", "source_claims", "stages", "risk", "global"],
8
8
  "properties": {
9
9
  "schema_version": { "const": "long-task-delivery-v2" },
10
10
  "task": {
11
11
  "type": "object",
12
12
  "additionalProperties": false,
13
- "required": ["id", "title", "goal", "source_paths", "context_refs"],
13
+ "required": ["id", "title", "goal", "target_profile", "execution_targets", "source_paths", "context_refs"],
14
14
  "properties": {
15
15
  "id": { "$ref": "#/$defs/key" },
16
16
  "title": { "$ref": "#/$defs/nonEmpty" },
17
17
  "goal": { "$ref": "#/$defs/nonEmpty" },
18
+ "target_profile": { "$ref": "#/$defs/targetProfile" },
19
+ "execution_targets": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/executionTarget" } },
18
20
  "source_paths": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/nonEmpty" } },
19
21
  "context_refs": { "$ref": "#/$defs/nonEmptyStrings" },
20
22
  "context_snapshot_mode": { "enum": ["referenced", "full"], "default": "referenced" }
@@ -25,6 +27,7 @@
25
27
  "minItems": 1,
26
28
  "items": { "$ref": "#/$defs/sourceClaim" }
27
29
  },
30
+ "stages": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/stage" } },
28
31
  "risk": { "$ref": "#/$defs/risk" },
29
32
  "global": { "$ref": "#/$defs/global" },
30
33
  "outcomes": { "type": "array", "items": { "$ref": "#/$defs/outcome" }, "minItems": 1 },
@@ -38,6 +41,40 @@
38
41
  "key": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
39
42
  "nonEmpty": { "type": "string", "minLength": 1 },
40
43
  "nonEmptyStrings": { "type": "array", "items": { "$ref": "#/$defs/nonEmpty" } },
44
+ "targetProfile": {
45
+ "type": "object",
46
+ "additionalProperties": false,
47
+ "required": ["key", "description", "required_state", "required_target_refs"],
48
+ "properties": {
49
+ "key": { "$ref": "#/$defs/key" },
50
+ "description": { "$ref": "#/$defs/nonEmpty" },
51
+ "required_state": { "enum": ["implementation_complete", "target_profile_usable", "production_release_ready"] },
52
+ "required_target_refs": { "$ref": "#/$defs/keys" }
53
+ }
54
+ },
55
+ "executionTarget": {
56
+ "type": "object",
57
+ "additionalProperties": false,
58
+ "required": ["key", "description", "role", "runtime_family", "root_entrypoint"],
59
+ "properties": {
60
+ "key": { "$ref": "#/$defs/key" },
61
+ "description": { "$ref": "#/$defs/nonEmpty" },
62
+ "role": { "enum": ["product", "support", "observer"] },
63
+ "runtime_family": { "enum": ["browser", "native", "desktop", "service", "process", "external"] },
64
+ "root_entrypoint": { "$ref": "#/$defs/nonEmpty" }
65
+ }
66
+ },
67
+ "stage": {
68
+ "type": "object",
69
+ "additionalProperties": false,
70
+ "required": ["key", "title", "depends_on", "gate_outcome"],
71
+ "properties": {
72
+ "key": { "$ref": "#/$defs/key" },
73
+ "title": { "$ref": "#/$defs/nonEmpty" },
74
+ "depends_on": { "$ref": "#/$defs/keys" },
75
+ "gate_outcome": { "$ref": "#/$defs/key" }
76
+ }
77
+ },
41
78
  "keyedStatement": {
42
79
  "type": "object",
43
80
  "additionalProperties": false,
@@ -114,7 +151,7 @@
114
151
  "properties": {
115
152
  "checks": { "type": "array", "items": { "$ref": "#/$defs/check" }, "default": [] },
116
153
  "counterfactual_controls": { "type": "array", "items": { "$ref": "#/$defs/globalCounterfactual" }, "default": [] },
117
- "external_confirmations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["key", "description", "owner"], "properties": { "key": { "$ref": "#/$defs/key" }, "description": { "$ref": "#/$defs/nonEmpty" }, "owner": { "$ref": "#/$defs/nonEmpty" } } }, "default": [] }
154
+ "external_confirmations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["key", "description", "owner", "kind", "impact_claims", "blocks_target"], "properties": { "key": { "$ref": "#/$defs/key" }, "description": { "$ref": "#/$defs/nonEmpty" }, "owner": { "$ref": "#/$defs/nonEmpty" }, "kind": { "enum": ["functional_prerequisite", "field_validation", "production_release_gate", "commercial_activation", "expert_authority"] }, "impact_claims": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/nonEmpty" } }, "blocks_target": { "type": "boolean" } } }, "default": [] }
118
155
  },
119
156
  "default": {}
120
157
  }
@@ -123,10 +160,11 @@
123
160
  "outcome": {
124
161
  "type": "object",
125
162
  "additionalProperties": false,
126
- "required": ["key", "title", "product", "technical", "acceptance"],
163
+ "required": ["key", "title", "stage", "product", "technical", "acceptance"],
127
164
  "properties": {
128
165
  "key": { "$ref": "#/$defs/key" },
129
166
  "title": { "$ref": "#/$defs/nonEmpty" },
167
+ "stage": { "$ref": "#/$defs/key" },
130
168
  "depends_on": { "$ref": "#/$defs/keys", "default": [] },
131
169
  "product": { "$ref": "#/$defs/product" },
132
170
  "technical": { "$ref": "#/$defs/technical" },
@@ -136,9 +174,11 @@
136
174
  "product": {
137
175
  "type": "object",
138
176
  "additionalProperties": false,
139
- "required": ["observable_result", "owner"],
177
+ "required": ["observable_result", "success_path_required", "degradation_path_required", "owner"],
140
178
  "properties": {
141
179
  "observable_result": { "$ref": "#/$defs/nonEmpty" },
180
+ "success_path_required": { "type": "boolean" },
181
+ "degradation_path_required": { "type": "boolean" },
142
182
  "owner": { "type": "object", "additionalProperties": false, "required": ["label", "context_refs", "path_globs"], "properties": { "label": { "$ref": "#/$defs/nonEmpty" }, "context_refs": { "$ref": "#/$defs/nonEmptyStrings" }, "path_globs": { "$ref": "#/$defs/nonEmptyStrings" } } },
143
183
  "requirements": { "type": "array", "items": { "$ref": "#/$defs/requirement" }, "default": [] },
144
184
  "owner_surfaces": { "$ref": "#/$defs/nonEmptyStrings", "default": [] },
@@ -156,7 +196,7 @@
156
196
  "type": "object",
157
197
  "additionalProperties": false,
158
198
  "required": ["key", "location"],
159
- "properties": { "key": { "$ref": "#/$defs/key" }, "location": { "$ref": "#/$defs/nonEmpty" }, "trigger": { "type": "string", "default": "" }, "input": { "type": "string", "default": "" }, "loading_state": { "type": "string", "default": "" }, "empty_state": { "type": "string", "default": "" }, "success_state": { "type": "string", "default": "" }, "failure_state": { "type": "string", "default": "" }, "feedback": { "type": "string", "default": "" } }
199
+ "properties": { "key": { "$ref": "#/$defs/key" }, "surface": { "type": "string", "default": "" }, "region": { "type": "string", "default": "" }, "location": { "$ref": "#/$defs/nonEmpty" }, "control_type": { "type": "string", "default": "" }, "label_content": { "type": "string", "default": "" }, "user_task": { "type": "string", "default": "" }, "visibility": { "type": "string", "default": "" }, "availability": { "type": "string", "default": "" }, "trigger": { "type": "string", "default": "" }, "input": { "type": "string", "default": "" }, "validation": { "type": "string", "default": "" }, "default_value": { "type": "string", "default": "" }, "interaction": { "type": "string", "default": "" }, "navigation_result": { "type": "string", "default": "" }, "loading_state": { "type": "string", "default": "" }, "empty_state": { "type": "string", "default": "" }, "success_state": { "type": "string", "default": "" }, "failure_state": { "type": "string", "default": "" }, "recovery": { "type": "string", "default": "" }, "permission": { "type": "string", "default": "" }, "feedback": { "type": "string", "default": "" }, "accessibility": { "type": "string", "default": "" } }
160
200
  },
161
201
  "technical": {
162
202
  "type": "object",
@@ -204,9 +244,12 @@
204
244
  "check": {
205
245
  "type": "object",
206
246
  "additionalProperties": false,
207
- "required": ["key", "proof_surface", "runner", "verification_inputs"],
247
+ "required": ["key", "journey_roles", "execution_target", "scenario", "proof_surface", "runner", "verification_inputs"],
208
248
  "properties": {
209
249
  "key": { "$ref": "#/$defs/key" },
250
+ "journey_roles": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "enum": ["success", "degradation", "recovery", "stage_gate", "conformance"] } },
251
+ "execution_target": { "type": "object", "additionalProperties": false, "required": ["target_ref", "entrypoint"], "properties": { "target_ref": { "$ref": "#/$defs/key" }, "entrypoint": { "enum": ["root", "internal"] } } },
252
+ "scenario": { "$ref": "#/$defs/scenario" },
210
253
  "proof_surface": { "$ref": "#/$defs/proofSurface" },
211
254
  "runner": { "$ref": "#/$defs/runner" },
212
255
  "verification_inputs": { "$ref": "#/$defs/nonEmptyStrings" },
@@ -236,12 +279,13 @@
236
279
  "assertion": {
237
280
  "type": "object",
238
281
  "additionalProperties": false,
239
- "required": ["key", "claims", "observation", "operator"],
282
+ "required": ["key", "claims", "observation", "operator", "evidence_capabilities"],
240
283
  "properties": {
241
284
  "key": { "$ref": "#/$defs/key" },
242
285
  "criterion": { "$ref": "#/$defs/nonEmpty" },
243
286
  "claims": { "$ref": "#/$defs/nonEmptyStrings" },
244
287
  "observation": { "$ref": "#/$defs/nonEmpty" },
288
+ "evidence_capabilities": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "$ref": "#/$defs/evidenceCapability" } },
245
289
  "operator": { "enum": ["equals", "not_equals", "contains", "not_contains", "matches", "not_matches", "greater_than", "greater_or_equal", "less_than", "less_or_equal", "truthy", "falsy", "exists", "set_equals", "subset_of", "superset_of"] },
246
290
  "expected": true
247
291
  },
@@ -268,6 +312,16 @@
268
312
  }
269
313
  ]
270
314
  },
315
+ "scenario": {
316
+ "type": "object",
317
+ "additionalProperties": false,
318
+ "required": ["given", "when"],
319
+ "properties": {
320
+ "given": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/keyedStatement" } },
321
+ "when": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/keyedStatement" } }
322
+ }
323
+ },
324
+ "evidenceCapability": { "enum": ["presence", "interaction_trace", "state_delta", "cross_surface_consistency", "durable_readback", "boundary_invocation", "external_side_effect", "failure_injection", "visual_render", "target_runtime", "input_variation"] },
271
325
  "environment": {
272
326
  "oneOf": [
273
327
  {
@@ -1,8 +1,15 @@
1
- # Migrations
2
-
3
- Schema migrations for Harness config and managed file layout belong here.
4
-
5
- Version 0.6.0 includes `long-task-v1-retirement`. It safely removes the
6
- retired repo-local Hook, reports a legacy active projection as
7
- `manual_required`, and deliberately does not import V1 progress or receipts
8
- into the V2 Claim/Evidence authority.
1
+ # Migrations
2
+
3
+ Schema migrations for Harness config and managed file layout belong here.
4
+
5
+ Version 0.6.0 includes `long-task-v1-retirement`. It safely removes the
6
+ retired repo-local Hook, reports a legacy active projection as
7
+ `manual_required`, and deliberately does not import V1 progress or receipts
8
+ into the V2 Claim/Evidence authority.
9
+
10
+ Version 0.7.2 includes `long-task-v2-semantic-drift-authority`. It reports a
11
+ conventional `.long-task/delivery-contract.yaml` as `manual_required` when the
12
+ V2 file predates explicit Stage, target-profile/root-runtime, journey-scenario,
13
+ success/degradation, evidence-capability or external-impact authority. Those
14
+ meanings must be re-authored from Source; migration never infers them from old
15
+ Progress or Receipts.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-tiny-context-harness",
3
- "version": "0.7.3",
3
+ "version": "0.7.5",
4
4
  "description": "Minimal project memory and validation harness for AI coding agents.",
5
5
  "license": "MIT",
6
6
  "author": "Seven128",
@@ -58,7 +58,7 @@
58
58
  "pretest": "npm run build",
59
59
  "test": "npm run test:built",
60
60
  "test:workflow-default:built": "node --test --test-concurrency=1 ../../tests/ty-context/workflow-contract-routing.test.mjs",
61
- "test:delivery-contract:built": "node --test --test-concurrency=1 ../../tests/ty-context/long-task-compact-authoring.test.mjs ../../tests/ty-context/long-task-authoring-claims.test.mjs ../../tests/ty-context/long-task-authoring-preflight.test.mjs ../../tests/ty-context/long-task-authority-authoring-fields.test.mjs ../../tests/ty-context/long-task-playwright-ac-evidence.test.mjs ../../tests/ty-context/long-task-delivery-parser.test.mjs ../../tests/ty-context/long-task-delivery-compiler.test.mjs ../../tests/ty-context/long-task-delivery-risk.test.mjs ../../tests/ty-context/long-task-claim-coverage.test.mjs ../../tests/ty-context/long-task-closure-invariants.test.mjs ../../tests/ty-context/long-task-source-authority-closure.test.mjs ../../tests/ty-context/long-task-evidence-sensitivity-policy.test.mjs ../../tests/ty-context/long-task-global-evidence-sensitivity.test.mjs ../../tests/ty-context/long-task-source-risk-binding.test.mjs ../../tests/ty-context/long-task-non-completing-source.test.mjs ../../tests/ty-context/long-task-playwright-trust-boundary.test.mjs ../../tests/ty-context/long-task-planned-counterfactual.test.mjs ../../tests/ty-context/long-task-public-contract-example.test.mjs ../../tests/ty-context/long-task-release-tarball-contract.test.mjs",
61
+ "test:delivery-contract:built": "node --test --test-concurrency=1 ../../tests/ty-context/long-task-compact-authoring.test.mjs ../../tests/ty-context/long-task-authoring-claims.test.mjs ../../tests/ty-context/long-task-authoring-preflight.test.mjs ../../tests/ty-context/long-task-authority-authoring-fields.test.mjs ../../tests/ty-context/long-task-playwright-ac-evidence.test.mjs ../../tests/ty-context/long-task-delivery-parser.test.mjs ../../tests/ty-context/long-task-delivery-compiler.test.mjs ../../tests/ty-context/long-task-delivery-risk.test.mjs ../../tests/ty-context/long-task-claim-coverage.test.mjs ../../tests/ty-context/long-task-closure-invariants.test.mjs ../../tests/ty-context/long-task-source-authority-closure.test.mjs ../../tests/ty-context/long-task-evidence-sensitivity-policy.test.mjs ../../tests/ty-context/long-task-global-evidence-sensitivity.test.mjs ../../tests/ty-context/long-task-source-risk-binding.test.mjs ../../tests/ty-context/long-task-non-completing-source.test.mjs ../../tests/ty-context/long-task-playwright-trust-boundary.test.mjs ../../tests/ty-context/long-task-planned-counterfactual.test.mjs ../../tests/ty-context/long-task-public-contract-example.test.mjs ../../tests/ty-context/long-task-release-tarball-contract.test.mjs ../../tests/ty-context/long-task-semantic-drift-closure.test.mjs ../../tests/ty-context/long-task-semantic-drift-lifecycle.test.mjs",
62
62
  "test:delivery-contract": "npm run build && npm run test:delivery-contract:built",
63
63
  "test:long-task-workflow:built": "node ../../tests/ty-context/run-package-suite.mjs long-task",
64
64
  "test:long-task-workflow": "npm run build && npm run test:long-task-workflow:built",