From 9c603d700f5eba7ab3dbebbd7b622a743519c8e0 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Mon, 28 Feb 2022 20:10:19 -0800
Subject: [PATCH 01/40] start the v14 spec with the v13 spec

The goal this time around will be to make small uncontroversial
changes, which can step us into paving the paths laid by node-tap,
Test::More, tappy, and many others over the years.  There will be no
innovation here, just cataloging what exists.

Goals:

* No changes will be accepted UNLESS they are already widely adopted by
  multiple implementations representing a majority of the TAP userbase.

* No changes will be blocked IF they are already widely adopted by
  multiple implementations representing a majority of the TAP userbase.

* Specification should remove as much ambiguity as possible, while
  maintaining backwards compatibility with existing TAP providers and
  consumers.

Features/Changes Anticipated:

* Change the version from 13 to 14 (of course)
* Require that yaml diagnostic blocks be actual yaml, stipulate that
  they are to be indented 2 spaces.
* Specify child tests (both indented and {}-wrapped buffered), indented
  4 spaces.
* Specify pragmas (at least, define the syntax, even if the specific
  keys are left up to implementations)
* Clean up and clarify ambiguous language.
---
 tap-version-14-specification.md | 473 ++++++++++++++++++++++++++++++++
 1 file changed, 473 insertions(+)
 create mode 100644 tap-version-14-specification.md

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
new file mode 100644
index 0000000..031c415
--- /dev/null
+++ b/tap-version-14-specification.md
@@ -0,0 +1,473 @@
+---
+layout: default
+title: TAP 13 specification
+---
+
+# NAME
+
+TAP13 - The Test Anything Protocol v13
+
+## SYNOPSIS
+
+TAP, the Test Anything Protocol, is a simple text-based interface between
+testing modules a test harness. TAP started life as part of the test
+harness for Perl but now has implementations in C/C++, Python, PHP, Perl,
+JavaScript, and probably others by the time you read this.  This document
+describes version 13 of TAP. Go to TAP to read about previous versions.
+
+## THE TAP13 FORMAT
+
+TAP13's general format is:
+
+```
+TAP version 13
+1..N
+ok 1 Description # Directive
+# Diagnostic
+  ---
+  message: 'Failure message'
+  severity: fail
+  data:
+    got:
+      - 1
+      - 3
+      - 2
+    expect:
+      - 1
+      - 2
+      - 3
+  ...
+ok 47 Description
+ok 48 Description
+more tests....
+```
+
+For example, a test file's output might look like:
+
+```
+TAP version 13
+1..4
+ok 1 - Input file opened
+not ok 2 - First line of the input valid
+  ---
+  message: 'First line invalid'
+  severity: fail
+  data:
+    got: 'Flirble'
+    expect: 'Fnible'
+  ...
+ok 3 - Read the rest of the file
+not ok 4 - Summarized correctly # TODO Not written yet
+  ---
+  message: "Can't make summary yet"
+  severity: todo
+  ...
+```
+
+## HARNESS BEHAVIOR
+
+In this document, the "harness" is any program analyzing TAP output.
+Typically this will be Perl's runtests program, or the underlying
+TAP::Harness-runtests> method.  A harness must only read TAP output from
+standard output and not from standard error. Lines written to standard
+output matching `/^(not )?ok\b/` must be interpreted as test lines. After a
+test line a block of lines starting with '---' and ending with '...' will
+be interpreted as an inline YAML document providing extended diagnostic
+information about the preceding test. All other lines must not be
+considered test output.
+
+## TESTS LINES AND THE PLAN
+
+### The version
+
+To indicate that this is TAP13 the first line must be
+
+```
+TAP version 13
+```
+
+### The plan
+
+The plan tells how many tests will be run, or how many tests have run. It's
+a check that the test file hasn't stopped prematurely. It must appear once,
+whether at the beginning or end of the output.  The plan is usually the
+second line of TAP output right after the version line, and it specifies
+how many test points are to follow. For example,
+
+```
+1..10
+```
+
+means you plan on running 10 tests. This is a safeguard in case your test
+file dies silently in the middle of its run. The plan is optional but if
+there is a plan before the test points it must be the first non-diagnostic
+line output by the test file.  In certain instances a test file may not
+know how many test points it will ultimately be running. In this case the
+plan can be the last non-diagnostic line in the output.  The plan cannot
+appear in the middle of the output, nor can it appear more than once.
+
+### The test line
+
+The core of TAP is the test line. A test file prints one test line test
+point executed. There must be at least one test line in TAP output. Each
+test line comprises the following elements:
+
+-    ok or not ok
+
+This tells whether the test point passed or failed. It must be at the
+beginning of the line. `/^not ok/` indicates a failed test point. `/^ok/`
+is a successful test point. This is the only mandatory part of the line.
+Note that unlike the Directives below, ok and not ok are case-sensitive.
+
+-    Test number
+
+TAP expects the ok or not ok to be followed by a test point number. If
+there is no number the harness must maintain its own counter until the
+script supplies test numbers again. So the following test output
+
+```
+1..6
+not ok
+ok
+not ok
+ok
+ok
+```
+
+has five tests. The sixth is missing. Test::Harness will generate
+
+```
+FAILED tests 1, 3, 6
+Failed 3/6 tests, 50.00% okay
+```
+
+-    Description Any text after the test number but before a # is the
+     description of the test point.
+
+```
+ok 42 this is the description of the test
+```
+
+Descriptions should not begin with a digit so that they are not confused
+with the test point number.  The harness may do whatever it wants with the
+description.
+
+-    Directive The test point may include a directive, following a hash on
+     the test line. There are currently two directives allowed: TODO and
+     SKIP. These are discussed below.
+
+To summarize:
+
+-    ok/not ok (required)
+-    Test number (recommended)
+-    Description (recommended)
+-    Directive (only when necessary)
+
+### YAML blocks
+
+If the test line is immediately followed by an indented block beginning
+with `/^\s+---/` and ending with `/^\s+.../` that block will be interpreted
+as an inline YAML document. The YAML encodes a data structure that provides
+more detailed information about the preceding test.  The YAML document is
+indented to make it visually distinct from the surrounding test results and
+to make it easier for the parser to recover if the trailing '...'
+terminator is missing.  For example:
+
+```
+not ok 3 Resolve address
+ ---
+ message: "Failed with error 'hostname peebles.example.com not found'"
+ severity: fail
+ data:
+   got:
+     hostname: 'peebles.example.com'
+     address: ~
+   expected:
+     hostname: 'peebles.example.com'
+     address: '85.193.201.85'
+ ...
+```
+
+For a harness written in Perl the corresponding data structure would look
+like this:
+
+```
+$diagnostic = {
+    'message'  => "Failed with error 'hostname peebles.example.com not found'",
+    'severity' => 'fail',
+    'data' => {
+        'got' => {
+            'hostname' => 'peebles.example.com',
+            'address'  => undef,
+        },
+        'expected' => {
+            'hostname' => 'peebles.example.com',
+            'address'  => '85.193.201.85',
+        }
+    },
+};
+```
+
+Currently (2007/03/17) the format of the data structure represented by a
+YAML block has not been standardized. It is likely that whatever schema
+emerges will be able to capture the kind of forensic information about a
+test's execution seen in the example above.
+
+## DIRECTIVES
+
+Directives are special notes that follow a # on the test line. Only two are
+currently defined: TODO and SKIP. Note that these two keywords are not
+case-sensitive.
+
+### TODO tests
+
+If the directive starts with # TODO, the test is counted as a todo test,
+and the text after TODO is the explanation.
+
+```
+not ok 13 # TODO bend space and time
+```
+
+Note that if the TODO has an explanation it must be separated from TODO by
+a space.  These tests represent a feature to be implemented or a bug to be
+fixed and act as something of an executable "things to do" list. They are
+not expected to succeed. Should a todo test point begin succeeding, the
+harness should report it as a bonus. This indicates that whatever you were
+supposed to do has been done and you should promote this to a normal test
+point.
+
+### Skipping tests
+
+If the directive starts with # SKIP, the test is counted as having been
+skipped. If the whole test file succeeds, the count of skipped tests is
+included in the generated output. The harness should report the text after
+# SKIP\S*\s+ as a reason for skipping.
+
+```
+ok 23 # skip Insufficient flogiston pressure.
+```
+
+Similarly, one can include an explanation in a plan line, emitted if the
+test file is skipped completely:
+
+```
+1..0 # Skipped: WWW::Mechanize not installed
+```
+
+## OTHER LINES
+
+### Bail out!
+
+As an emergency measure a test script can decide that further tests are
+useless (e.g. missing dependencies) and testing should stop immediately. In
+that case the test script prints the magic words
+
+```
+Bail out!
+```
+
+to standard output. Any message after these words must be displayed by the
+interpreter as the reason why testing must be stopped, as in
+
+```
+Bail out! MySQL is not running.
+```
+
+### Diagnostics
+
+Additional information may be put into the testing output on separate
+lines. Diagnostic lines should begin with a #, which the harness must
+ignore, at least as far as analyzing the test results. The harness is free,
+however, to display the diagnostics.  TAP13's YAML blocks are intended to
+replace diagnostics for most purposes but TAP13 consumers should maintain
+backwards compatibility by supporting them.
+
+### Anything else
+
+Any output that is not a version, a plan, a test line, a YAML block, a
+diagnostic or a bail out is incorrect. How a harness handles the incorrect
+line is undefined.  Test::Harness silently ignores incorrect lines, but
+will become more stringent in the future.  TAP::Harness reports TAP syntax
+errors at the end of a test run.
+
+## EXAMPLES
+
+All names, places, and events depicted in any example are wholly fictitious
+and bear no resemblance to, connection with, or relation to any real
+entity. Any such similarity is purely coincidental, unintentional, and
+unintended.
+
+### Common with explanation
+
+The following TAP listing declares that six tests follow as well as
+provides handy feedback as to what the test is about to do. All six tests
+pass.
+
+```
+TAP version 13
+1..6
+#
+# Create a new Board and Tile, then place
+# the Tile onto the board.
+#
+ok 1 - The object isa Board
+ok 2 - Board size is zero
+ok 3 - The object isa Tile
+ok 4 - Get possible places to put the Tile
+ok 5 - Placing the tile produces no error
+ok 6 - Board size is 1
+```
+
+### Unknown amount and failures
+
+This hypothetical test program ensures that a handful of servers are online
+and network-accessible. Because it retrieves the hypothetical servers from
+a database, it doesn't know exactly how many servers it will need to ping.
+Thus, the test count is declared at the bottom after all the test points
+have run. Also, two of the tests fail. The YAML block following each
+failure gives additional information about the failure that may be
+displayed by the harness.
+
+```
+TAP version 13
+ok 1 - retrieving servers from the database
+# need to ping 6 servers
+ok 2 - pinged diamond
+ok 3 - pinged ruby
+not ok 4 - pinged saphire
+  ---
+  message: 'hostname "saphire" unknown'
+  severity: fail
+  ...
+ok 5 - pinged onyx
+not ok 6 - pinged quartz
+  ---
+  message: 'timeout'
+  severity: fail
+  ...
+ok 7 - pinged gold
+1..7
+```
+
+### Giving up
+
+This listing reports that a pile of tests are going to be run. However, the
+first test fails, reportedly because a connection to the database could not
+be established. The program decided that continuing was pointless and
+exited.
+
+```
+TAP version 13
+1..573
+not ok 1 - database handle
+Bail out! Couldn't connect to database.
+```
+
+### Skipping a few
+
+The following listing plans on running 5 tests. However, our program
+decided to not run tests 2 thru 5 at all. To properly report this, the
+tests are marked as being skipped.
+
+```
+TAP version 13
+1..5
+ok 1 - approved operating system
+# $^0 is solaris
+ok 2 - # SKIP no /sys directory
+ok 3 - # SKIP no /sys directory
+ok 4 - # SKIP no /sys directory
+ok 5 - # SKIP no /sys directory
+```
+
+### Skipping everything
+
+This listing shows that the entire listing is a skip. No tests were run.
+
+```
+TAP version 13
+1..0 # skip because English-to-French translator isn't installed
+```
+
+## Got spare tuits?
+
+The following example reports that four tests are run and the last two
+tests failed. However, because the failing tests are marked as things to do
+later, they are considered successes. Thus, a harness should report this
+entire listing as a success.
+
+```
+TAP version 13
+1..4
+ok 1 - Creating test program
+ok 2 - Test program runs, no error
+not ok 3 - infinite loop # TODO halting problem unsolved
+not ok 4 - infinite loop 2 # TODO halting problem unsolved
+```
+
+## Creative liberties
+
+This listing shows an alternate output where the test numbers aren't
+provided. The test also reports the state of a ficticious board game as a
+YAML block. Finally, the test count is reported at the end.
+
+```
+TAP version 13
+ok - created Board
+ok
+ok
+ok
+ok
+ok
+ok
+ok
+  ---
+  message: "Board layout"
+  severity: comment
+  dump:
+     board:
+       - '      16G         05C        '
+       - '      G N C       C C G      '
+       - '        G           C  +     '
+       - '10C   01G         03C        '
+       - 'R N G G A G       C C C      '
+       - '  R     G           C  +     '
+       - '      01G   17C   00C        '
+       - '      G A G G N R R N R      '
+       - '        G     R     G        '
+  ...
+ok - board has 7 tiles + starter tile
+1..9
+```
+
+## BUGS
+
+Feature requests and bug reports should be [raised on
+GitHub.](https://github.com/TestAnything/testanything.github.io/issues/new)
+
+## AUTHORS
+
+The original TAP documentation (of which this is a hacked about version)
+was written by Andy Lester, based on the original Test::Harness
+documentation by Michael Schwern.  This version was written by Andy
+Armstrong.
+
+## ACKNOWLEDGEMENTS
+
+Thanks to Pete Krawczyk, Paul Johnson, Ian Langworth and Nik Clayton for
+help and contributions on this document.  The basis for the TAP format was
+created by Larry Wall in the original test script for Perl 1. Tim Bunce and
+Andreas Koenig developed it further with their modifications to
+Test::Harness.
+
+## COPYRIGHT
+
+Copyright 2003-2007 by Michael G Schwern <schwern@pobox.com>, Andy Lester
+<andy@petdance.com>, Andy Armstrong <andy@hexten.net>.  This program is
+free software; you can redistribute it and/or modify it under the same
+terms as Perl itself.  See
+[http://www.perl.com/perl/misc/artistic.html](http://www.perl.com/perl/misc/artistic.html).
+
+## TODO
+
+Define the exit code of the process.

From ca19c3134115beb0fbb3e6e398fa4dfd013692e0 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Mon, 28 Feb 2022 20:25:42 -0800
Subject: [PATCH 02/40] TAP14: update version number

Hopefully this much we can agree upon, at least ;)

Note that a parser is still technically allowed to interpret a `TAP
version 13` stream as TAP14 and be compliant with this spec, but this
behavior is not required.  (In other words, they can also throw that out
as an error, and also be compliant.)  Since the goal is to codify
existing behavior and add little to it, and all current "TAP13"
implementations allow `TAP version 13`, this follows logically.
---
 tap-version-14-specification.md | 43 ++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 19 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 031c415..9cba518 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -1,11 +1,11 @@
 ---
 layout: default
-title: TAP 13 specification
+title: TAP 14 specification
 ---
 
 # NAME
 
-TAP13 - The Test Anything Protocol v13
+TAP14 - The Test Anything Protocol v14
 
 ## SYNOPSIS
 
@@ -13,14 +13,14 @@ TAP, the Test Anything Protocol, is a simple text-based interface between
 testing modules a test harness. TAP started life as part of the test
 harness for Perl but now has implementations in C/C++, Python, PHP, Perl,
 JavaScript, and probably others by the time you read this.  This document
-describes version 13 of TAP. Go to TAP to read about previous versions.
+describes version 14 of TAP. Go to TAP to read about previous versions.
 
-## THE TAP13 FORMAT
+## THE TAP14 FORMAT
 
-TAP13's general format is:
+TAP14's general format is:
 
 ```
-TAP version 13
+TAP version 14
 1..N
 ok 1 Description # Directive
 # Diagnostic
@@ -45,7 +45,7 @@ more tests....
 For example, a test file's output might look like:
 
 ```
-TAP version 13
+TAP version 14
 1..4
 ok 1 - Input file opened
 not ok 2 - First line of the input valid
@@ -80,12 +80,17 @@ considered test output.
 
 ### The version
 
-To indicate that this is TAP13 the first line must be
+To indicate that this is TAP14 the first line must be
 
 ```
-TAP version 13
+TAP version 14
 ```
 
+Parsers _may_ interpret ostensibly
+[TAP13](https://testanything.org/tap-version-13-specification.html) streams
+as TAP14, as this specification is compatible with observed behavior of
+existing TAP13 consumers and producers.
+
 ### The plan
 
 The plan tells how many tests will be run, or how many tests have run. It's
@@ -225,7 +230,7 @@ If the directive starts with # TODO, the test is counted as a todo test,
 and the text after TODO is the explanation.
 
 ```
-not ok 13 # TODO bend space and time
+not ok 14 # TODO bend space and time
 ```
 
 Note that if the TODO has an explanation it must be separated from TODO by
@@ -278,8 +283,8 @@ Bail out! MySQL is not running.
 Additional information may be put into the testing output on separate
 lines. Diagnostic lines should begin with a #, which the harness must
 ignore, at least as far as analyzing the test results. The harness is free,
-however, to display the diagnostics.  TAP13's YAML blocks are intended to
-replace diagnostics for most purposes but TAP13 consumers should maintain
+however, to display the diagnostics.  TAP14's YAML blocks are intended to
+replace diagnostics for most purposes but TAP14 consumers should maintain
 backwards compatibility by supporting them.
 
 ### Anything else
@@ -304,7 +309,7 @@ provides handy feedback as to what the test is about to do. All six tests
 pass.
 
 ```
-TAP version 13
+TAP version 14
 1..6
 #
 # Create a new Board and Tile, then place
@@ -329,7 +334,7 @@ failure gives additional information about the failure that may be
 displayed by the harness.
 
 ```
-TAP version 13
+TAP version 14
 ok 1 - retrieving servers from the database
 # need to ping 6 servers
 ok 2 - pinged diamond
@@ -357,7 +362,7 @@ be established. The program decided that continuing was pointless and
 exited.
 
 ```
-TAP version 13
+TAP version 14
 1..573
 not ok 1 - database handle
 Bail out! Couldn't connect to database.
@@ -370,7 +375,7 @@ decided to not run tests 2 thru 5 at all. To properly report this, the
 tests are marked as being skipped.
 
 ```
-TAP version 13
+TAP version 14
 1..5
 ok 1 - approved operating system
 # $^0 is solaris
@@ -385,7 +390,7 @@ ok 5 - # SKIP no /sys directory
 This listing shows that the entire listing is a skip. No tests were run.
 
 ```
-TAP version 13
+TAP version 14
 1..0 # skip because English-to-French translator isn't installed
 ```
 
@@ -397,7 +402,7 @@ later, they are considered successes. Thus, a harness should report this
 entire listing as a success.
 
 ```
-TAP version 13
+TAP version 14
 1..4
 ok 1 - Creating test program
 ok 2 - Test program runs, no error
@@ -412,7 +417,7 @@ provided. The test also reports the state of a ficticious board game as a
 YAML block. Finally, the test count is reported at the end.
 
 ```
-TAP version 13
+TAP version 14
 ok - created Board
 ok
 ok

From b01d92d71f19f99ad2957c2dcd73a142e66d52af Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Mon, 28 Feb 2022 20:43:25 -0800
Subject: [PATCH 03/40] TAP14: put language markers on code fence blocks

---
 tap-version-14-specification.md | 40 ++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 9cba518..7637438 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -19,7 +19,7 @@ describes version 14 of TAP. Go to TAP to read about previous versions.
 
 TAP14's general format is:
 
-```
+```tap
 TAP version 14
 1..N
 ok 1 Description # Directive
@@ -44,7 +44,7 @@ more tests....
 
 For example, a test file's output might look like:
 
-```
+```tap
 TAP version 14
 1..4
 ok 1 - Input file opened
@@ -82,7 +82,7 @@ considered test output.
 
 To indicate that this is TAP14 the first line must be
 
-```
+```tap
 TAP version 14
 ```
 
@@ -99,7 +99,7 @@ whether at the beginning or end of the output.  The plan is usually the
 second line of TAP output right after the version line, and it specifies
 how many test points are to follow. For example,
 
-```
+```tap
 1..10
 ```
 
@@ -130,7 +130,7 @@ TAP expects the ok or not ok to be followed by a test point number. If
 there is no number the harness must maintain its own counter until the
 script supplies test numbers again. So the following test output
 
-```
+```tap
 1..6
 not ok
 ok
@@ -149,7 +149,7 @@ Failed 3/6 tests, 50.00% okay
 -    Description Any text after the test number but before a # is the
      description of the test point.
 
-```
+```tap
 ok 42 this is the description of the test
 ```
 
@@ -178,7 +178,7 @@ indented to make it visually distinct from the surrounding test results and
 to make it easier for the parser to recover if the trailing '...'
 terminator is missing.  For example:
 
-```
+```tap
 not ok 3 Resolve address
  ---
  message: "Failed with error 'hostname peebles.example.com not found'"
@@ -196,7 +196,7 @@ not ok 3 Resolve address
 For a harness written in Perl the corresponding data structure would look
 like this:
 
-```
+```perl
 $diagnostic = {
     'message'  => "Failed with error 'hostname peebles.example.com not found'",
     'severity' => 'fail',
@@ -229,7 +229,7 @@ case-sensitive.
 If the directive starts with # TODO, the test is counted as a todo test,
 and the text after TODO is the explanation.
 
-```
+```tap
 not ok 14 # TODO bend space and time
 ```
 
@@ -248,14 +248,14 @@ skipped. If the whole test file succeeds, the count of skipped tests is
 included in the generated output. The harness should report the text after
 # SKIP\S*\s+ as a reason for skipping.
 
-```
+```tap
 ok 23 # skip Insufficient flogiston pressure.
 ```
 
 Similarly, one can include an explanation in a plan line, emitted if the
 test file is skipped completely:
 
-```
+```tap
 1..0 # Skipped: WWW::Mechanize not installed
 ```
 
@@ -267,14 +267,14 @@ As an emergency measure a test script can decide that further tests are
 useless (e.g. missing dependencies) and testing should stop immediately. In
 that case the test script prints the magic words
 
-```
+```tap
 Bail out!
 ```
 
 to standard output. Any message after these words must be displayed by the
 interpreter as the reason why testing must be stopped, as in
 
-```
+```tap
 Bail out! MySQL is not running.
 ```
 
@@ -308,7 +308,7 @@ The following TAP listing declares that six tests follow as well as
 provides handy feedback as to what the test is about to do. All six tests
 pass.
 
-```
+```tap
 TAP version 14
 1..6
 #
@@ -333,7 +333,7 @@ have run. Also, two of the tests fail. The YAML block following each
 failure gives additional information about the failure that may be
 displayed by the harness.
 
-```
+```tap
 TAP version 14
 ok 1 - retrieving servers from the database
 # need to ping 6 servers
@@ -361,7 +361,7 @@ first test fails, reportedly because a connection to the database could not
 be established. The program decided that continuing was pointless and
 exited.
 
-```
+```tap
 TAP version 14
 1..573
 not ok 1 - database handle
@@ -374,7 +374,7 @@ The following listing plans on running 5 tests. However, our program
 decided to not run tests 2 thru 5 at all. To properly report this, the
 tests are marked as being skipped.
 
-```
+```tap
 TAP version 14
 1..5
 ok 1 - approved operating system
@@ -389,7 +389,7 @@ ok 5 - # SKIP no /sys directory
 
 This listing shows that the entire listing is a skip. No tests were run.
 
-```
+```tap
 TAP version 14
 1..0 # skip because English-to-French translator isn't installed
 ```
@@ -401,7 +401,7 @@ tests failed. However, because the failing tests are marked as things to do
 later, they are considered successes. Thus, a harness should report this
 entire listing as a success.
 
-```
+```tap
 TAP version 14
 1..4
 ok 1 - Creating test program
@@ -416,7 +416,7 @@ This listing shows an alternate output where the test numbers aren't
 provided. The test also reports the state of a ficticious board game as a
 YAML block. Finally, the test count is reported at the end.
 
-```
+```tap
 TAP version 14
 ok - created Board
 ok

From e9c1961df11a853a2117f9c3937a7c41c6c93da2 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Tue, 1 Mar 2022 07:49:01 -0800
Subject: [PATCH 04/40] TAP14: First cleanup pass

- Provide rough EBNF grammar for the tap document.
- Allow Harnesses to accept `TAP version 13` and still be TAP14
  compliant.
- Group all Test Point definitions together.
- Include RFC2119 language note.
- Clarify Harness behavior without being implicitly tied to perl command
  line test runners.
- Clarification of TODO and SKIP directives, specify that they MUST NOT
  be treated as a test failure, even if the Test Point is `not ok`.
- Specify that YAML blocks must be indented by 2 spaces.
- Provide guidance around test exit status, handling of invalid TAP
  lines, and other Harness behavior.
---
 tap-version-14-specification.md | 509 +++++++++++++++++++++-----------
 1 file changed, 334 insertions(+), 175 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 7637438..c5d95e6 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -15,32 +15,36 @@ harness for Perl but now has implementations in C/C++, Python, PHP, Perl,
 JavaScript, and probably others by the time you read this.  This document
 describes version 14 of TAP. Go to TAP to read about previous versions.
 
-## THE TAP14 FORMAT
+The key words _must_, _must not_, _required_, _shall_, _shall not_,
+_should_, _should not_, _recommended_, _may_, and _optional_ in this
+document are to be interpreted as described in [RFC
+2119](https://datatracker.ietf.org/doc/html/rfc2119).
+
+## TAP14 FORMAT
+
+TAP14's general grammar is:
+
+```ebnf
+TAPDocument := Version Plan Body | Version Body Plan
+Version     := "TAP version 14\n"
+Plan        := "1.." (Number) (" # " Reason)? "\n"
+Body        := (TestPoint | BailOut | Pragma | Comment | Anything | Empty)*
+TestPoint   := ("not ")? "ok" (" " Number)? ((" -")? (" " Description) )? "\n" (YamlBlock)?
+YamlBlock   := "  ---\n" (YamlLine)* "  ...\n"
+YamlLine    := "  " (Yaml)* "\n"
+BailOut     := "Bail out!" (" " Reason)?
+Pragma      := "pragma " [+-] PragmaKey "\n"
+PragmaKey   := ([a-zA-Z0-9_-])+
+Comment     := (" ")* "#" [^\n]* "\n"
+Empty       := [\s\t]* "\n"
+Anything    := [^\n]+ "\n"
+```
 
-TAP14's general format is:
+The Version is the line `TAP version 14`.
 
-```tap
-TAP version 14
-1..N
-ok 1 Description # Directive
-# Diagnostic
-  ---
-  message: 'Failure message'
-  severity: fail
-  data:
-    got:
-      - 1
-      - 3
-      - 2
-    expect:
-      - 1
-      - 2
-      - 3
-  ...
-ok 47 Description
-ok 48 Description
-more tests....
-```
+The Body is a collection of lines representing a test set.
+
+The Plan reports on the number of tests included in the Body.
 
 For example, a test file's output might look like:
 
@@ -67,199 +71,364 @@ not ok 4 - Summarized correctly # TODO Not written yet
 ## HARNESS BEHAVIOR
 
 In this document, the "harness" is any program analyzing TAP output.
-Typically this will be Perl's runtests program, or the underlying
-TAP::Harness-runtests> method.  A harness must only read TAP output from
-standard output and not from standard error. Lines written to standard
-output matching `/^(not )?ok\b/` must be interpreted as test lines. After a
-test line a block of lines starting with '---' and ending with '...' will
-be interpreted as an inline YAML document providing extended diagnostic
-information about the preceding test. All other lines must not be
-considered test output.
 
-## TESTS LINES AND THE PLAN
+Typically this will be a test framework's runner program, but may also be a
+programmatic parser, parent test object, or test result reporter.
+
+In a typical TAP implementation, tests are programs that ouput TAP data
+according to this specification.  The "test harness" reads TAP output from
+these programs, and handles it in some way.
+
+A harness that is collecting output from test programs _should_ read and
+interpret TAP from the process's standard output, not standard error.
+(Handling of test standard error is implementation-specific.)
+
+A Harness _should_ normalize line endings by replacing any instances of
+`\r\n` or `\r` in the TAP document with `\n`.
 
-### The version
+A harness _should_ treat a test program as a failed test if:
 
-To indicate that this is TAP14 the first line must be
+* The TAP output lines indicate test failure, or
+* The TAP output of the process is invalid in a way that is not
+  recoverable, or
+* The exit code of the test program is not 0 (including test programs
+  killed by a fatal Unix signal).
+
+If one or more test programs are considered failures, then a TAP Harness
+_should_ indicate failure to the user in whatever means are appropriate.
+For example, a command-line test runner might exit with a non-zero status
+code, while a web-based continuous integration system might put a red
+"FAILED" notice in the html output.
+
+Note that some of the above guidance may not apply if the Harness is
+interpreting TAP from a different sort of text stream, or for a purpose
+other than actually running tests.  For example, a Harness may be used to
+analyze the recorded output of past test runs and provide data about them.
+
+## TAP DOCUMENT STRUCTURE
+
+### Version
+
+To indicate that this is TAP14 the first line _must_ be
 
 ```tap
 TAP version 14
 ```
 
-Parsers _may_ interpret ostensibly
+Harnesses _may_ interpret ostensibly
 [TAP13](https://testanything.org/tap-version-13-specification.html) streams
 as TAP14, as this specification is compatible with observed behavior of
-existing TAP13 consumers and producers.
-
-### The plan
-
-The plan tells how many tests will be run, or how many tests have run. It's
-a check that the test file hasn't stopped prematurely. It must appear once,
-whether at the beginning or end of the output.  The plan is usually the
-second line of TAP output right after the version line, and it specifies
-how many test points are to follow. For example,
+existing TAP13 consumers and producers.  That is, they _may_ treat this as
+a valid Version line while parsing TAP14:
 
 ```tap
-1..10
+TAP version 13
 ```
 
-means you plan on running 10 tests. This is a safeguard in case your test
-file dies silently in the middle of its run. The plan is optional but if
-there is a plan before the test points it must be the first non-diagnostic
-line output by the test file.  In certain instances a test file may not
-know how many test points it will ultimately be running. In this case the
-plan can be the last non-diagnostic line in the output.  The plan cannot
-appear in the middle of the output, nor can it appear more than once.
-
-### The test line
+Harnesses _may_ treat any TAP stream lacking a version as a failed test.
 
-The core of TAP is the test line. A test file prints one test line test
-point executed. There must be at least one test line in TAP output. Each
-test line comprises the following elements:
+### Plan
 
--    ok or not ok
+The Plan tells how many tests will be run, or how many tests have run. It's
+a check that the test file hasn't stopped prematurely.
 
-This tells whether the test point passed or failed. It must be at the
-beginning of the line. `/^not ok/` indicates a failed test point. `/^ok/`
-is a successful test point. This is the only mandatory part of the line.
-Note that unlike the Directives below, ok and not ok are case-sensitive.
+The Plan _must_ appear exactly once in the file, either before any Test
+Point lines, or after all Test Point lines.  That is, if it appears after
+any Test Point lines, there _must not_ be any Test Point lines following.
 
--    Test number
+A Harness _must_ treat a TAP stream lacking a plan as a failed test.
 
-TAP expects the ok or not ok to be followed by a test point number. If
-there is no number the harness must maintain its own counter until the
-script supplies test numbers again. So the following test output
+The Plan specifies how many test points are to follow. For example,
 
 ```tap
-1..6
-not ok
-ok
-not ok
-ok
-ok
+1..10
 ```
 
-has five tests. The sixth is missing. Test::Harness will generate
+means that either 10 test points will follow, or 10 test points are
+believed to have been present in the stream already.
 
-```
-FAILED tests 1, 3, 6
-Failed 3/6 tests, 50.00% okay
+This is a safeguard in case the test file dies silently in the middle of
+its run.
+
+The Plan lists the range of test point IDs that are expected in the TAP
+stream.  It can also optionally contain a comment prefixed by a `#`.
+
+It's basic grammar is:
+
+```ebnf
+Plan := Number ".." Number ("" | "# " Comment)
 ```
 
--    Description Any text after the test number but before a # is the
-     description of the test point.
+A plan line of `1..0` indicates that the test set was completely skipped;
+no tests are expected to follow, and none should have come before.
+Harnesses _should_ report on `1..0` test runs similarly to their handling
+of `SKIP` Test Points, treating any comment in the Plan as the reason for
+skipping.
 
 ```tap
-ok 42 this is the description of the test
+1..0 # WWW::Mechanize not installed
 ```
 
-Descriptions should not begin with a digit so that they are not confused
-with the test point number.  The harness may do whatever it wants with the
-description.
+**Note**: Plan lines starting with a number other than `1` are deprecated,
+and _may_ be treated as invalid in a future version of this specification.
+At the present time (March 2022), most popular TAP generating utilities
+always start Plan lines at 1.
+
+### Test Points
+
+The core of TAP is the "Test Point". A test file prints one test point
+executed. There must be at least one test point in TAP output. Each test
+point comprises the following elements:
+
+- Test Status: `ok` or `not ok`
+
+    This tells whether the test point passed or failed. It must be at the
+    beginning of the line. `/^not ok/` indicates a failed test point.
+    `/^ok/` is a successful test point. This is the only mandatory part of
+    the line.
+
+    Note that unlike the Directives below, `ok` and `not ok` are
+    case-sensitive.
+
+- Test Point ID
+
+    TAP expects the ok or not ok to be followed by an integer Test Point
+    ID. If there is no number, the harness _must_ maintain its own counter
+    until the script supplies test numbers again.
+
+    For example, the following test output is acceptable:
+
+    ```tap
+    1..5
+    not ok
+    ok
+    not ok
+    ok
+    ok
+    ```
+
+    and is equivalent to:
+
+    ```tap
+    1..5
+    not ok 1
+    ok 2
+    not ok 3
+    ok 4
+    ok 5
+    ```
+
+    This test output is _not_ valid TAP:
+
+    ```tap
+    1..6
+    not ok
+    ok
+    not ok
+    ok
+    ok
+    ```
+
+    has five tests. The sixth is missing. Test::Harness will generate
+
+    ```
+    FAILED tests 1, 3, 6
+    Failed 3/6 tests, 50.00% okay
+    ```
 
--    Directive The test point may include a directive, following a hash on
-     the test line. There are currently two directives allowed: TODO and
-     SKIP. These are discussed below.
+    Test Points _may_ be output in any order, but any Test Point ID
+    provided _must_ be within the range described by the Plan.
+
+    This is valid TAP:
+
+    ```tap
+    TAP version 14
+    1..3
+    ok 2
+    ok 3
+    ok 1
+    ```
+
+    This is not valid TAP:
+
+    ```tap
+    TAP version 14
+    1..3
+    ok 2
+    ok 4
+    ok 1
+    ```
+
+- Description
+
+    Any text after the test number but before a `#` is the description of
+    the test point.
+
+    ```tap
+    ok 42 - this is the description of the test
+    ```
+
+    Descriptions _should_ be separated from the Test Point Status and Test
+    Point ID by the string `" - "`, in order to prevent confusing a numeric
+    description with a Test Point ID.  However, the `" - "` separator is
+    _optional_.
+
+    Harnesses _should not_ consider a leading `" - "` to be a part of the
+    description reported to a user.
+
+- Directive
+
+    The test point may include a directive, following a hash on the test
+    line.  There are currently two directives allowed: `TODO` and `SKIP`.
+    These are discussed below.
 
 To summarize:
 
--    ok/not ok (required)
--    Test number (recommended)
--    Description (recommended)
--    Directive (only when necessary)
+- Test Status: `ok`/`not ok` (required)
+- Test number (recommended)
+- Description (recommended, prefixed by `" - "`)
+- Directive (only when necessary)
 
-### YAML blocks
 
-If the test line is immediately followed by an indented block beginning
-with `/^\s+---/` and ending with `/^\s+.../` that block will be interpreted
-as an inline YAML document. The YAML encodes a data structure that provides
-more detailed information about the preceding test.  The YAML document is
-indented to make it visually distinct from the surrounding test results and
-to make it easier for the parser to recover if the trailing '...'
-terminator is missing.  For example:
+#### DIRECTIVES
+
+Directives are special notes that follow a # on the Test Point line. Only
+two are currently defined: `TODO` and `SKIP`. These two keywords are not
+case-sensitive.
+
+##### TODO tests
+
+If the directive starts with `# TODO`, the test is counted as a todo test,
+and the text after `TODO` is the explanation.
 
 ```tap
-not ok 3 Resolve address
- ---
- message: "Failed with error 'hostname peebles.example.com not found'"
- severity: fail
- data:
-   got:
-     hostname: 'peebles.example.com'
-     address: ~
-   expected:
-     hostname: 'peebles.example.com'
-     address: '85.193.201.85'
- ...
+not ok 14 # TODO bend space and time
 ```
 
-For a harness written in Perl the corresponding data structure would look
-like this:
-
-```perl
-$diagnostic = {
-    'message'  => "Failed with error 'hostname peebles.example.com not found'",
-    'severity' => 'fail',
-    'data' => {
-        'got' => {
-            'hostname' => 'peebles.example.com',
-            'address'  => undef,
-        },
-        'expected' => {
-            'hostname' => 'peebles.example.com',
-            'address'  => '85.193.201.85',
-        }
-    },
-};
-```
+If the TODO has an explanation, it must be separated from TODO by a space.
+These tests represent a feature to be implemented or a bug to be fixed and
+act as something of an executable "things to do" list. They are not
+expected to succeed.
 
-Currently (2007/03/17) the format of the data structure represented by a
-YAML block has not been standardized. It is likely that whatever schema
-emerges will be able to capture the kind of forensic information about a
-test's execution seen in the example above.
+Should a todo test point begin succeeding, the harness _may_ report it in
+some way that indicates that whatever was supposed to be done has been, and
+it should be promoted to a normal Test Point.
 
-## DIRECTIVES
+Harnesses _must not_ treat failing `TODO` test points as a test failure.
 
-Directives are special notes that follow a # on the test line. Only two are
-currently defined: TODO and SKIP. Note that these two keywords are not
-case-sensitive.
+Harneses _should_ report `TODO` test points found as a list of items
+needing work, if that is appropriate for their use case.
 
-### TODO tests
+##### SKIP tests
 
-If the directive starts with # TODO, the test is counted as a todo test,
-and the text after TODO is the explanation.
+If the directive starts with `# SKIP`, the test is counted as a todo test,
+and the text after `SKIP` is the explanation.
 
 ```tap
-not ok 14 # TODO bend space and time
+ok 14 - mung the gums # SKIP leave gums unmunged for now
 ```
 
-Note that if the TODO has an explanation it must be separated from TODO by
-a space.  These tests represent a feature to be implemented or a bug to be
-fixed and act as something of an executable "things to do" list. They are
-not expected to succeed. Should a todo test point begin succeeding, the
-harness should report it as a bonus. This indicates that whatever you were
-supposed to do has been done and you should promote this to a normal test
-point.
+If the SKIP has an explanation, it must be separated from SKIP by a space.
+These tests indicate that a test was not run, or if it was, that its
+success or failure is being temporarily ignored.
+
+Harnesses _must not_ treat failing `SKIP` test points as a test failure.
+
+Harnesses _should_ report `SKIP` test points found as a list of items that
+were not tested, if that is appropriate for their use case.
+
+### YAML Diagnostics
+
+If a Test Point is followed by a 2-space indented block beginning with
+the line `  ---` and ending with the line `  ...`, separated from the Test
+Point only by comments or whitespace, then the block of lines between these
+markers will be interpreted as an inline YAML Diagnostic document.
 
-### Skipping tests
+The YAML encodes a data structure that provides information about the
+preceding Test Point.
 
-If the directive starts with # SKIP, the test is counted as having been
-skipped. If the whole test file succeeds, the count of skipped tests is
-included in the generated output. The harness should report the text after
-# SKIP\S*\s+ as a reason for skipping.
+For example:
 
 ```tap
-ok 23 # skip Insufficient flogiston pressure.
+not ok 3 - Resolve address
+  ---
+  message: "Failed with error 'hostname peebles.example.com not found'"
+  severity: fail
+  found:
+    hostname: 'peebles.example.com'
+    address: ~
+  wanted:
+    hostname: 'peebles.example.com'
+    address: '85.193.201.85'
+  at:
+    file: test/dns-resolve.c
+    line: 142
+  ...
 ```
 
-Similarly, one can include an explanation in a plan line, emitted if the
-test file is skipped completely:
+Currently (March 2022) the data structure represented by a YAML Diagnostic
+block has not been standardized.  TAP14 Harnesses _must_ allow any data
+structures supported by their YAML parser implementation.
+
+A future version of this specification _may_ provide guidance regarding
+YAML Diagnostic fields in common usage.
+
+### Comments
+
+Lines outside of a YAML diagnostic block which begin with a `#` character
+preceeded by zero or more characters of whitespace, are comments.
+
+A Harness _may_ present these to the user, ignore them, or assign meaning
+to certain comments.
+
+A Harness _must not_ treat a test as a failure based on the presence of
+comment lines.  That is, a Harness _must_ ignore any unrecognized comment
+lines.
+
+### Pragmas
+
+A Pragma provides information to a Harness to control its behavior or
+configure it in some way.  Each Pragma line represents a single boolean
+switch which can be set to `true` or `false`.
+
+The structure of a Pragma line is:
+
+- `"pragma "`
+- `+` (true) or `-` (false)
+- key: The name of the field being enabled or disabled.
+
+For example:
 
 ```tap
-1..0 # Skipped: WWW::Mechanize not installed
+TAP version 13
+# tell the parser to bail out on any failures from now on
+pragma +bail
+
+# tell the parser to execute in strict mode, treating any invalid TAP
+# as a test failure.
+pragma +strict
+
+# turn off a feature we don't want to be active right now
+pragma -bail
 ```
 
-## OTHER LINES
+The meaning and availability of keys that may be set by Pragmas are
+implementation-specific.
+
+Harnesses _must not_ treat unrecognized Pragma keys as a test failure.
+However, they _may_ warn if a Pragma is unrecognized, or fail if the
+named flag cannot be set for some reason.
+
+### Blank Lines
+
+For the purposes of this specification, a "blank" line is any line
+consisting exclusively of zero or more whitespace characters.
+
+Blank lines within YAML blocks _must_ be preserved as part of the YAML
+document, because line breaks have semantic meaning in YAML documents.  For
+example, multiline folded scalar values use `\n\n` to denote line breaks.
+
+Blank lines outside of YAML blocks _must_ be ignored by the Harness.
 
 ### Bail out!
 
@@ -278,22 +447,16 @@ interpreter as the reason why testing must be stopped, as in
 Bail out! MySQL is not running.
 ```
 
-### Diagnostics
+The words "Bail out!" are case insensitive.
 
-Additional information may be put into the testing output on separate
-lines. Diagnostic lines should begin with a #, which the harness must
-ignore, at least as far as analyzing the test results. The harness is free,
-however, to display the diagnostics.  TAP14's YAML blocks are intended to
-replace diagnostics for most purposes but TAP14 consumers should maintain
-backwards compatibility by supporting them.
+### Anything Else
 
-### Anything else
+Any line that is not a valid version, plan, test point, yaml diagnostic,
+pragma, a blank line, or a bail out is invalid TAP.
 
-Any output that is not a version, a plan, a test line, a YAML block, a
-diagnostic or a bail out is incorrect. How a harness handles the incorrect
-line is undefined.  Test::Harness silently ignores incorrect lines, but
-will become more stringent in the future.  TAP::Harness reports TAP syntax
-errors at the end of a test run.
+A Harness _may_ silently ignore invalid TAP lines, pass them through to its
+own stderr or stdout, or report them in some other fashion.  However, it
+_should not_ treat invalid TAP lines as a test failure by default.
 
 ## EXAMPLES
 
@@ -472,7 +635,3 @@ Copyright 2003-2007 by Michael G Schwern <schwern@pobox.com>, Andy Lester
 free software; you can redistribute it and/or modify it under the same
 terms as Perl itself.  See
 [http://www.perl.com/perl/misc/artistic.html](http://www.perl.com/perl/misc/artistic.html).
-
-## TODO
-
-Define the exit code of the process.

From ff79a2f5989657378f767b9994111a71af3f5265 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Tue, 1 Mar 2022 07:59:07 -0800
Subject: [PATCH 05/40] TAP14: Add (temporary) status/goals section up top

---
 tap-version-14-specification.md | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index c5d95e6..e750284 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -3,6 +3,22 @@ layout: default
 title: TAP 14 specification
 ---
 
+# STATUS: DRAFT
+
+This is a draft document pending further editing and ratification by no
+fewer than 3 widely used TAP implementations in 3 different language
+communities.
+
+This section will likely be removed prior to ratification.
+
+## GOALS OF THIS SPECIFICATION
+
+* Document the observed behavior of widely used TAP implementations.
+* Add no features that are not already in wide usage across multiple
+  implementations.
+* Explicitly allow what is already allowed, deny what is already denied.
+* Provide updated and clearer guidance for new TAP implementations.
+
 # NAME
 
 TAP14 - The Test Anything Protocol v14
@@ -27,7 +43,7 @@ TAP14's general grammar is:
 ```ebnf
 TAPDocument := Version Plan Body | Version Body Plan
 Version     := "TAP version 14\n"
-Plan        := "1.." (Number) (" # " Reason)? "\n"
+Plan        := (Number) ".." (Number) (" # " Reason)? "\n"
 Body        := (TestPoint | BailOut | Pragma | Comment | Anything | Empty)*
 TestPoint   := ("not ")? "ok" (" " Number)? ((" -")? (" " Description) )? "\n" (YamlBlock)?
 YamlBlock   := "  ---\n" (YamlLine)* "  ...\n"

From 459a33007cf6ad513fce2c45a924d102ed8a43f8 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Tue, 1 Mar 2022 08:06:49 -0800
Subject: [PATCH 06/40] TAP14: unknown directives are a thing

---
 tap-version-14-specification.md | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index e750284..84d499c 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -312,6 +312,12 @@ Directives are special notes that follow a # on the Test Point line. Only
 two are currently defined: `TODO` and `SKIP`. These two keywords are not
 case-sensitive.
 
+Harnesses _may_ support additional platform-specific directives.  Future
+versions of this specification _may_ codify additional directives with
+defined semantics.
+
+Unrecognized directives _must_ be ignored, and treated as comments.
+
 ##### TODO tests
 
 If the directive starts with `# TODO`, the test is counted as a todo test,

From 89380697f76e78baddb9d33d73e8c937a9bcd9e3 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 12:57:50 -0800
Subject: [PATCH 07/40] TAP14: improve pseudo-EBNF

---
 tap-version-14-specification.md | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 84d499c..9cf5a1a 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -43,19 +43,24 @@ TAP14's general grammar is:
 ```ebnf
 TAPDocument := Version Plan Body | Version Body Plan
 Version     := "TAP version 14\n"
-Plan        := (Number) ".." (Number) (" # " Reason)? "\n"
+Plan        := "1.." (Number) (" # " Reason)? "\n"
 Body        := (TestPoint | BailOut | Pragma | Comment | Anything | Empty)*
-TestPoint   := ("not ")? "ok" (" " Number)? ((" -")? (" " Description) )? "\n" (YamlBlock)?
+TestPoint   := ("not ")? "ok" (" " Number)? ((" -")? (" " Description) )? (" " Directive)? "\n" (YamlBlock)?
+Directive   := "# " ("todo" | "skip") (" " Reason)?
 YamlBlock   := "  ---\n" (YamlLine)* "  ...\n"
 YamlLine    := "  " (Yaml)* "\n"
-BailOut     := "Bail out!" (" " Reason)?
+BailOut     := "Bail out!" (" " Reason)? "\n"
+Reason      := [^\n]+
 Pragma      := "pragma " [+-] PragmaKey "\n"
 PragmaKey   := ([a-zA-Z0-9_-])+
-Comment     := (" ")* "#" [^\n]* "\n"
+Comment     := ^ (" ")* "#" [^\n]* "\n"
 Empty       := [\s\t]* "\n"
 Anything    := [^\n]+ "\n"
 ```
 
+(Note that the above is intended as a rough "pseudocode" guidance for
+humans.  It is not strict EBNF.)
+
 The Version is the line `TAP version 14`.
 
 The Body is a collection of lines representing a test set.

From 2fd8aaf895e58210aa173faf0826ba40bbc6cb4d Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 13:05:45 -0800
Subject: [PATCH 08/40] TAP14: plans must start with 1..

---
 tap-version-14-specification.md | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 9cf5a1a..4d41769 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -168,16 +168,16 @@ The Plan specifies how many test points are to follow. For example,
 means that either 10 test points will follow, or 10 test points are
 believed to have been present in the stream already.
 
-This is a safeguard in case the test file dies silently in the middle of
-its run.
+This is a safeguard against test data being truncated or damaged in some
+other way, rendering the output unreliable.
 
 The Plan lists the range of test point IDs that are expected in the TAP
-stream.  It can also optionally contain a comment prefixed by a `#`.
+stream.  It can also optionally contain a comment/reason prefixed by a `#`.
 
 It's basic grammar is:
 
 ```ebnf
-Plan := Number ".." Number ("" | "# " Comment)
+Plan := "1.." Number ("" | "# " Reason)
 ```
 
 A plan line of `1..0` indicates that the test set was completely skipped;
@@ -190,10 +190,14 @@ skipping.
 1..0 # WWW::Mechanize not installed
 ```
 
-**Note**: Plan lines starting with a number other than `1` are deprecated,
-and _may_ be treated as invalid in a future version of this specification.
-At the present time (March 2022), most popular TAP generating utilities
-always start Plan lines at 1.
+Previous versions of TAP allowed plans to specify any two numbers, for
+example, `5..8` to indicate that test points with IDs between 5 and 8 would
+be run.  However, this is not widely supported.
+
+Thus, TAP14 producers _must_ output a Plan starting with `1`.  TAP14
+Harnesses _may_ allow plans starting with numbers other than 1, but if so,
+they _must_ treat any Test Point IDs outside the plan range as a test
+failure.
 
 ### Test Points
 

From 943e7d733cbe9e4b0bf337d3cfdb35058f32242e Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 13:21:46 -0800
Subject: [PATCH 09/40] TAP14: loosen/clarify expectations re Pragma lines

---
 tap-version-14-specification.md | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 4d41769..2197427 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -426,7 +426,8 @@ The structure of a Pragma line is:
 
 - `"pragma "`
 - `+` (true) or `-` (false)
-- key: The name of the field being enabled or disabled.
+- key: The name of the field being enabled or disabled.  ASCII alphanumeric
+  characters, `_`, and `-` are allowed.
 
 For example:
 
@@ -436,7 +437,7 @@ TAP version 13
 pragma +bail
 
 # tell the parser to execute in strict mode, treating any invalid TAP
-# as a test failure.
+# line as a test failure.
 pragma +strict
 
 # turn off a feature we don't want to be active right now
@@ -446,9 +447,12 @@ pragma -bail
 The meaning and availability of keys that may be set by Pragmas are
 implementation-specific.
 
-Harnesses _must not_ treat unrecognized Pragma keys as a test failure.
-However, they _may_ warn if a Pragma is unrecognized, or fail if the
-named flag cannot be set for some reason.
+Harnesses _may_ choose to respond to Pragma lines, or ignore them.
+
+Harnesses _must not_ treat unrecognized Pragma keys as a test failure, even
+if they would normally treat invalid TAP as a test failure.  Harnesses
+_may_ warn if a Pragma is unrecognized, or fail if the named pragma is
+recognized, but cannot be set for some reason.
 
 ### Blank Lines
 

From fc4b81311e9b55baefda6be55ec2539f992695c4 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 13:36:55 -0800
Subject: [PATCH 10/40] TAP14: Copyright, authorship, and licensing

---
 tap-version-14-specification.md | 39 +++++++++++++++++++++------------
 1 file changed, 25 insertions(+), 14 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 2197427..cbfbb30 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -646,27 +646,38 @@ ok - board has 7 tiles + starter tile
 ## BUGS
 
 Feature requests and bug reports should be [raised on
-GitHub.](https://github.com/TestAnything/testanything.github.io/issues/new)
+GitHub.](https://github.com/TestAnything/Specification/issues/new)
 
 ## AUTHORS
 
-The original TAP documentation (of which this is a hacked about version)
-was written by Andy Lester, based on the original Test::Harness
-documentation by Michael Schwern.  This version was written by Andy
-Armstrong.
+The TAP 14 Specification is authored by [Isaac Z.
+Schlueter](https://github.com/isaacs), as a result of much discussion on
+the [TestAnything
+Specification](https://github.com/TestAnything/Specification) project, with
+considerable input, encouragement, feedback, and suggestions from:
+
+* [Matt Layman](https://github.com/mblayman)
+* [Leon Timmermans](https://github.com/Leont)
+* [Bruno P. Kinoshita](https://github.com/kinow)
+* [Chad Granum](https://github.com/exodist)
 
 ## ACKNOWLEDGEMENTS
 
-Thanks to Pete Krawczyk, Paul Johnson, Ian Langworth and Nik Clayton for
-help and contributions on this document.  The basis for the TAP format was
-created by Larry Wall in the original test script for Perl 1. Tim Bunce and
-Andreas Koenig developed it further with their modifications to
-Test::Harness.
+The TAP 13 Specification was written by Andy Armstrong with help and
+contributions from Pete Krawczyk, Paul Johnson, Ian Langworth and Nik
+Clayton, based on the original TAP documentation by Andy Lester, based on
+the original Test::Harness documentation by Michael Schwern.
+
+The basis for the TAP format was created by Larry Wall in the original test
+script for Perl 1. Tim Bunce and Andreas Koenig developed it further with
+their modifications to Test::Harness.
 
 ## COPYRIGHT
 
+Copyright 2015-2022 by Isaac Z. Schlueter <i@izs.me> and Contributors.
+
 Copyright 2003-2007 by Michael G Schwern <schwern@pobox.com>, Andy Lester
-<andy@petdance.com>, Andy Armstrong <andy@hexten.net>.  This program is
-free software; you can redistribute it and/or modify it under the same
-terms as Perl itself.  See
-[http://www.perl.com/perl/misc/artistic.html](http://www.perl.com/perl/misc/artistic.html).
+<andy@petdance.com>, Andy Armstrong <andy@hexten.net>.
+
+This specification is released under the [Artistic License
+2.0](https://opensource.org/licenses/Artistic-2.0)

From 7b6b2093d57a9a6c15692229a5d191cca678d48c Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 13:39:21 -0800
Subject: [PATCH 11/40] TAP14: language cleanup on stderr harness behavior

---
 tap-version-14-specification.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index cbfbb30..ad9406b 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -100,7 +100,7 @@ In a typical TAP implementation, tests are programs that ouput TAP data
 according to this specification.  The "test harness" reads TAP output from
 these programs, and handles it in some way.
 
-A harness that is collecting output from test programs _should_ read and
+A harness that is collecting output from a test program _should_ read and
 interpret TAP from the process's standard output, not standard error.
 (Handling of test standard error is implementation-specific.)
 

From 7595f7a35b31f5e2ea18f652dbafdfbc2f863cd4 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 13:40:03 -0800
Subject: [PATCH 12/40] TAP14: it's -> its

---
 tap-version-14-specification.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index ad9406b..b475db1 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -174,7 +174,7 @@ other way, rendering the output unreliable.
 The Plan lists the range of test point IDs that are expected in the TAP
 stream.  It can also optionally contain a comment/reason prefixed by a `#`.
 
-It's basic grammar is:
+Its basic grammar is:
 
 ```ebnf
 Plan := "1.." Number ("" | "# " Reason)

From 708b8541f665f5f885b444bb66655f7c10dc277b Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 13:55:51 -0800
Subject: [PATCH 13/40] TAP14: specify what counts as 'blank' in a blank line

---
 tap-version-14-specification.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index b475db1..8c19fec 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -457,7 +457,8 @@ recognized, but cannot be set for some reason.
 ### Blank Lines
 
 For the purposes of this specification, a "blank" line is any line
-consisting exclusively of zero or more whitespace characters.
+consisting exclusively of zero or more whitespace characters (ie,
+`/^[ \t]+$/`).
 
 Blank lines within YAML blocks _must_ be preserved as part of the YAML
 document, because line breaks have semantic meaning in YAML documents.  For

From 6d619d29998c8a71604a494e31a202ef14ad20c3 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 13:57:22 -0800
Subject: [PATCH 14/40] TAP14: clarification of test point IDs, plan ranges,
 and failures

---
 tap-version-14-specification.md | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 8c19fec..57a0d0c 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -243,9 +243,10 @@ point comprises the following elements:
     ok 5
     ```
 
-    This test output is _not_ valid TAP:
+    This test output is _not_ a successful test run:
 
     ```tap
+    TAP version 13
     1..6
     not ok
     ok
@@ -254,7 +255,9 @@ point comprises the following elements:
     ok
     ```
 
-    has five tests. The sixth is missing. Test::Harness will generate
+    Five tests are shown, but the plan indicated that there would be 6.
+    Furthermore, tests 1 and 3 are explicitly failing.  Perl's
+    `Test::Harness` will report:
 
     ```
     FAILED tests 1, 3, 6
@@ -264,7 +267,7 @@ point comprises the following elements:
     Test Points _may_ be output in any order, but any Test Point ID
     provided _must_ be within the range described by the Plan.
 
-    This is valid TAP:
+    This is valid TAP and a successful test run:
 
     ```tap
     TAP version 14
@@ -274,7 +277,8 @@ point comprises the following elements:
     ok 1
     ```
 
-    This is not valid TAP:
+    This is not a successful test run. Even though there are 3 Test Points,
+    the Test Point ID 4 is outside the stated Plan range.
 
     ```tap
     TAP version 14

From f1803dd8f1acfa088cdbc1a109f73b91f30d2a98 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 14:00:50 -0800
Subject: [PATCH 15/40] TAP14: clarify optionality of ' - ' in Test Point
 Description

---
 tap-version-14-specification.md | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 57a0d0c..68043db 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -299,8 +299,16 @@ point comprises the following elements:
 
     Descriptions _should_ be separated from the Test Point Status and Test
     Point ID by the string `" - "`, in order to prevent confusing a numeric
-    description with a Test Point ID.  However, the `" - "` separator is
-    _optional_.
+    description with a Test Point ID.  Harnesses _must_ treat Test Points
+    identically whether the description starts with `" - "` or not.
+
+    For example, these two test points _must_ be treated identically by a
+    Harness:
+
+    ```tap
+    ok 1 this is fine
+    ok 1 - this is fine
+    ```
 
     Harnesses _should not_ consider a leading `" - "` to be a part of the
     description reported to a user.

From 2ffc0e4d55667b9514b137339b185bb5141d8cf6 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 14:01:58 -0800
Subject: [PATCH 16/40] TAP14: <code> the #

---
 tap-version-14-specification.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 68043db..a826b5c 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -329,7 +329,7 @@ To summarize:
 
 #### DIRECTIVES
 
-Directives are special notes that follow a # on the Test Point line. Only
+Directives are special notes that follow a `#` on the Test Point line. Only
 two are currently defined: `TODO` and `SKIP`. These two keywords are not
 case-sensitive.
 

From fff58d6aeecd0ad25ac433f6625c28610b0e9b7c Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 14:04:16 -0800
Subject: [PATCH 17/40] TAP14: clarify case-sensitivity of directives

---
 tap-version-14-specification.md | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index a826b5c..45f2b82 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -330,8 +330,10 @@ To summarize:
 #### DIRECTIVES
 
 Directives are special notes that follow a `#` on the Test Point line. Only
-two are currently defined: `TODO` and `SKIP`. These two keywords are not
-case-sensitive.
+two are currently defined: `TODO` and `SKIP`.
+
+Directives are not case sensitive.  That is, Harnesses _must_ treat `#
+SKIP`, `# skip`, and `# SkIp` identically.
 
 Harnesses _may_ support additional platform-specific directives.  Future
 versions of this specification _may_ codify additional directives with

From f843c1ad656a8582bb8df4e64936d3a10ebbbecc Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 14:05:06 -0800
Subject: [PATCH 18/40] TAP14: copypasta error s/todo/skip/

---
 tap-version-14-specification.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 45f2b82..525c760 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -366,8 +366,8 @@ needing work, if that is appropriate for their use case.
 
 ##### SKIP tests
 
-If the directive starts with `# SKIP`, the test is counted as a todo test,
-and the text after `SKIP` is the explanation.
+If the directive starts with `# SKIP`, the test is counted as a skipped
+test, and the text after `SKIP` is the explanation.
 
 ```tap
 ok 14 - mung the gums # SKIP leave gums unmunged for now

From ba460ac138568f2103cd09b1780acb98d15a82d7 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 14:51:01 -0800
Subject: [PATCH 19/40] TAP14: Consistent capitalization, refresh ancient joke

---
 tap-version-14-specification.md | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 525c760..0806a67 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -11,7 +11,7 @@ communities.
 
 This section will likely be removed prior to ratification.
 
-## GOALS OF THIS SPECIFICATION
+## Goals of This Specification
 
 * Document the observed behavior of widely used TAP implementations.
 * Add no features that are not already in wide usage across multiple
@@ -19,11 +19,11 @@ This section will likely be removed prior to ratification.
 * Explicitly allow what is already allowed, deny what is already denied.
 * Provide updated and clearer guidance for new TAP implementations.
 
-# NAME
+# Name
 
 TAP14 - The Test Anything Protocol v14
 
-## SYNOPSIS
+## Synopsis
 
 TAP, the Test Anything Protocol, is a simple text-based interface between
 testing modules a test harness. TAP started life as part of the test
@@ -36,7 +36,7 @@ _should_, _should not_, _recommended_, _may_, and _optional_ in this
 document are to be interpreted as described in [RFC
 2119](https://datatracker.ietf.org/doc/html/rfc2119).
 
-## TAP14 FORMAT
+## TAP14 Format
 
 TAP14's general grammar is:
 
@@ -45,10 +45,10 @@ TAPDocument := Version Plan Body | Version Body Plan
 Version     := "TAP version 14\n"
 Plan        := "1.." (Number) (" # " Reason)? "\n"
 Body        := (TestPoint | BailOut | Pragma | Comment | Anything | Empty)*
-TestPoint   := ("not ")? "ok" (" " Number)? ((" -")? (" " Description) )? (" " Directive)? "\n" (YamlBlock)?
+TestPoint   := ("not ")? "ok" (" " Number)? ((" -")? (" " Description) )? (" " Directive)? "\n" (YAMLBlock)?
 Directive   := "# " ("todo" | "skip") (" " Reason)?
-YamlBlock   := "  ---\n" (YamlLine)* "  ...\n"
-YamlLine    := "  " (Yaml)* "\n"
+YAMLBlock   := "  ---\n" (YAMLLine)* "  ...\n"
+YAMLLine    := "  " (YAML)* "\n"
 BailOut     := "Bail out!" (" " Reason)? "\n"
 Reason      := [^\n]+
 Pragma      := "pragma " [+-] PragmaKey "\n"
@@ -89,7 +89,7 @@ not ok 4 - Summarized correctly # TODO Not written yet
   ...
 ```
 
-## HARNESS BEHAVIOR
+## Harness Behavior
 
 In this document, the "harness" is any program analyzing TAP output.
 
@@ -126,7 +126,7 @@ interpreting TAP from a different sort of text stream, or for a purpose
 other than actually running tests.  For example, a Harness may be used to
 analyze the recorded output of past test runs and provide data about them.
 
-## TAP DOCUMENT STRUCTURE
+## Document Structure
 
 ### Version
 
@@ -341,7 +341,7 @@ defined semantics.
 
 Unrecognized directives _must_ be ignored, and treated as comments.
 
-##### TODO tests
+##### `TODO` tests
 
 If the directive starts with `# TODO`, the test is counted as a todo test,
 and the text after `TODO` is the explanation.
@@ -364,7 +364,7 @@ Harnesses _must not_ treat failing `TODO` test points as a test failure.
 Harneses _should_ report `TODO` test points found as a list of items
 needing work, if that is appropriate for their use case.
 
-##### SKIP tests
+##### `SKIP` tests
 
 If the directive starts with `# SKIP`, the test is counted as a skipped
 test, and the text after `SKIP` is the explanation.
@@ -501,7 +501,7 @@ The words "Bail out!" are case insensitive.
 
 ### Anything Else
 
-Any line that is not a valid version, plan, test point, yaml diagnostic,
+Any line that is not a valid version, plan, test point, YAML diagnostic,
 pragma, a blank line, or a bail out is invalid TAP.
 
 A Harness _may_ silently ignore invalid TAP lines, pass them through to its
@@ -607,7 +607,7 @@ TAP version 14
 1..0 # skip because English-to-French translator isn't installed
 ```
 
-## Got spare tuits?
+## Procrastination Considered `ok`
 
 The following example reports that four tests are run and the last two
 tests failed. However, because the failing tests are marked as things to do

From d5a477e72d449247fd46062bbead773949c976e2 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 14:52:49 -0800
Subject: [PATCH 20/40] TAP14: make pragmas kinda strict

---
 tap-version-14-specification.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 0806a67..6effbe0 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -468,6 +468,9 @@ if they would normally treat invalid TAP as a test failure.  Harnesses
 _may_ warn if a Pragma is unrecognized, or fail if the named pragma is
 recognized, but cannot be set for some reason.
 
+Pragmas _must not_ include comments, directives, or other characters other
+than those specified above.
+
 ### Blank Lines
 
 For the purposes of this specification, a "blank" line is any line

From 87e2dfa610a54fb15156ac84411cb8f71d44c59f Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 15:10:18 -0800
Subject: [PATCH 21/40] TAP14: missed a manpage-esque caps fix

---
 tap-version-14-specification.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 6effbe0..9b20d2d 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -511,7 +511,7 @@ A Harness _may_ silently ignore invalid TAP lines, pass them through to its
 own stderr or stdout, or report them in some other fashion.  However, it
 _should not_ treat invalid TAP lines as a test failure by default.
 
-## EXAMPLES
+## Examples
 
 All names, places, and events depicted in any example are wholly fictitious
 and bear no resemblance to, connection with, or relation to any real

From 6b160bef6f71b486521397930cc7bc93f3482bb6 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 15:25:01 -0800
Subject: [PATCH 22/40] TAP14: tap is utf8

Fix: https://github.com/TestAnything/Specification/issues/12
---
 tap-version-14-specification.md | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 9b20d2d..aece179 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -128,6 +128,12 @@ analyze the recorded output of past test runs and provide data about them.
 
 ## Document Structure
 
+TAP14 producers _must_ encode TAP data using the UTF-8 encoding.
+
+Harnesses _should_ interpret all TAP streams using UTF-8.  Harnesses _may_
+provide a mechanism for using other encodings explicitly, if needed for
+backwards compatibility.
+
 ### Version
 
 To indicate that this is TAP14 the first line _must_ be

From 089b42cae8da71004d8f1dad6661000d532e6749 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 20:51:14 -0800
Subject: [PATCH 23/40] TAP14: MORE CAPITALIZATION fixes

---
 tap-version-14-specification.md | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index aece179..2db2692 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -3,7 +3,7 @@ layout: default
 title: TAP 14 specification
 ---
 
-# STATUS: DRAFT
+# Status: DRAFT
 
 This is a draft document pending further editing and ratification by no
 fewer than 3 widely used TAP implementations in 3 different language
@@ -333,7 +333,7 @@ To summarize:
 - Directive (only when necessary)
 
 
-#### DIRECTIVES
+#### Directives
 
 Directives are special notes that follow a `#` on the Test Point line. Only
 two are currently defined: `TODO` and `SKIP`.
@@ -667,12 +667,12 @@ ok - board has 7 tiles + starter tile
 1..9
 ```
 
-## BUGS
+## Bugs
 
 Feature requests and bug reports should be [raised on
 GitHub.](https://github.com/TestAnything/Specification/issues/new)
 
-## AUTHORS
+## Authors
 
 The TAP 14 Specification is authored by [Isaac Z.
 Schlueter](https://github.com/isaacs), as a result of much discussion on
@@ -685,7 +685,7 @@ considerable input, encouragement, feedback, and suggestions from:
 * [Bruno P. Kinoshita](https://github.com/kinow)
 * [Chad Granum](https://github.com/exodist)
 
-## ACKNOWLEDGEMENTS
+## Acknowledgements
 
 The TAP 13 Specification was written by Andy Armstrong with help and
 contributions from Pete Krawczyk, Paul Johnson, Ian Langworth and Nik
@@ -696,7 +696,7 @@ The basis for the TAP format was created by Larry Wall in the original test
 script for Perl 1. Tim Bunce and Andreas Koenig developed it further with
 their modifications to Test::Harness.
 
-## COPYRIGHT
+## Copyright
 
 Copyright 2015-2022 by Isaac Z. Schlueter <i@izs.me> and Contributors.
 

From 8a581d5d419805082caf0db67f83f38da9149d5a Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 21:36:17 -0800
Subject: [PATCH 24/40] TAP14: specific instructions for escaping # and \

Re discussion in https://github.com/TestAnything/Specification/issues/26
---
 tap-version-14-specification.md | 125 ++++++++++++++++++++++++++++----
 1 file changed, 112 insertions(+), 13 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 2db2692..ddd479c 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -205,6 +205,9 @@ Harnesses _may_ allow plans starting with numbers other than 1, but if so,
 they _must_ treat any Test Point IDs outside the plan range as a test
 failure.
 
+`#` and `\` characters may be escaped in Plan reason, and if so, _should_
+be unescaped prior to being presented to the user.  See "Escaping" below.
+
 ### Test Points
 
 The core of TAP is the "Test Point". A test file prints one test point
@@ -321,8 +324,8 @@ point comprises the following elements:
 
 - Directive
 
-    The test point may include a directive, following a hash on the test
-    line.  There are currently two directives allowed: `TODO` and `SKIP`.
+    The test point may include a directive, following a `#` on the test
+    line.  There are currently two Directives allowed: `TODO` and `SKIP`.
     These are discussed below.
 
 To summarize:
@@ -332,20 +335,24 @@ To summarize:
 - Description (recommended, prefixed by `" - "`)
 - Directive (only when necessary)
 
-
 #### Directives
 
-Directives are special notes that follow a `#` on the Test Point line. Only
-two are currently defined: `TODO` and `SKIP`.
+Directives are special notes that follow the first unescaped `#` on the
+Test Point line.  Only two are currently defined: `TODO` and `SKIP`.
 
 Directives are not case sensitive.  That is, Harnesses _must_ treat `#
 SKIP`, `# skip`, and `# SkIp` identically.
 
-Harnesses _may_ support additional platform-specific directives.  Future
-versions of this specification _may_ codify additional directives with
+Harnesses _may_ support additional platform-specific Directives.  Future
+versions of this specification may codify additional Directives with
 defined semantics.
 
-Unrecognized directives _must_ be ignored, and treated as comments.
+Unrecognized Directives _must_ not be treated as test failure, or an
+invalid TAP line.  Harnesses _should_ include any unrecognized directives
+in the Test Point description.
+
+Note that escaped `#` characters are not to be treated as delimiters for
+Directives.  See "Escaping" below.
 
 ##### `TODO` tests
 
@@ -474,7 +481,7 @@ if they would normally treat invalid TAP as a test failure.  Harnesses
 _may_ warn if a Pragma is unrecognized, or fail if the named pragma is
 recognized, but cannot be set for some reason.
 
-Pragmas _must not_ include comments, directives, or other characters other
+Pragmas _must not_ include Comments, Directives, or other characters other
 than those specified above.
 
 ### Blank Lines
@@ -499,13 +506,22 @@ that case the test script prints the magic words
 Bail out!
 ```
 
-to standard output. Any message after these words must be displayed by the
-interpreter as the reason why testing must be stopped, as in
+to standard output. Any message after these words _must_ be presented by
+the Harness as the reason why testing must be stopped.  For example:
 
 ```tap
 Bail out! MySQL is not running.
 ```
 
+`#` and `\` characters may be escaped in `Bail out!` messages, and if so,
+_should_ be unescaped prior to being presented to the user.  See
+"Escaping" below.
+
+```tap
+# reason for stopping: # and \ are not supported
+Bail out! \# and \\ are not supported
+```
+
 The words "Bail out!" are case insensitive.
 
 ### Anything Else
@@ -514,8 +530,91 @@ Any line that is not a valid version, plan, test point, YAML diagnostic,
 pragma, a blank line, or a bail out is invalid TAP.
 
 A Harness _may_ silently ignore invalid TAP lines, pass them through to its
-own stderr or stdout, or report them in some other fashion.  However, it
-_should not_ treat invalid TAP lines as a test failure by default.
+own stderr or stdout, or report them in some other fashion.  However,
+Harnesses _should not_ treat invalid TAP lines as a test failure by
+default.
+
+## Escaping
+
+Sometimes a user may include a `#` character in a Test Point description,
+Plan comment, Bailout reason, or TODO/SKIP reason.
+
+In order to distinguish this from a directive or other sort of comment, the
+`#` character may be escaped with a backslash `\` character.  To include a
+literal `\` character, a double-`\` may be used.  No other characters may
+be escaped in this way; a `\` that precedes any character other than `\` or
+`#` will be interpreted as a literal `\` and included in the result data.
+
+Providers _should_ escape any `#` or `\` that is present in the Test Point
+description or directive reason sections.
+
+For example:
+
+```js
+// using node-tap
+const t = require('tap')
+t.pass('hello # \\ world', { todo: 'escape # characters with \\' })
+// outputs:
+// ok 1 - hello \# \\ world # TODO escape \# characters with \\
+```
+
+Harnesses _must_:
+
+1. Treat any `\\` as a literal `\`, but ignore it for the purpose of
+   escaping a `#` character.
+2. Treat any `\#` as a literal `#`, but ignore it for the purpose of
+   delimiting a directive, provided the `\` was not escaped.
+3. Treat any unescaped `#` as a literal `#` in a description or reason
+   field, if doing so would not cause it to be treated as a delimiter.
+
+### Escaping Examples
+
+The following are examples of escaping `#` and `\` characters, and
+including unescaped `#` characters in the Test Point description or `TODO`
+reason.
+
+Note that the specific fields `description`, `todo`, and `todo reason` are
+not normative, and shown for illustration purposes only.  Harnesses
+_should_ present this data to their consumers in whatever manner is
+appropriate for their language and context.
+
+```tap
+TAP version 14
+
+# description: hello
+# todo: true
+ok 1 - hello # todo
+
+# description: hello # todo
+# todo: false
+ok 2 - hello \# todo
+
+# description: hello
+# todo: true
+# todo reason: hash # character
+ok 3 - hello # todo hash \# character
+# (assuming "character" isn't a known custom directive)
+ok 4 - hello # todo hash # character
+
+# description: hello \
+# todo: true
+# todo reason: hash # character
+ok 5 - hello \\# todo hash \# character
+# (assuming "character" isn't a known custom directive)
+ok 6 - hello \\# todo hash # character
+
+# description: hello # description # todo
+# todo: false
+# (assuming "description" isn't a known custom directive)
+ok 7 - hello # description # todo
+
+# multiple escaped \ can appear in a row
+# description: hello \\\# todo
+# todo: false
+ok 8 - hello \\\\\\\# todo
+
+1..8
+```
 
 ## Examples
 

From f6ca3b0afa58c16a105ce3d353efa027f742be8d Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 21:51:50 -0800
Subject: [PATCH 25/40] TAP14: <code> Test::Harness

---
 tap-version-14-specification.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index ddd479c..940f3ba 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -789,11 +789,11 @@ considerable input, encouragement, feedback, and suggestions from:
 The TAP 13 Specification was written by Andy Armstrong with help and
 contributions from Pete Krawczyk, Paul Johnson, Ian Langworth and Nik
 Clayton, based on the original TAP documentation by Andy Lester, based on
-the original Test::Harness documentation by Michael Schwern.
+the original `Test::Harness` documentation by Michael Schwern.
 
 The basis for the TAP format was created by Larry Wall in the original test
 script for Perl 1. Tim Bunce and Andreas Koenig developed it further with
-their modifications to Test::Harness.
+their modifications to `Test::Harness`.
 
 ## Copyright
 

From fb2f09be53300c68cff0f472a00674905f656419 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 21:52:10 -0800
Subject: [PATCH 26/40] TAP14: thank Jonathan Kingston

---
 tap-version-14-specification.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 940f3ba..1b607b6 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -786,6 +786,9 @@ considerable input, encouragement, feedback, and suggestions from:
 
 ## Acknowledgements
 
+Special thanks to [Jonathan Kingston](https://github.com/jonathanKingston)
+for his efforts to keep TAP flourishing and bring implementors together.
+
 The TAP 13 Specification was written by Andy Armstrong with help and
 contributions from Pete Krawczyk, Paul Johnson, Ian Langworth and Nik
 Clayton, based on the original TAP documentation by Andy Lester, based on

From ac0043c4b93f178130976ac3ebed6b8e058a1d5f Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 23:08:24 -0800
Subject: [PATCH 27/40] TAP14: formatting of Test Point sections

---
 tap-version-14-specification.md | 226 ++++++++++++++++----------------
 1 file changed, 110 insertions(+), 116 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 1b607b6..2ea6382 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -214,128 +214,122 @@ The core of TAP is the "Test Point". A test file prints one test point
 executed. There must be at least one test point in TAP output. Each test
 point comprises the following elements:
 
-- Test Status: `ok` or `not ok`
-
-    This tells whether the test point passed or failed. It must be at the
-    beginning of the line. `/^not ok/` indicates a failed test point.
-    `/^ok/` is a successful test point. This is the only mandatory part of
-    the line.
-
-    Note that unlike the Directives below, `ok` and `not ok` are
-    case-sensitive.
-
-- Test Point ID
-
-    TAP expects the ok or not ok to be followed by an integer Test Point
-    ID. If there is no number, the harness _must_ maintain its own counter
-    until the script supplies test numbers again.
-
-    For example, the following test output is acceptable:
-
-    ```tap
-    1..5
-    not ok
-    ok
-    not ok
-    ok
-    ok
-    ```
-
-    and is equivalent to:
-
-    ```tap
-    1..5
-    not ok 1
-    ok 2
-    not ok 3
-    ok 4
-    ok 5
-    ```
-
-    This test output is _not_ a successful test run:
-
-    ```tap
-    TAP version 13
-    1..6
-    not ok
-    ok
-    not ok
-    ok
-    ok
-    ```
-
-    Five tests are shown, but the plan indicated that there would be 6.
-    Furthermore, tests 1 and 3 are explicitly failing.  Perl's
-    `Test::Harness` will report:
-
-    ```
-    FAILED tests 1, 3, 6
-    Failed 3/6 tests, 50.00% okay
-    ```
-
-    Test Points _may_ be output in any order, but any Test Point ID
-    provided _must_ be within the range described by the Plan.
-
-    This is valid TAP and a successful test run:
-
-    ```tap
-    TAP version 14
-    1..3
-    ok 2
-    ok 3
-    ok 1
-    ```
-
-    This is not a successful test run. Even though there are 3 Test Points,
-    the Test Point ID 4 is outside the stated Plan range.
-
-    ```tap
-    TAP version 14
-    1..3
-    ok 2
-    ok 4
-    ok 1
-    ```
-
-- Description
-
-    Any text after the test number but before a `#` is the description of
-    the test point.
-
-    ```tap
-    ok 42 - this is the description of the test
-    ```
-
-    Descriptions _should_ be separated from the Test Point Status and Test
-    Point ID by the string `" - "`, in order to prevent confusing a numeric
-    description with a Test Point ID.  Harnesses _must_ treat Test Points
-    identically whether the description starts with `" - "` or not.
-
-    For example, these two test points _must_ be treated identically by a
-    Harness:
-
-    ```tap
-    ok 1 this is fine
-    ok 1 - this is fine
-    ```
-
-    Harnesses _should not_ consider a leading `" - "` to be a part of the
-    description reported to a user.
-
-- Directive
-
-    The test point may include a directive, following a `#` on the test
-    line.  There are currently two Directives allowed: `TODO` and `SKIP`.
-    These are discussed below.
-
-To summarize:
+In summary:
 
 - Test Status: `ok`/`not ok` (required)
 - Test number (recommended)
 - Description (recommended, prefixed by `" - "`)
 - Directive (only when necessary)
 
-#### Directives
+#### Test Status: `ok` or `not ok`
+
+This tells whether the test point passed or failed. It must be at the
+beginning of the line. `/^not ok/` indicates a failed test point.
+`/^ok/` is a successful test point. This is the only mandatory part of
+the line.
+
+Note that unlike the Directives below, `ok` and `not ok` are
+case-sensitive.
+
+#### Test Point ID
+
+TAP expects the ok or not ok to be followed by an integer Test Point
+ID. If there is no number, the harness _must_ maintain its own counter
+until the script supplies test numbers again.
+
+For example, the following test output is acceptable:
+
+```tap
+1..5
+not ok
+ok
+not ok
+ok
+ok
+```
+
+and is equivalent to:
+
+```tap
+1..5
+not ok 1
+ok 2
+not ok 3
+ok 4
+ok 5
+```
+
+This test output is _not_ a successful test run:
+
+```tap
+TAP version 13
+1..6
+not ok
+ok
+not ok
+ok
+ok
+```
+
+Five tests are shown, but the plan indicated that there would be 6.
+Furthermore, tests 1 and 3 are explicitly failing.  Perl's
+`Test::Harness` will report:
+
+```
+FAILED tests 1, 3, 6
+Failed 3/6 tests, 50.00% okay
+```
+
+Test Points _may_ be output in any order, but any Test Point ID
+provided _must_ be within the range described by the Plan.
+
+This is valid TAP and a successful test run:
+
+```tap
+TAP version 14
+1..3
+ok 2
+ok 3
+ok 1
+```
+
+This is not a successful test run. Even though there are 3 Test Points,
+the Test Point ID 4 is outside the stated Plan range.
+
+```tap
+TAP version 14
+1..3
+ok 2
+ok 4
+ok 1
+```
+
+#### Description
+
+Any text after the test number but before a `#` is the description of
+the test point.
+
+```tap
+ok 42 - this is the description of the test
+```
+
+Descriptions _should_ be separated from the Test Point Status and Test
+Point ID by the string `" - "`, in order to prevent confusing a numeric
+description with a Test Point ID.  Harnesses _must_ treat Test Points
+identically whether the description starts with `" - "` or not.
+
+For example, these two test points _must_ be treated identically by a
+Harness:
+
+```tap
+ok 1 this is fine
+ok 1 - this is fine
+```
+
+Harnesses _should not_ consider a leading `" - "` to be a part of the
+description reported to a user.
+
+#### Directive
 
 Directives are special notes that follow the first unescaped `#` on the
 Test Point line.  Only two are currently defined: `TODO` and `SKIP`.

From 8068f3153b2a9dfd8f314a8a35a4cf18bb364452 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Fri, 4 Mar 2022 23:09:26 -0800
Subject: [PATCH 28/40] TAP14: (provisional) no repeating Test Point IDs

https://github.com/TestAnything/Specification/issues/27
---
 tap-version-14-specification.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 2ea6382..2b42b9d 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -304,6 +304,10 @@ ok 4
 ok 1
 ```
 
+Test Point IDs _should_ be unique within the TAP Document.  Harnesses _may_
+warn about repeated Test Point IDs or treat them as a test failure, but
+_must not_ treat a Test Point with a re-used ID as a non-TAP line.
+
 #### Description
 
 Any text after the test number but before a `#` is the description of

From c57ac913abe2a33d6a844e08615917d839629546 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Sat, 5 Mar 2022 10:20:42 -0800
Subject: [PATCH 29/40] TAP14: remove wiki holdover language

Co-authored-by: Matt Layman <matthewlayman@gmail.com>
---
 tap-version-14-specification.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 2b42b9d..92ea604 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -29,7 +29,7 @@ TAP, the Test Anything Protocol, is a simple text-based interface between
 testing modules a test harness. TAP started life as part of the test
 harness for Perl but now has implementations in C/C++, Python, PHP, Perl,
 JavaScript, and probably others by the time you read this.  This document
-describes version 14 of TAP. Go to TAP to read about previous versions.
+describes version 14 of TAP.
 
 The key words _must_, _must not_, _required_, _shall_, _shall not_,
 _should_, _should not_, _recommended_, _may_, and _optional_ in this

From 9585efb56be653009c81af6c84f75c203a46bcbd Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Sun, 6 Mar 2022 10:21:13 -0800
Subject: [PATCH 30/40] TAP14: SKIP and TODO can have additional non-whitespace
 characters

---
 tap-version-14-specification.md | 34 +++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 92ea604..efbf48b 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -352,10 +352,40 @@ in the Test Point description.
 Note that escaped `#` characters are not to be treated as delimiters for
 Directives.  See "Escaping" below.
 
+##### Backwards Compatibility Note
+
+For backwards compatibility with earlier incarnations of TAP, Harnesses
+_must_ accept additional non-whitespace characters following the the
+literal strings `"# SKIP"` or `"# TODO"`.  Everything after
+`(TODO|SKIP)\S*\s+` is the reason.  For example, this is supported, and
+shows a test with 2 `skip` tests: one with no reason given, and the other
+with an explanation.
+
+```tap
+TAP version 14
+1..2
+ok 1 - do it later # Skipped
+ok 2 - works on windows # Skipped: only run on windows
+```
+
+For broad compatibility with as many harnesses as possible, as well as
+future-proofing their output, Producers _should_ always report `SKIP` and
+`TODO` tests using only the directive names ("SKIP" or "TODO"), optionally
+followed by a space and a reason.  Future versions of this specification
+may drop support for `\S*` characters following directive names.
+
+Thus, the regular expression for directives is:
+
+```
+/#\s+(SKIP|TODO)\S*\s+([^\n]*)/
+directive type = $1
+reason = $2
+```
+
 ##### `TODO` tests
 
 If the directive starts with `# TODO`, the test is counted as a todo test,
-and the text after `TODO` is the explanation.
+and any text after `TODO\S*\s+` is the explanation.
 
 ```tap
 not ok 14 # TODO bend space and time
@@ -378,7 +408,7 @@ needing work, if that is appropriate for their use case.
 ##### `SKIP` tests
 
 If the directive starts with `# SKIP`, the test is counted as a skipped
-test, and the text after `SKIP` is the explanation.
+test, and the text after `SKIP\S*\s+` is the explanation.
 
 ```tap
 ok 14 - mung the gums # SKIP leave gums unmunged for now

From 40655dcc5668ea2c3648d14b36d8675b98d3c717 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Sun, 6 Mar 2022 10:59:13 -0800
Subject: [PATCH 31/40] TAP14: require directive #'s to be preceded by
 whitespace

This prevents eg 'https://example.com/x.html#skip' being treated as a
directive, since #'s occur in urls and other contexts.

Of course, a producer _should_ escape the # in that case, but that can't
be relied upon, so the Harness _should_ handle it.
---
 tap-version-14-specification.md | 39 +++++++++++++++++++++++++++------
 1 file changed, 32 insertions(+), 7 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index efbf48b..addb3c0 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -336,7 +336,8 @@ description reported to a user.
 #### Directive
 
 Directives are special notes that follow the first unescaped `#` on the
-Test Point line.  Only two are currently defined: `TODO` and `SKIP`.
+Test Point line which is preceded by whitespace.  Only two are currently
+defined: `TODO` and `SKIP`.
 
 Directives are not case sensitive.  That is, Harnesses _must_ treat `#
 SKIP`, `# skip`, and `# SkIp` identically.
@@ -352,19 +353,23 @@ in the Test Point description.
 Note that escaped `#` characters are not to be treated as delimiters for
 Directives.  See "Escaping" below.
 
-##### Backwards Compatibility Note
+##### Backwards Compatibility and Parsing Notes
 
 For backwards compatibility with earlier incarnations of TAP, Harnesses
 _must_ accept additional non-whitespace characters following the the
-literal strings `"# SKIP"` or `"# TODO"`.  Everything after
-`(TODO|SKIP)\S*\s+` is the reason.  For example, this is supported, and
-shows a test with 2 `skip` tests: one with no reason given, and the other
-with an explanation.
+literal strings `"SKIP"` or `"TODO"`.  Everything after `(TODO|SKIP)\S*\s+`
+is the reason.  For example, this is supported, and shows a test with 2
+`skip` tests: one with no reason given, and the other with an explanation.
 
 ```tap
 TAP version 14
 1..2
+
+# skip: true
 ok 1 - do it later # Skipped
+
+# skip: true
+# skip reason: "only run on windows"
 ok 2 - works on windows # Skipped: only run on windows
 ```
 
@@ -377,11 +382,31 @@ may drop support for `\S*` characters following directive names.
 Thus, the regular expression for directives is:
 
 ```
-/#\s+(SKIP|TODO)\S*\s+([^\n]*)/
+/\s+#\s*(SKIP|TODO)\S*\s+([^\n]*)/
 directive type = $1
 reason = $2
 ```
 
+More examples of parsing directives:
+
+```tap
+TAP version 14
+
+# skip: true
+# skip reason: "this test is skipped"
+# description: ""
+ok 1 #skip this test is skipped
+
+# skip: false
+# description: "not skipped: https://example.com/page.html\#skip is a url"
+ok 2 not skipped: https://example.com/page.html#skip is a url
+
+# skip: true
+# skip reason: "case insensitive, so this is skipped"
+# description: ""
+ok 3 - #SkIp case insensitive, so this is skipped
+```
+
 ##### `TODO` tests
 
 If the directive starts with `# TODO`, the test is counted as a todo test,

From c8f80ba20c79c1bb535c38d057fa50217e810c9c Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Sun, 6 Mar 2022 11:00:38 -0800
Subject: [PATCH 32/40] TAP14: fix fix the the extra extra word word

Co-authored-by: Matt Layman <matthewlayman@gmail.com>
---
 tap-version-14-specification.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index addb3c0..7efe021 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -356,7 +356,7 @@ Directives.  See "Escaping" below.
 ##### Backwards Compatibility and Parsing Notes
 
 For backwards compatibility with earlier incarnations of TAP, Harnesses
-_must_ accept additional non-whitespace characters following the the
+_must_ accept additional non-whitespace characters following the
 literal strings `"SKIP"` or `"TODO"`.  Everything after `(TODO|SKIP)\S*\s+`
 is the reason.  For example, this is supported, and shows a test with 2
 `skip` tests: one with no reason given, and the other with an explanation.

From 388d96a15540bc704783cbb8838e0fac893e676e Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Tue, 15 Mar 2022 14:56:40 -0700
Subject: [PATCH 33/40] TAP14: clarify space around # in directives

Fix: https://github.com/TestAnything/Specification/issues/28
---
 tap-version-14-specification.md | 57 ++++++++++++++++++++++++++++-----
 1 file changed, 49 insertions(+), 8 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 7efe021..5149c44 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -46,7 +46,7 @@ Version     := "TAP version 14\n"
 Plan        := "1.." (Number) (" # " Reason)? "\n"
 Body        := (TestPoint | BailOut | Pragma | Comment | Anything | Empty)*
 TestPoint   := ("not ")? "ok" (" " Number)? ((" -")? (" " Description) )? (" " Directive)? "\n" (YAMLBlock)?
-Directive   := "# " ("todo" | "skip") (" " Reason)?
+Directive   := " # " ("todo" | "skip") (" " Reason)?
 YAMLBlock   := "  ---\n" (YAMLLine)* "  ...\n"
 YAMLLine    := "  " (YAML)* "\n"
 BailOut     := "Bail out!" (" " Reason)? "\n"
@@ -58,8 +58,9 @@ Empty       := [\s\t]* "\n"
 Anything    := [^\n]+ "\n"
 ```
 
-(Note that the above is intended as a rough "pseudocode" guidance for
-humans.  It is not strict EBNF.)
+Note that the above is intended as a rough "pseudocode" guidance for
+humans.  It is not strict EBNF.  Detailed parsing instructions for each
+element can be found in the sections below.
 
 The Version is the line `TAP version 14`.
 
@@ -336,8 +337,8 @@ description reported to a user.
 #### Directive
 
 Directives are special notes that follow the first unescaped `#` on the
-Test Point line which is preceded by whitespace.  Only two are currently
-defined: `TODO` and `SKIP`.
+Test Point line that is preceded and followed by whitespace.  Only two are
+currently defined: `TODO` and `SKIP`.
 
 Directives are not case sensitive.  That is, Harnesses _must_ treat `#
 SKIP`, `# skip`, and `# SkIp` identically.
@@ -346,13 +347,53 @@ Harnesses _may_ support additional platform-specific Directives.  Future
 versions of this specification may codify additional Directives with
 defined semantics.
 
-Unrecognized Directives _must_ not be treated as test failure, or an
+Unrecognized Directives _must not_ be treated as test failure, or an
 invalid TAP line.  Harnesses _should_ include any unrecognized directives
 in the Test Point description.
 
 Note that escaped `#` characters are not to be treated as delimiters for
 Directives.  See "Escaping" below.
 
+##### Whitespace Around Directive Delimiter
+
+Earlier versions of the TAP specification were not explicit about
+whitespace requirements regarding directives.  The following rules maximize
+compatibility between TAP14 producers and harnesses:
+
+1. Producers _must_ output directives with at least one space character
+   preceding the `#` in a directive, as well as at least one space
+   character between the `#` and the directive name.
+
+2. Harnesses _must not_ treat escaped `#` characters as directive
+   delimiters.
+
+3. Harnesses _may_ accept directive delimiters where the `#` is not
+   preceded by whitespace, but _should_ warn that such output is
+   non-conformant with the TAP14 specification.
+
+If harnesses choose to parse directives without whitespace before and after
+the `#`, then they ought to consider the impact if test descriptions
+contain URLs and/or may be coming from TAP producers that are not diligent
+about escaping `#` characters.  This should be done only to the extent
+necessary for backwards compatibility with existing TAP producers.
+
+For example:
+
+```tap
+TAP version 13
+
+# MUST be treated as a SKIP test
+ok 1 - must be skipped test # SKIP
+
+# MUST NOT be treated as a SKIP test
+ok 2 - must not be skipped test \# SKIP
+
+# MAY be treated as a SKIP test, but SHOULD warn about it
+ok 3 - may skip, but should warn# skip
+ok 4 - may skip, but should warn #skip
+ok 5 - may skip, but should warn#skip
+```
+
 ##### Backwards Compatibility and Parsing Notes
 
 For backwards compatibility with earlier incarnations of TAP, Harnesses
@@ -395,7 +436,7 @@ TAP version 14
 # skip: true
 # skip reason: "this test is skipped"
 # description: ""
-ok 1 #skip this test is skipped
+ok 1 # skip this test is skipped
 
 # skip: false
 # description: "not skipped: https://example.com/page.html\#skip is a url"
@@ -487,7 +528,7 @@ YAML Diagnostic fields in common usage.
 ### Comments
 
 Lines outside of a YAML diagnostic block which begin with a `#` character
-preceeded by zero or more characters of whitespace, are comments.
+preceded by zero or more characters of whitespace, are comments.
 
 A Harness _may_ present these to the user, ignore them, or assign meaning
 to certain comments.

From 31b879158f189e5d9d56b28d44622ebf37ffb5bc Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Wed, 16 Mar 2022 12:22:43 -0700
Subject: [PATCH 34/40] TAP14: use version 14 except where relevant

---
 tap-version-14-specification.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 5149c44..09126e2 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -263,7 +263,7 @@ ok 5
 This test output is _not_ a successful test run:
 
 ```tap
-TAP version 13
+TAP version 14
 1..6
 not ok
 ok
@@ -380,7 +380,7 @@ necessary for backwards compatibility with existing TAP producers.
 For example:
 
 ```tap
-TAP version 13
+TAP version 14
 
 # MUST be treated as a SKIP test
 ok 1 - must be skipped test # SKIP
@@ -553,7 +553,7 @@ The structure of a Pragma line is:
 For example:
 
 ```tap
-TAP version 13
+TAP version 14
 # tell the parser to bail out on any failures from now on
 pragma +bail
 

From 3cd4b531621fe61c318d647097ce84028534b2a0 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Sun, 20 Mar 2022 17:01:57 -0700
Subject: [PATCH 35/40] TAP14: Subtests

Fix: https://github.com/TestAnything/Specification/issues/29
---
 tap-version-14-specification.md | 266 +++++++++++++++++++++++++++++++-
 1 file changed, 265 insertions(+), 1 deletion(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 09126e2..c3eb108 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -44,7 +44,7 @@ TAP14's general grammar is:
 TAPDocument := Version Plan Body | Version Body Plan
 Version     := "TAP version 14\n"
 Plan        := "1.." (Number) (" # " Reason)? "\n"
-Body        := (TestPoint | BailOut | Pragma | Comment | Anything | Empty)*
+Body        := (TestPoint | BailOut | Pragma | Comment | Anything | Empty | Subtest)*
 TestPoint   := ("not ")? "ok" (" " Number)? ((" -")? (" " Description) )? (" " Directive)? "\n" (YAMLBlock)?
 Directive   := " # " ("todo" | "skip") (" " Reason)?
 YAMLBlock   := "  ---\n" (YAMLLine)* "  ...\n"
@@ -53,6 +53,7 @@ BailOut     := "Bail out!" (" " Reason)? "\n"
 Reason      := [^\n]+
 Pragma      := "pragma " [+-] PragmaKey "\n"
 PragmaKey   := ([a-zA-Z0-9_-])+
+Subtest     := ("# Subtest" (": " SubtestName)?)? "\n" SubtestDocument TestPoint
 Comment     := ^ (" ")* "#" [^\n]* "\n"
 Empty       := [\s\t]* "\n"
 Anything    := [^\n]+ "\n"
@@ -68,6 +69,9 @@ The Body is a collection of lines representing a test set.
 
 The Plan reports on the number of tests included in the Body.
 
+A Subtest indicates a nested TAP Document that is included by the parent
+TAP Document.  It is a TAP Document where each line is indented by 4 spaces.
+
 For example, a test file's output might look like:
 
 ```tap
@@ -710,6 +714,266 @@ ok 8 - hello \\\\\\\# todo
 1..8
 ```
 
+## Subtests
+
+Subtests provide a way to nest one TAP14 stream inside another.  This is
+useful in a variety of situations.  For example:
+
+1. A Harness parses a collection of TAP documents, providing output which
+   is also in TAP format.
+
+    ```tap
+    TAP version 14
+    1..2
+
+    # Subtest: foo.tap
+        1..2
+        ok 1
+        ok 2 - this passed
+    ok 1 - foo.tap
+
+    # Subtest: bar.tap
+        ok 1 - object should be a Bar
+        not ok 2 - object.isBar should return true
+          ---
+          found: false
+          wanted: true
+          at:
+            file: test/bar.ts
+            line: 43
+            column: 8
+          ...
+        ok 3 - object can bar bears # TODO
+        1..3
+    not ok 2 - bar.tap
+      ---
+      fail: 1
+      todo: 1
+      ...
+    ```
+
+2. A test framework Producer provides an API for grouping assertions about
+   a related subject.  For example:
+
+    ```js
+    import t from 'tap'
+    t.ok(true, 'true is ok')
+    t.test('this is a subtest', subtest => {
+      subtest.pass('this is fine')
+      subtest.fail('this is not fine')
+      subtest.end()
+    })
+    ```
+
+    which produces the output:
+
+    ```tap
+    TAP version 14
+    ok 1 - true is ok
+    # Subtest: this is a subtest
+        ok 1 - this is fine
+        not ok 2 - this is not fine
+        1..2
+    not ok 2 - this is a subtest
+    1..2
+    ```
+
+Subtests are designed with graceful fallback for TAP 13 harnesses in mind.
+
+Since TAP 13 specifies that non-TAP output _should_ be ignored or provided
+directly to the user, and indented Test Points and Plans are non-TAP
+according to TAP 13, only the terminating correlated test point will be
+interpreted by most TAP 13 Harnesses.  Thus, they will usually report the
+overall subtest result correctly, even if they lack the details about the
+results of the subtest.
+
+Since several TAP 13 parsers in popular usage treat a repeated Version
+declaration as an error, even if the Version is indented, Subtests _should
+not_ include a Version, if TAP 13 Harness compatibility is desirable.
+
+### Bare Subtests
+
+In its simplest form, a Subtest is introduced by a 4-space indented Test
+Point, Version, Plan or Pragma line.
+
+For example:
+
+```tap
+TAP version 14
+    ok 1 - subtest test point
+    1..1
+ok 1 - subtest passing
+1..1
+```
+
+Note that, because the Version is optional in subtests, and the plan may
+occur after all test points, the first item in a subtest may be a further
+subtest.  Harnesses must thus treat any multiple of 4-space indentation is
+multiple levels of nested subtest:
+
+```tap
+TAP version 14
+        ok 1 - nested twice
+        1..1
+    ok 1 - nested parent
+    1..1
+ok 1 - double nest passing
+1..1
+```
+
+The first test point at the parent level is the correlated Test Point for
+the subtest, and terminates the Subtest.
+
+### Commented Subtests
+
+A Subtest may be introduced with a comment at the parent test indentation
+level, which defines the expected name of the terminating correlated Test
+Point.
+
+This comment has the form `^# Subtest(: .*)$`.  Everything after the `: `
+is the Subtest Name.  For example:
+
+```tap
+# Subtest: <name>
+```
+
+or
+
+```tap
+# Subtest
+```
+
+A Commented Subtest with a Subtest Name _must_ be terminated by a Test
+Point with a matching Description.  If no Subtest Name is present, then the
+terminating Test Point _must not_ include a description.
+
+For example:
+
+```tap
+TAP version 14
+
+ok 1 - in the parent
+
+# Subtest: nested
+    1..1
+    ok 1 - in the subtest
+ok 2 - nested
+
+# Subtest: empty
+    1..0
+ok 3 - empty
+
+# Subtest
+    ok 1 - name is optional
+    1..1
+ok 4
+
+1..4
+```
+
+Commented Subtests are encouraged, as they provide the following benefits:
+
+* Easier for humans to read.  For example:
+
+    ```tap
+    TAP version 14
+                1..1
+                ok 1 - hmm, what level is this?
+    ```
+
+    vs:
+
+    ```tap
+    TAP version 14
+    # Subtest: level 1
+        # Subtest: level 2
+            # Subtest: level 3
+                1..1
+                ok 1 - clearly level 3
+    ```
+
+* Additional strictness around matching the Test Point description to
+  Subtest Name can catch errors and detect accidentally interleaved output.
+
+### Subtest Bailouts
+
+Harnesses _must_ treat a Bailout in a nested Subtest as a bailout for the
+entire test run.
+
+For backwards compatibility with TAP13 Harnesses, Producers _should_ emit a
+`Bail out!` line at the root indentation level whenever a Subtest bails
+out.
+
+### Subtest Pragmas
+
+Any Pragmas set in a Subtest affect _only_ the parsing of the Subtest.
+Harnesses _must not_ allow Pragmas set in Subtests to affect the behavior
+of the parser with respect to the parent TAP Document.
+
+For example, given a Harnesses where a `strict` Pragma will cause it to
+treat any non-TAP as an error:
+
+```tap
+TAP version 14
+pragma -strict
+# Subtest: child test
+    1..1
+    pragma +strict
+    ok 1
+ok 1 - child test
+!!This is not valid TAP content!!
+1..1
+```
+
+In this TAP document, the non-TAP content _must not_ be treated as a test
+failure, because the `strict` Pragma setting at the parent level was false.
+
+### Subtest Parsing/Generating Rules
+
+1. The subtest TAP document is indented 4 spaces.
+2. Subtests _must_ be a valid TAP document, meaning that they cannot be
+   entirely empty.  At minimum, they must include a `1..0` line to indicate
+   that no Test Points are expected.  This implies the following:
+    1. Subtests can be nested within subtests by indenting another 4
+       characters for each level of nesting.
+    2. YAML Diagnostics are indented 2 spaces with respect to the Test
+       Point they are associated with.  So, for example, a YAML Diagnostic
+       block for a Test Point in a nested subtest would be indented 6
+       spaces (4 + 2).  In a subtest nested within another subtest, YAML
+       diagnostics would be indented 10 spaces (4 + 4 + 2).
+3. Subtests _should not_ emit a Version line, if compatibility with TAP 13
+   Harnesses is desirable.
+4. The subtest is terminated by a single Test Point line in the parent TAP
+   document, which follows the indented TAP Document.  This is the
+   Correlated Test Point, and reflects the pass/fail status of the Subtest.
+    1. Producers _must_ communicate the intended status of the subtest
+       (pass/fail/todo/skip/etc.) by assigning these semantics to the
+       correlated Test Point.
+    2. Harneses _should_ treat the entire subtest as either a pass or fail
+       based on the status of the correlated Test Point, but _may_ treat
+       the subtest as a failure if they would consider the nested subtest
+       TAP Document a test failure.
+5. Harnesses _should_ treat otherwise valid TAP that is indented anything
+   other than a multiple of 4 spaces as non-TAP.
+6. Providers _should not_ emit a Version for the Subtest TAP Document.
+7. Providers _should_ emit a Subtest Comment if the name of the subtest is
+   known at the outset.
+8. If Subtest Comment is provided, Harnesses _should_ continue the subtest
+   until a matching test point (same name, or no name in either) at parent
+   level is found, treating any other un-indented lines as non-TAP, and
+   fail the test if a matching test point is not found.
+9. If subtest comment is not provided, Harnesses _must_ treat the next Test
+   Point at the parent level as the end of the subtest, and treat any
+   intervening lines indented less than the subtest level as non-TAP.
+10. Harnesses _should_ treat unterminated Subtests as non-TAP.
+11. A Bailout in a subtest TAP document _must_ abort the entire process,
+    exactly as if it had occurred in the top-level TAP document.
+12. Any lines at the parent indentation level that occur between the
+    Subtest Introduction and a valid Subtest Termination _must_ be treated
+    as non-TAP output.
+
+------
+
 ## Examples
 
 All names, places, and events depicted in any example are wholly fictitious

From 71228cb7bcc29f75c2d6adc9d783ac95d1de8aad Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Wed, 23 Mar 2022 17:54:05 -0700
Subject: [PATCH 36/40] TAP14: corrections from @kinow

---
 tap-version-14-specification.md | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index c3eb108..171b0d7 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -778,18 +778,18 @@ useful in a variety of situations.  For example:
     1..2
     ```
 
-Subtests are designed with graceful fallback for TAP 13 harnesses in mind.
+Subtests are designed with graceful fallback for TAP13 harnesses in mind.
 
-Since TAP 13 specifies that non-TAP output _should_ be ignored or provided
+Since TAP13 specifies that non-TAP output _should_ be ignored or provided
 directly to the user, and indented Test Points and Plans are non-TAP
-according to TAP 13, only the terminating correlated test point will be
-interpreted by most TAP 13 Harnesses.  Thus, they will usually report the
+according to TAP13, only the terminating correlated test point will be
+interpreted by most TAP13 Harnesses.  Thus, they will usually report the
 overall subtest result correctly, even if they lack the details about the
 results of the subtest.
 
-Since several TAP 13 parsers in popular usage treat a repeated Version
+Since several TAP13 parsers in popular usage treat a repeated Version
 declaration as an error, even if the Version is indented, Subtests _should
-not_ include a Version, if TAP 13 Harness compatibility is desirable.
+not_ include a Version, if TAP13 Harness compatibility is desirable.
 
 ### Bare Subtests
 
@@ -910,8 +910,8 @@ Any Pragmas set in a Subtest affect _only_ the parsing of the Subtest.
 Harnesses _must not_ allow Pragmas set in Subtests to affect the behavior
 of the parser with respect to the parent TAP Document.
 
-For example, given a Harnesses where a `strict` Pragma will cause it to
-treat any non-TAP as an error:
+For example, given a Harness where a `strict` Pragma will cause it to treat
+any non-TAP as an error:
 
 ```tap
 TAP version 14
@@ -941,7 +941,7 @@ failure, because the `strict` Pragma setting at the parent level was false.
        block for a Test Point in a nested subtest would be indented 6
        spaces (4 + 2).  In a subtest nested within another subtest, YAML
        diagnostics would be indented 10 spaces (4 + 4 + 2).
-3. Subtests _should not_ emit a Version line, if compatibility with TAP 13
+3. Subtests _should not_ emit a Version line, if compatibility with TAP13
    Harnesses is desirable.
 4. The subtest is terminated by a single Test Point line in the parent TAP
    document, which follows the indented TAP Document.  This is the
@@ -949,7 +949,7 @@ failure, because the `strict` Pragma setting at the parent level was false.
     1. Producers _must_ communicate the intended status of the subtest
        (pass/fail/todo/skip/etc.) by assigning these semantics to the
        correlated Test Point.
-    2. Harneses _should_ treat the entire subtest as either a pass or fail
+    2. Harnesses _should_ treat the entire subtest as either a pass or fail
        based on the status of the correlated Test Point, but _may_ treat
        the subtest as a failure if they would consider the nested subtest
        TAP Document a test failure.
@@ -1147,7 +1147,7 @@ considerable input, encouragement, feedback, and suggestions from:
 Special thanks to [Jonathan Kingston](https://github.com/jonathanKingston)
 for his efforts to keep TAP flourishing and bring implementors together.
 
-The TAP 13 Specification was written by Andy Armstrong with help and
+The TAP13 Specification was written by Andy Armstrong with help and
 contributions from Pete Krawczyk, Paul Johnson, Ian Langworth and Nik
 Clayton, based on the original TAP documentation by Andy Lester, based on
 the original `Test::Harness` documentation by Michael Schwern.

From 4129fdb1ef5d07a51d33e52da1089d88b8e1414c Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Wed, 23 Mar 2022 17:58:44 -0700
Subject: [PATCH 37/40] TAP14: pragmas only introduce subtests if they're
 supported

---
 tap-version-14-specification.md | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 171b0d7..f61802c 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -793,8 +793,9 @@ not_ include a Version, if TAP13 Harness compatibility is desirable.
 
 ### Bare Subtests
 
-In its simplest form, a Subtest is introduced by a 4-space indented Test
-Point, Version, Plan or Pragma line.
+In its simplest form, a Subtest is introduced by a 4-space indented valid
+TAP line.  That is, a Test Point, Version, Plan, or (if Pragmas are
+supported) Pragma, prefixed by 4 space characters.
 
 For example:
 

From d78673be8273d0b80df598fca60a71d891f33e13 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Thu, 24 Mar 2022 13:00:56 -0700
Subject: [PATCH 38/40] TAP14: "Subtest Comment" is a Defined Term

Co-authored-by: Matt Layman <matthewlayman@gmail.com>
---
 tap-version-14-specification.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index f61802c..9c40e5d 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -963,7 +963,7 @@ failure, because the `strict` Pragma setting at the parent level was false.
    until a matching test point (same name, or no name in either) at parent
    level is found, treating any other un-indented lines as non-TAP, and
    fail the test if a matching test point is not found.
-9. If subtest comment is not provided, Harnesses _must_ treat the next Test
+9. If Subtest Comment is not provided, Harnesses _must_ treat the next Test
    Point at the parent level as the end of the subtest, and treat any
    intervening lines indented less than the subtest level as non-TAP.
 10. Harnesses _should_ treat unterminated Subtests as non-TAP.

From 92fe30cdbe18c8d0cb903ff0a22e4765de3f814a Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Mon, 28 Mar 2022 09:04:01 -0700
Subject: [PATCH 39/40] TAP14: specify YAML v1.2

Re: https://github.com/TestAnything/Specification/pull/25#pullrequestreview-922477041
---
 tap-version-14-specification.md | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 9c40e5d..7c619c6 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -495,10 +495,11 @@ were not tested, if that is appropriate for their use case.
 
 ### YAML Diagnostics
 
-If a Test Point is followed by a 2-space indented block beginning with
-the line `  ---` and ending with the line `  ...`, separated from the Test
+If a Test Point is followed by a 2-space indented block beginning with the
+line `  ---` and ending with the line `  ...`, separated from the Test
 Point only by comments or whitespace, then the block of lines between these
-markers will be interpreted as an inline YAML Diagnostic document.
+markers will be interpreted as an inline YAML Diagnostic document according
+to version 1.2 of the [YAML specification](https://yaml.org).
 
 The YAML encodes a data structure that provides information about the
 preceding Test Point.

From 2c1c6086f17c8d4ba4cab26dcea9afc42b1db223 Mon Sep 17 00:00:00 2001
From: isaacs <i@izs.me>
Date: Mon, 18 Apr 2022 09:05:26 -0700
Subject: [PATCH 40/40] TAP14: no longer a draft!

---
 tap-version-14-specification.md | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/tap-version-14-specification.md b/tap-version-14-specification.md
index 7c619c6..3d37a52 100644
--- a/tap-version-14-specification.md
+++ b/tap-version-14-specification.md
@@ -3,14 +3,6 @@ layout: default
 title: TAP 14 specification
 ---
 
-# Status: DRAFT
-
-This is a draft document pending further editing and ratification by no
-fewer than 3 widely used TAP implementations in 3 different language
-communities.
-
-This section will likely be removed prior to ratification.
-
 ## Goals of This Specification
 
 * Document the observed behavior of widely used TAP implementations.
