@descent-vtt/spec-brief 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -11,6 +11,22 @@ release that can turn a run red. This is the family's policy, recorded in
11
11
  releases up to 0.2.7 came before it, and several of their patches changed
12
12
  what a run reports.
13
13
 
14
+ ## 0.4.1
15
+
16
+ `lint`, `matrix`, `schedule` and `archive` over a large repository take time
17
+ that grows with the work, not with its square; nothing they answer has
18
+ changed.
19
+
20
+ ### Changed
21
+
22
+ - **`lint`, `matrix`, `schedule` and `archive` take time that grows with the
23
+ briefs and the tree, not with the one times the other.** Every scope pattern
24
+ was asked about every file git sees; the tree is now indexed by path once a
25
+ run, and a pattern is asked only about the files below the directories its
26
+ matches must lie in. Over 240 briefs and 93,000 files a lint took 35 s,
27
+ nine tenths of it matching, and `matrix` 16 s. Nothing any command answers
28
+ has changed.
29
+
14
30
  ## 0.4.0
15
31
 
16
32
  spec-brief reads English only again, and a placeholder is told from a word
package/dist/glob.d.ts CHANGED
@@ -69,6 +69,14 @@ export declare function parseGlob(source: string, options?: ParseOptions): GlobP
69
69
  * `.` segments are dropped, so `./src//a.ts` is `src/a.ts`.
70
70
  */
71
71
  export declare function matchGlob(glob: Glob, path: string): boolean;
72
+ /**
73
+ * The files of a list a glob matches, in the list's order: those
74
+ * {@link matchGlob} matches, asked only of the files below one of the glob's
75
+ * bases.
76
+ */
77
+ export declare function filesMatching(glob: Glob, files: readonly string[]): string[];
78
+ /** Whether a glob matches any file of a list, asked only of the files below one of its bases. */
79
+ export declare function matchesAny(glob: Glob, files: readonly string[]): boolean;
72
80
  /**
73
81
  * A shortest path every glob in `include` matches and none in `exclude` does,
74
82
  * `none` as a proof that there is no such path, or `undecided` when the search
package/dist/glob.js CHANGED
@@ -77,6 +77,78 @@ export function matchGlob(glob, path) {
77
77
  const canonical = segments(path).join('/');
78
78
  return canonical !== '' && glob.compiled.match(canonical);
79
79
  }
80
+ const indexes = new WeakMap();
81
+ /** The index of a list. Built once per list, which every pattern of a run shares, as {@link treeOf} is. */
82
+ function indexOf(files) {
83
+ const known = indexes.get(files);
84
+ if (known !== undefined)
85
+ return known;
86
+ const positions = new Map();
87
+ files.forEach((file, position) => {
88
+ const path = segments(file).join('/');
89
+ const others = positions.get(path);
90
+ if (others === undefined)
91
+ positions.set(path, [position]);
92
+ else
93
+ others.push(position);
94
+ });
95
+ const index = { paths: [...positions.keys()].sort(), positions };
96
+ indexes.set(files, index);
97
+ return index;
98
+ }
99
+ /**
100
+ * The positions of the files a glob can match: the run of the index below
101
+ * each of its bases. spec-core names, for each brace alternative, the
102
+ * directory every match of it lies below, or `''` where a match can lie
103
+ * anywhere, so a file below none of them cannot match. Asking every pattern
104
+ * about every file made `lint`, `matrix` and `schedule` grow with patterns
105
+ * times files: over 240 briefs and 93,000 files a lint took 35 s, nine tenths
106
+ * of it matching.
107
+ */
108
+ function* candidates(index, glob) {
109
+ const { paths, positions } = index;
110
+ for (const base of glob.compiled.bases) {
111
+ const prefix = base === '' ? '' : `${base}/`;
112
+ // The first path that sorts at or after the prefix. `<=` finds the same
113
+ // one, an equivalent mutant: no path read so ends with `/`, so none
114
+ // equals a prefix but `''`, which no glob matches.
115
+ let low = 0;
116
+ let high = paths.length;
117
+ while (low < high) {
118
+ const middle = (low + high) >>> 1;
119
+ if (paths[middle] < prefix)
120
+ low = middle + 1;
121
+ else
122
+ high = middle;
123
+ }
124
+ for (let place = low; place < paths.length && paths[place].startsWith(prefix); place += 1) {
125
+ yield* positions.get(paths[place]);
126
+ }
127
+ }
128
+ }
129
+ /**
130
+ * The files of a list a glob matches, in the list's order: those
131
+ * {@link matchGlob} matches, asked only of the files below one of the glob's
132
+ * bases.
133
+ */
134
+ export function filesMatching(glob, files) {
135
+ const index = indexOf(files);
136
+ const matched = new Set();
137
+ for (const position of candidates(index, glob)) {
138
+ if (matchGlob(glob, files[position]))
139
+ matched.add(position);
140
+ }
141
+ return [...matched].sort((a, b) => a - b).map((position) => files[position]);
142
+ }
143
+ /** Whether a glob matches any file of a list, asked only of the files below one of its bases. */
144
+ export function matchesAny(glob, files) {
145
+ const index = indexOf(files);
146
+ for (const position of candidates(index, glob)) {
147
+ if (matchGlob(glob, files[position]))
148
+ return true;
149
+ }
150
+ return false;
151
+ }
80
152
  /**
81
153
  * A shortest path every glob in `include` matches and none in `exclude` does,
82
154
  * `none` as a proof that there is no such path, or `undecided` when the search
package/dist/glob.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"glob.js","sourceRoot":"","sources":["../src/glob.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Scopes as globs: spec-core's `path` dialect, read the way spec-brief reads a\n * brief.\n *\n * The syntax, the automaton and the witness search are spec-core's, copied\n * into `src/vendor/` and verified by hash, so the family's tools read one\n * pattern the same way (spec-core ADR-0003). What is decided here is what\n * spec-brief adds around it:\n *\n * - A pattern is relative to the repository root, so a leading `/` is refused\n * rather than rooted at the filesystem: on the pattern, and on a text its\n * braces give, since spec-core reads `{/docs,x}` as `/docs` or `x`, and\n * `docs` would fall out of the scope unsaid. A leading `./` goes with the\n * slashes after it, as POSIX reads them: `.//docs` is `docs`, and\n * `./{/docs,x}` is `docs` or `x`. A list entry's `!` has no list to belong\n * to in a scope, so it is refused rather than read.\n * - Paths compare case-sensitively on every host, as git's do.\n * - A path with no glob syntax is read as the tree reads it: a file the tree\n * holds is that file, a directory it holds is everything beneath it, and a\n * path it does not hold is a file, unless it is written with a trailing `/`.\n * The tree, not the spelling, knows that `Dockerfile` is a file and\n * `docs/v1.2` a directory (ADR-0005, amended 2026-09-26).\n * - A trailing `/**` is at least one segment, so `docs/**` is the directory's\n * contents and a collision witness is always a file. A trailing `/` means\n * the same on a brace alternative as on the whole pattern: `{src/,lib}` is\n * `src/` or `lib`, and the tree is asked about `lib` alone.\n *\n * Nothing here compiles to a `RegExp`. Matching costs at most the pattern's\n * size times the path's length, and a question about two scopes that cannot be\n * answered within the search's budget answers `undecided`, never a guess.\n */\n\nimport {\n globAlternatives,\n globCovers as coreCovers,\n globWitness as coreWitness,\n isGlobSyntax,\n parseGlob as coreParse,\n type Glob as CoreGlob,\n type LiteralReading,\n WITNESS_BUDGET,\n type Witness,\n} from './vendor/spec-core/pattern/index.js';\nimport { segments } from './vendor/spec-core/path/index.js';\n\nexport { isGlobSyntax, type LiteralReading, WITNESS_BUDGET, type Witness };\n\n/** A literal path a pattern names, and how it was read. */\nexport interface Literal {\n readonly path: string;\n readonly reading: LiteralReading;\n}\n\nexport interface Glob {\n readonly source: string;\n /** The compiled pattern: spec-core's `path` dialect, case-sensitive. */\n readonly compiled: CoreGlob;\n /**\n * Each path the pattern names with no glob syntax and no trailing `/`, one\n * per brace alternative; empty when it has none.\n */\n readonly literals: readonly Literal[];\n}\n\nexport type GlobParse = { readonly ok: true; readonly glob: Glob } | { readonly ok: false; readonly error: string };\n\nexport interface ParseOptions {\n /**\n * How a path with no glob syntax is read: `file`, that path alone;\n * `directory`, everything beneath it; `either`, both. A function is asked\n * per literal path, as {@link readingIn} answers for a tree. `file` when\n * unset: a path nothing says is a directory is not read as one.\n */\n readonly literal?: LiteralReading | ((path: string) => LiteralReading) | undefined;\n}\n\n/** Parses a scope pattern, or says why it cannot. */\nexport function parseGlob(source: string, options: ParseOptions = {}): GlobParse {\n const pattern = source.trim();\n if (pattern.startsWith('!')) return { ok: false, error: 'negated patterns are not supported; narrow the positive pattern' };\n // spec-core's own reading of where each alternative starts, a leading `./`\n // and `/` included (spec-core ADR-0003). A pattern it refuses, the core's\n // parse refuses in the same words, so either may say so. It comes first so\n // that a pattern led by `/`, which the core roots at the filesystem's root,\n // is refused in spec-brief's words.\n const read = globAlternatives(pattern);\n if (!read.ok) return { ok: false, error: read.error };\n if (read.rooted) return { ok: false, error: 'a pattern is relative to the repository root and cannot start with \"/\"' };\n const given = options.literal ?? 'file';\n const literals: Literal[] = [];\n const literal = (path: string): LiteralReading => {\n const reading = typeof given === 'function' ? given(path) : given;\n literals.push({ path, reading });\n return reading;\n };\n // A pattern too large to compile is refused by the core, with its reason,\n // as a malformed one is; what the reading throws is a defect, and passes on.\n const parsed = coreParse(pattern, { dialect: 'path', caseSensitive: true, literal });\n if (!parsed.ok) return parsed;\n // Once the core has parsed the pattern, so that an alternative naming no\n // path, `{/,x}`, is refused in the core's words. The text is named behind\n // the `/` that roots it, as spec-core gives it: it reads the same written\n // alone, so a `}` or `,` no group took is written as a class, `[}]`.\n const rooted = read.alternatives.find((alternative) => alternative.rooted);\n if (rooted !== undefined) {\n return { ok: false, error: `a pattern is relative to the repository root, and the braces expand to \"/${rooted.text}\", which starts with \"/\"` };\n }\n return { ok: true, glob: { source, compiled: parsed.glob, literals } };\n}\n\n/**\n * Whether a path matches. The path is read as a repository path: empty and\n * `.` segments are dropped, so `./src//a.ts` is `src/a.ts`.\n */\nexport function matchGlob(glob: Glob, path: string): boolean {\n const canonical = segments(path).join('/');\n return canonical !== '' && glob.compiled.match(canonical);\n}\n\n/**\n * A shortest path every glob in `include` matches and none in `exclude` does,\n * `none` as a proof that there is no such path, or `undecided` when the search\n * met its budget first.\n */\nexport function globWitness(include: readonly Glob[], exclude: readonly Glob[] = [], budget: number = WITNESS_BUDGET): Witness {\n return coreWitness(\n include.map((g) => g.compiled),\n exclude.map((g) => g.compiled),\n budget,\n );\n}\n\n/** Whether every path `inner` matches is matched by one of `outer`, or `undecided`. */\nexport function globCovers(outer: readonly Glob[], inner: Glob, budget: number = WITNESS_BUDGET): boolean | 'undecided' {\n return coreCovers(\n outer.map((g) => g.compiled),\n inner.compiled,\n budget,\n );\n}\n\n/**\n * A path both globs match, or `null` when there is none: the 0.1 interface,\n * kept for the library's callers. It cannot say `undecided`, so a search that\n * meets its budget throws; {@link globWitness} answers in three ways.\n */\nexport function intersectGlobs(a: Glob, b: Glob, budget: number = WITNESS_BUDGET): string | null {\n const witness = globWitness([a, b], [], budget);\n if (witness.kind === 'undecided') {\n throw new Error(`whether \"${a.source}\" and \"${b.source}\" meet is undecided within the search's budget`);\n }\n return witness.kind === 'found' ? witness.path : null;\n}\n\n/**\n * The directories a walk must enter to find every match, one per brace\n * alternative: the leading literal segments, or a literal file's directory.\n * `''` for an alternative that can match at the root.\n */\nexport function globBases(glob: Glob): readonly string[] {\n return glob.compiled.bases;\n}\n\n/** The first of {@link globBases}: the 0.1 interface, kept for the library's callers. */\nexport function globBase(glob: Glob): string {\n // One base per alternative, and a pattern has at least one.\n return glob.compiled.bases[0] as string;\n}\n\n/** A brace alternative as its pattern writes it, and the index in the pattern where it ends. */\nexport interface WrittenAlternative {\n readonly written: string;\n readonly end: number;\n}\n\n/**\n * Each alternative of a pattern as written, in the order the core expands\n * them, and where each ends, when a `/` written there ends that alternative\n * and no other: the pattern itself when it has no braces, or the alternatives\n * of braces that end the pattern and whose own braces end theirs -\n * `lib/{util,new}`, `{a,b/{c,d}}`. `null` when more of the pattern follows\n * braces, `{a,b}/new`, since every alternative they give ends where the\n * pattern does; and for a pattern with a class, which may hold a brace or a\n * comma of its own and which this does not read.\n *\n * spec-core expands braces and keeps nothing of where an alternative was\n * written, and a note's advice is built from what was written, as the core\n * builds its own. So this reads braces as the expansion does, for a pattern\n * that parses: a `\\` escapes the next character, and a `}` with no `{` open\n * is a literal.\n */\nexport function writtenAlternatives(pattern: string): WrittenAlternative[] | null {\n let depth = 0;\n let open = 0;\n const stops: number[] = [];\n for (let i = 0; i < pattern.length; i += 1) {\n const ch = pattern.charAt(i);\n if (ch === '\\\\') {\n i += 1;\n } else if (ch === '[') {\n return null;\n } else if (ch === '{') {\n if (depth === 0) open = i;\n depth += 1;\n } else if (ch === ',' && depth === 1) {\n stops.push(i);\n } else if (ch === '}' && depth > 0) {\n depth -= 1;\n if (depth === 0) return i === pattern.length - 1 ? optionsOf(pattern, open, [...stops, i]) : null;\n }\n }\n return [{ written: pattern, end: pattern.length }];\n}\n\n/** The alternatives of the braces opened at `open`, each option ending at one of `stops`. */\nfunction optionsOf(pattern: string, open: number, stops: readonly number[]): WrittenAlternative[] | null {\n const prefix = pattern.slice(0, open);\n const alternatives: WrittenAlternative[] = [];\n let start = open + 1;\n for (const stop of stops) {\n const inner = writtenAlternatives(pattern.slice(start, stop));\n if (inner === null) return null;\n for (const { written, end } of inner) alternatives.push({ written: prefix + written, end: start + end });\n start = stop + 1;\n }\n return alternatives;\n}\n\n/** A name with an extension, `login.ts` or `.eslintrc.json`, and not a dot-name such as `.github`. */\nexport function hasExtension(name: string): boolean {\n return /.\\.[^.]+$/.test(name);\n}\n\n/** The files a tree holds, and every directory above one. */\nexport interface Tree {\n readonly files: ReadonlySet<string>;\n readonly directories: ReadonlySet<string>;\n}\n\nconst trees = new WeakMap<readonly string[], Tree>();\n\n/** The tree a list of files describes. Built once per list, which every brief of a run shares. */\nexport function treeOf(files: readonly string[]): Tree {\n const known = trees.get(files);\n if (known !== undefined) return known;\n const directories = new Set<string>();\n for (const file of files) {\n for (let slash = file.indexOf('/'); slash !== -1; slash = file.indexOf('/', slash + 1)) directories.add(file.slice(0, slash));\n }\n const tree = { files: new Set(files), directories };\n trees.set(files, tree);\n return tree;\n}\n\n/** What the tree holds at a path: a file, a directory, or nothing. */\nexport function held(tree: Tree, path: string): 'file' | 'directory' | null {\n if (tree.files.has(path)) return 'file';\n return tree.directories.has(path) ? 'directory' : null;\n}\n\n/**\n * How a tree reads a literal path: a directory it holds is a directory, and\n * anything else is a file. Without a tree nothing is known to be a directory,\n * so every literal is a file; a trailing `/` says otherwise, and never reaches\n * this question.\n */\nexport function readingIn(files: readonly string[] | null): (path: string) => LiteralReading {\n if (files === null) return () => 'file';\n const tree = treeOf(files);\n return (path) => (held(tree, path) === 'directory' ? 'directory' : 'file');\n}\n"]}
1
+ {"version":3,"file":"glob.js","sourceRoot":"","sources":["../src/glob.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Scopes as globs: spec-core's `path` dialect, read the way spec-brief reads a\n * brief.\n *\n * The syntax, the automaton and the witness search are spec-core's, copied\n * into `src/vendor/` and verified by hash, so the family's tools read one\n * pattern the same way (spec-core ADR-0003). What is decided here is what\n * spec-brief adds around it:\n *\n * - A pattern is relative to the repository root, so a leading `/` is refused\n * rather than rooted at the filesystem: on the pattern, and on a text its\n * braces give, since spec-core reads `{/docs,x}` as `/docs` or `x`, and\n * `docs` would fall out of the scope unsaid. A leading `./` goes with the\n * slashes after it, as POSIX reads them: `.//docs` is `docs`, and\n * `./{/docs,x}` is `docs` or `x`. A list entry's `!` has no list to belong\n * to in a scope, so it is refused rather than read.\n * - Paths compare case-sensitively on every host, as git's do.\n * - A path with no glob syntax is read as the tree reads it: a file the tree\n * holds is that file, a directory it holds is everything beneath it, and a\n * path it does not hold is a file, unless it is written with a trailing `/`.\n * The tree, not the spelling, knows that `Dockerfile` is a file and\n * `docs/v1.2` a directory (ADR-0005, amended 2026-09-26).\n * - A trailing `/**` is at least one segment, so `docs/**` is the directory's\n * contents and a collision witness is always a file. A trailing `/` means\n * the same on a brace alternative as on the whole pattern: `{src/,lib}` is\n * `src/` or `lib`, and the tree is asked about `lib` alone.\n *\n * Nothing here compiles to a `RegExp`. Matching costs at most the pattern's\n * size times the path's length, and a question about two scopes that cannot be\n * answered within the search's budget answers `undecided`, never a guess.\n */\n\nimport {\n globAlternatives,\n globCovers as coreCovers,\n globWitness as coreWitness,\n isGlobSyntax,\n parseGlob as coreParse,\n type Glob as CoreGlob,\n type LiteralReading,\n WITNESS_BUDGET,\n type Witness,\n} from './vendor/spec-core/pattern/index.js';\nimport { segments } from './vendor/spec-core/path/index.js';\n\nexport { isGlobSyntax, type LiteralReading, WITNESS_BUDGET, type Witness };\n\n/** A literal path a pattern names, and how it was read. */\nexport interface Literal {\n readonly path: string;\n readonly reading: LiteralReading;\n}\n\nexport interface Glob {\n readonly source: string;\n /** The compiled pattern: spec-core's `path` dialect, case-sensitive. */\n readonly compiled: CoreGlob;\n /**\n * Each path the pattern names with no glob syntax and no trailing `/`, one\n * per brace alternative; empty when it has none.\n */\n readonly literals: readonly Literal[];\n}\n\nexport type GlobParse = { readonly ok: true; readonly glob: Glob } | { readonly ok: false; readonly error: string };\n\nexport interface ParseOptions {\n /**\n * How a path with no glob syntax is read: `file`, that path alone;\n * `directory`, everything beneath it; `either`, both. A function is asked\n * per literal path, as {@link readingIn} answers for a tree. `file` when\n * unset: a path nothing says is a directory is not read as one.\n */\n readonly literal?: LiteralReading | ((path: string) => LiteralReading) | undefined;\n}\n\n/** Parses a scope pattern, or says why it cannot. */\nexport function parseGlob(source: string, options: ParseOptions = {}): GlobParse {\n const pattern = source.trim();\n if (pattern.startsWith('!')) return { ok: false, error: 'negated patterns are not supported; narrow the positive pattern' };\n // spec-core's own reading of where each alternative starts, a leading `./`\n // and `/` included (spec-core ADR-0003). A pattern it refuses, the core's\n // parse refuses in the same words, so either may say so. It comes first so\n // that a pattern led by `/`, which the core roots at the filesystem's root,\n // is refused in spec-brief's words.\n const read = globAlternatives(pattern);\n if (!read.ok) return { ok: false, error: read.error };\n if (read.rooted) return { ok: false, error: 'a pattern is relative to the repository root and cannot start with \"/\"' };\n const given = options.literal ?? 'file';\n const literals: Literal[] = [];\n const literal = (path: string): LiteralReading => {\n const reading = typeof given === 'function' ? given(path) : given;\n literals.push({ path, reading });\n return reading;\n };\n // A pattern too large to compile is refused by the core, with its reason,\n // as a malformed one is; what the reading throws is a defect, and passes on.\n const parsed = coreParse(pattern, { dialect: 'path', caseSensitive: true, literal });\n if (!parsed.ok) return parsed;\n // Once the core has parsed the pattern, so that an alternative naming no\n // path, `{/,x}`, is refused in the core's words. The text is named behind\n // the `/` that roots it, as spec-core gives it: it reads the same written\n // alone, so a `}` or `,` no group took is written as a class, `[}]`.\n const rooted = read.alternatives.find((alternative) => alternative.rooted);\n if (rooted !== undefined) {\n return { ok: false, error: `a pattern is relative to the repository root, and the braces expand to \"/${rooted.text}\", which starts with \"/\"` };\n }\n return { ok: true, glob: { source, compiled: parsed.glob, literals } };\n}\n\n/**\n * Whether a path matches. The path is read as a repository path: empty and\n * `.` segments are dropped, so `./src//a.ts` is `src/a.ts`.\n */\nexport function matchGlob(glob: Glob, path: string): boolean {\n const canonical = segments(path).join('/');\n return canonical !== '' && glob.compiled.match(canonical);\n}\n\n/** A list of files by path, so the files below a directory are one run of it. */\ninterface FileIndex {\n /** Each path the list holds, as {@link matchGlob} reads it, once, in code-unit order. */\n readonly paths: readonly string[];\n /** The positions in the list of each path's files. */\n readonly positions: ReadonlyMap<string, readonly number[]>;\n}\n\nconst indexes = new WeakMap<readonly string[], FileIndex>();\n\n/** The index of a list. Built once per list, which every pattern of a run shares, as {@link treeOf} is. */\nfunction indexOf(files: readonly string[]): FileIndex {\n const known = indexes.get(files);\n if (known !== undefined) return known;\n const positions = new Map<string, number[]>();\n files.forEach((file, position) => {\n const path = segments(file).join('/');\n const others = positions.get(path);\n if (others === undefined) positions.set(path, [position]);\n else others.push(position);\n });\n const index = { paths: [...positions.keys()].sort(), positions };\n indexes.set(files, index);\n return index;\n}\n\n/**\n * The positions of the files a glob can match: the run of the index below\n * each of its bases. spec-core names, for each brace alternative, the\n * directory every match of it lies below, or `''` where a match can lie\n * anywhere, so a file below none of them cannot match. Asking every pattern\n * about every file made `lint`, `matrix` and `schedule` grow with patterns\n * times files: over 240 briefs and 93,000 files a lint took 35 s, nine tenths\n * of it matching.\n */\nfunction* candidates(index: FileIndex, glob: Glob): Generator<number> {\n const { paths, positions } = index;\n for (const base of glob.compiled.bases) {\n const prefix = base === '' ? '' : `${base}/`;\n // The first path that sorts at or after the prefix. `<=` finds the same\n // one, an equivalent mutant: no path read so ends with `/`, so none\n // equals a prefix but `''`, which no glob matches.\n let low = 0;\n let high = paths.length;\n while (low < high) {\n const middle = (low + high) >>> 1;\n if ((paths[middle] as string) < prefix) low = middle + 1;\n else high = middle;\n }\n for (let place = low; place < paths.length && (paths[place] as string).startsWith(prefix); place += 1) {\n yield* positions.get(paths[place] as string) as readonly number[];\n }\n }\n}\n\n/**\n * The files of a list a glob matches, in the list's order: those\n * {@link matchGlob} matches, asked only of the files below one of the glob's\n * bases.\n */\nexport function filesMatching(glob: Glob, files: readonly string[]): string[] {\n const index = indexOf(files);\n const matched = new Set<number>();\n for (const position of candidates(index, glob)) {\n if (matchGlob(glob, files[position] as string)) matched.add(position);\n }\n return [...matched].sort((a, b) => a - b).map((position) => files[position] as string);\n}\n\n/** Whether a glob matches any file of a list, asked only of the files below one of its bases. */\nexport function matchesAny(glob: Glob, files: readonly string[]): boolean {\n const index = indexOf(files);\n for (const position of candidates(index, glob)) {\n if (matchGlob(glob, files[position] as string)) return true;\n }\n return false;\n}\n\n/**\n * A shortest path every glob in `include` matches and none in `exclude` does,\n * `none` as a proof that there is no such path, or `undecided` when the search\n * met its budget first.\n */\nexport function globWitness(include: readonly Glob[], exclude: readonly Glob[] = [], budget: number = WITNESS_BUDGET): Witness {\n return coreWitness(\n include.map((g) => g.compiled),\n exclude.map((g) => g.compiled),\n budget,\n );\n}\n\n/** Whether every path `inner` matches is matched by one of `outer`, or `undecided`. */\nexport function globCovers(outer: readonly Glob[], inner: Glob, budget: number = WITNESS_BUDGET): boolean | 'undecided' {\n return coreCovers(\n outer.map((g) => g.compiled),\n inner.compiled,\n budget,\n );\n}\n\n/**\n * A path both globs match, or `null` when there is none: the 0.1 interface,\n * kept for the library's callers. It cannot say `undecided`, so a search that\n * meets its budget throws; {@link globWitness} answers in three ways.\n */\nexport function intersectGlobs(a: Glob, b: Glob, budget: number = WITNESS_BUDGET): string | null {\n const witness = globWitness([a, b], [], budget);\n if (witness.kind === 'undecided') {\n throw new Error(`whether \"${a.source}\" and \"${b.source}\" meet is undecided within the search's budget`);\n }\n return witness.kind === 'found' ? witness.path : null;\n}\n\n/**\n * The directories a walk must enter to find every match, one per brace\n * alternative: the leading literal segments, or a literal file's directory.\n * `''` for an alternative that can match at the root.\n */\nexport function globBases(glob: Glob): readonly string[] {\n return glob.compiled.bases;\n}\n\n/** The first of {@link globBases}: the 0.1 interface, kept for the library's callers. */\nexport function globBase(glob: Glob): string {\n // One base per alternative, and a pattern has at least one.\n return glob.compiled.bases[0] as string;\n}\n\n/** A brace alternative as its pattern writes it, and the index in the pattern where it ends. */\nexport interface WrittenAlternative {\n readonly written: string;\n readonly end: number;\n}\n\n/**\n * Each alternative of a pattern as written, in the order the core expands\n * them, and where each ends, when a `/` written there ends that alternative\n * and no other: the pattern itself when it has no braces, or the alternatives\n * of braces that end the pattern and whose own braces end theirs -\n * `lib/{util,new}`, `{a,b/{c,d}}`. `null` when more of the pattern follows\n * braces, `{a,b}/new`, since every alternative they give ends where the\n * pattern does; and for a pattern with a class, which may hold a brace or a\n * comma of its own and which this does not read.\n *\n * spec-core expands braces and keeps nothing of where an alternative was\n * written, and a note's advice is built from what was written, as the core\n * builds its own. So this reads braces as the expansion does, for a pattern\n * that parses: a `\\` escapes the next character, and a `}` with no `{` open\n * is a literal.\n */\nexport function writtenAlternatives(pattern: string): WrittenAlternative[] | null {\n let depth = 0;\n let open = 0;\n const stops: number[] = [];\n for (let i = 0; i < pattern.length; i += 1) {\n const ch = pattern.charAt(i);\n if (ch === '\\\\') {\n i += 1;\n } else if (ch === '[') {\n return null;\n } else if (ch === '{') {\n if (depth === 0) open = i;\n depth += 1;\n } else if (ch === ',' && depth === 1) {\n stops.push(i);\n } else if (ch === '}' && depth > 0) {\n depth -= 1;\n if (depth === 0) return i === pattern.length - 1 ? optionsOf(pattern, open, [...stops, i]) : null;\n }\n }\n return [{ written: pattern, end: pattern.length }];\n}\n\n/** The alternatives of the braces opened at `open`, each option ending at one of `stops`. */\nfunction optionsOf(pattern: string, open: number, stops: readonly number[]): WrittenAlternative[] | null {\n const prefix = pattern.slice(0, open);\n const alternatives: WrittenAlternative[] = [];\n let start = open + 1;\n for (const stop of stops) {\n const inner = writtenAlternatives(pattern.slice(start, stop));\n if (inner === null) return null;\n for (const { written, end } of inner) alternatives.push({ written: prefix + written, end: start + end });\n start = stop + 1;\n }\n return alternatives;\n}\n\n/** A name with an extension, `login.ts` or `.eslintrc.json`, and not a dot-name such as `.github`. */\nexport function hasExtension(name: string): boolean {\n return /.\\.[^.]+$/.test(name);\n}\n\n/** The files a tree holds, and every directory above one. */\nexport interface Tree {\n readonly files: ReadonlySet<string>;\n readonly directories: ReadonlySet<string>;\n}\n\nconst trees = new WeakMap<readonly string[], Tree>();\n\n/** The tree a list of files describes. Built once per list, which every brief of a run shares. */\nexport function treeOf(files: readonly string[]): Tree {\n const known = trees.get(files);\n if (known !== undefined) return known;\n const directories = new Set<string>();\n for (const file of files) {\n for (let slash = file.indexOf('/'); slash !== -1; slash = file.indexOf('/', slash + 1)) directories.add(file.slice(0, slash));\n }\n const tree = { files: new Set(files), directories };\n trees.set(files, tree);\n return tree;\n}\n\n/** What the tree holds at a path: a file, a directory, or nothing. */\nexport function held(tree: Tree, path: string): 'file' | 'directory' | null {\n if (tree.files.has(path)) return 'file';\n return tree.directories.has(path) ? 'directory' : null;\n}\n\n/**\n * How a tree reads a literal path: a directory it holds is a directory, and\n * anything else is a file. Without a tree nothing is known to be a directory,\n * so every literal is a file; a trailing `/` says otherwise, and never reaches\n * this question.\n */\nexport function readingIn(files: readonly string[] | null): (path: string) => LiteralReading {\n if (files === null) return () => 'file';\n const tree = treeOf(files);\n return (path) => (held(tree, path) === 'directory' ? 'directory' : 'file');\n}\n"]}
package/dist/rules.js CHANGED
@@ -12,7 +12,7 @@ import { statusWords } from './config.js';
12
12
  import { cycleSubject, dependencyCycles, duplicateIds, idKey, resolveDependency } from './corpus.js';
13
13
  import { findEntry } from './frontmatter.js';
14
14
  import { integrityOf } from './integrity.js';
15
- import { hasExtension, held, isGlobSyntax, matchGlob, parseGlob, readingIn, treeOf, WITNESS_BUDGET, writtenAlternatives } from './glob.js';
15
+ import { hasExtension, held, isGlobSyntax, matchesAny, parseGlob, readingIn, treeOf, WITNESS_BUDGET, writtenAlternatives } from './glob.js';
16
16
  import { hasContent } from './markdown.js';
17
17
  import { closest } from './schema.js';
18
18
  import { contradictions, patternsOf, scopeOf } from './scope.js';
@@ -530,7 +530,7 @@ export const RULES = [
530
530
  const reading = readingIn(repoFiles);
531
531
  return SCOPE_FIELDS.flatMap((field) => patternsOf(brief[field], reading)
532
532
  // A literal the tree does not hold is literal-read-as-file's finding.
533
- .filter((p) => unheldLiterals(p.glob, repoFiles).length === 0 && !repoFiles.some((file) => matchGlob(p.glob, file)))
533
+ .filter((p) => unheldLiterals(p.glob, repoFiles).length === 0 && !matchesAny(p.glob, repoFiles))
534
534
  .map((p) => ({
535
535
  line: at(lineOfField(brief, field)),
536
536
  message: `"${p.pattern}" in ${field} matches no file in the tree`,
package/dist/rules.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The built-in rules. Each is a pure function of one brief and the corpus\n * around it, and returns what it found with 1-based lines.\n *\n * Structure is checked on live briefs only. An archived brief is a frozen\n * record of the tree before a round, and holding it to today's schema would\n * ask somebody to edit what must not be edited; the rules that do reach the\n * archive are about identity and the freeze itself.\n */\n\nimport { BUILT_IN_FIELDS, type Brief, knownFields, lineOfField } from './brief.js';\nimport { type Config, type SectionRule, statusWords } from './config.js';\nimport { type Corpus, cycleSubject, dependencyCycles, duplicateIds, idKey, resolveDependency } from './corpus.js';\nimport { findEntry } from './frontmatter.js';\nimport { integrityOf } from './integrity.js';\nimport { type Glob, hasExtension, held, isGlobSyntax, matchGlob, parseGlob, readingIn, treeOf, WITNESS_BUDGET, writtenAlternatives } from './glob.js';\nimport { hasContent, type Section } from './markdown.js';\nimport { closest } from './schema.js';\nimport { contradictions, patternsOf, scopeOf, type ScopePattern } from './scope.js';\nimport { inWords, labelMatches } from './text.js';\nimport { namesAnEvent } from './trigger.js';\nimport type { Severity, SeveritySetting } from './types.js';\n\nexport interface RuleResult {\n /** 1-based. */\n readonly line: number;\n readonly message: string;\n readonly hint?: string | undefined;\n /** Lower than the rule's severity for this one finding, as a draft's unwritten sections are. */\n readonly severity?: Severity | undefined;\n /** What the finding is about, where the rule can report more than one thing in a brief: a finding's `subject`. */\n readonly subject?: string | undefined;\n}\n\nexport interface RuleContext {\n readonly brief: Brief;\n readonly corpus: Corpus;\n readonly config: Config;\n /** The files git sees, or every file without git; `null` when unknown. A rule that needs them stays quiet without them. */\n readonly repoFiles: readonly string[] | null;\n /** Analyses computed once per run and shared by every brief. */\n readonly shared: SharedAnalysis;\n /** A plugin's options from the configuration. */\n readonly options?: unknown;\n}\n\n/** What a rule is called, how loud it is by default, and what it checks. */\nexport interface RuleInfo {\n readonly id: string;\n readonly severity: SeveritySetting;\n readonly description: string;\n}\n\nexport interface Rule extends RuleInfo {\n check(context: RuleContext): readonly RuleResult[] | Promise<readonly RuleResult[]>;\n}\n\nexport interface SharedAnalysis {\n readonly cycles: readonly (readonly Brief[])[];\n readonly duplicates: ReadonlyMap<string, readonly Brief[]>;\n}\n\nexport function analyse(corpus: Corpus): SharedAnalysis {\n return { cycles: dependencyCycles(corpus), duplicates: duplicateIds(corpus) };\n}\n\nconst at = (line0: number): number => line0 + 1;\n\n/** The sections a brief must carry: the configured ones, then its type's. */\nexport function sectionRules(brief: Brief, config: Config): SectionRule[] {\n const typed = brief.type === null ? [] : (config.types[brief.type] ?? []);\n return [...config.sections, ...typed];\n}\n\n/** The headings that fill a section rule. */\nexport function sectionsFilling(brief: Brief, rule: SectionRule): Section[] {\n const names = [rule.name, ...rule.aliases];\n return brief.sections.filter((s) => names.some((name) => labelMatches(s.heading.text, name)));\n}\n\n/** A section's own lines that carry content: comments dropped, sub-headings not counted. */\nfunction contentLines(brief: Brief, section: Section): number[] {\n const headingLines = new Set(brief.scan.headings.map((h) => h.line));\n const lines: number[] = [];\n for (let i = section.heading.line + 1; i < section.end; i += 1) {\n if (!headingLines.has(i) && hasContent(brief.scan.prose[i] as string)) lines.push(i);\n }\n return lines;\n}\n\n/** Whether `text` is the placeholder `word`, alone or with the stops that end a sentence: `TBD`, `TBD.`, `TBD?!`. */\nfunction onlyPlaceholder(text: string, word: string): boolean {\n return text.startsWith(word) && /^[.!?;\\u2026]*$/.test(text.slice(word.length));\n}\n\nfunction isPlaceholder(line: string, placeholders: readonly string[]): boolean {\n const text = line\n .replace(/^\\s*(?:[-*+]|\\d{1,9}[.)])\\s+/, '')\n .replace(/^\\[[ xX]\\]\\s*/, '')\n .replace(/[*_]/g, '')\n .trim();\n if (text === '') return true;\n const lower = text.toLowerCase();\n return placeholders.some((p) => {\n const word = p.toLowerCase();\n // A space, a colon or an em dash, after a stop or not, introduces a note on\n // the placeholder: `TBD: ask the vendor`, `TBD. Ask the vendor.`, `TBD - later`.\n // A stop or a hyphen that goes on into a word, `TODO.md`, `TODO-driven`,\n // is part of that word. An em dash joins no words, so none is made across it.\n return lower.startsWith(word) && /^[.!?;\\u2026\\-]*(?:$|[\\s:\\u2014])/.test(lower.slice(word.length));\n });\n}\n\n/** Completeness findings on a draft are reminders, not failures. */\nfunction leniency(brief: Brief): Severity | undefined {\n return brief.status === 'draft' ? 'warning' : undefined;\n}\n\nfunction live(check: (context: RuleContext) => RuleResult[]): (context: RuleContext) => RuleResult[] {\n return (context) => (context.brief.phase === 'live' ? check(context) : []);\n}\n\nconst SCOPE_FIELDS = ['affectedFiles', 'protectedFiles'] as const;\n\nconst quoted = (items: readonly string[]): string => inWords(items.map((item) => `\"${item}\"`));\n\n/**\n * The paths a pattern names with no glob syntax that the tree does not hold\n * and whose names carry no extension. The tree reads each as a file, and the\n * spelling cannot say whether a directory was meant.\n */\nexport function unheldLiterals(glob: Glob, files: readonly string[]): string[] {\n const tree = treeOf(files);\n return glob.literals\n .map((literal) => literal.path)\n .filter((path) => held(tree, path) === null && !hasExtension(path.slice(path.lastIndexOf('/') + 1)));\n}\n\n/**\n * What to write for a directory where a pattern names paths the tree reads as\n * files, built from the pattern as written, as spec-core builds its own\n * advice: the pattern with a `/` ending each alternative that names one, since\n * a trailing `/` inside braces says directory as it does alone, or each such\n * alternative in an entry of its own (ADR-0005, amended 2026-09-29). Where\n * more of the pattern follows braces, `{a,b}/new`, no `/` written inside them\n * ends one alternative alone, so an entry of its own is the advice; and an\n * alternative the reader refuses as an entry, one opening with `!`, is left as\n * written. The reader trims every list item, so the pattern is as meant.\n */\nfunction directoryAdvice(pattern: string, paths: readonly string[]): string {\n const alternatives = writtenAlternatives(pattern) ?? [];\n const named = alternatives.filter(({ written }) => {\n const parsed = parseGlob(written);\n return parsed.ok && parsed.glob.literals.some((literal) => paths.includes(literal.path));\n });\n const entries = (named.length === 0 ? paths : named.map(({ written }) => written)).map((entry) => `${entry}/`);\n const one = entries.length === 1;\n const kind = one ? 'a directory' : 'directories';\n const own = one ? 'an entry of its own' : 'entries of their own';\n if (named.length === 0) return `write ${quoted(entries)} for ${kind}, in ${own}`;\n if (alternatives.length === 1) return `write ${quoted(entries)} for ${kind}`;\n let slashed = '';\n let from = 0;\n for (const { end } of named) {\n slashed += `${pattern.slice(from, end)}/`;\n from = end;\n }\n return `write \"${slashed}${pattern.slice(from)}\" for ${kind}, or ${quoted(entries)} in ${own}`;\n}\n\n/**\n * Affected patterns a brief's own protections cover entirely: one error for\n * all of them, and a warning for those the search could not decide.\n */\nexport function scopeContradiction(brief: Brief, repoFiles: readonly string[] | null, budget: number = WITNESS_BUDGET): RuleResult[] {\n const { covered, undecided } = contradictions(scopeOf(brief, readingIn(repoFiles)), budget);\n const line = at(lineOfField(brief, 'protectedFiles'));\n const results: RuleResult[] = [];\n if (covered.length > 0) {\n const one = covered.length === 1;\n results.push({\n line,\n message: `${quoted(covered)} in affectedFiles ${one ? 'is' : 'are'} entirely protected, so nothing of ${one ? 'it' : 'them'} is writable`,\n hint: `drop ${one ? 'it' : 'them'} from affectedFiles, or narrow protectedFiles so that some of ${one ? 'it' : 'each'} is writable`,\n subject: 'covered',\n });\n }\n if (undecided.length > 0) {\n results.push({\n line,\n message: `whether ${quoted(undecided)} in affectedFiles ${undecided.length === 1 ? 'is' : 'are'} entirely protected is undecided: the search met its budget`,\n hint: 'simplify the patterns until the question can be answered',\n severity: 'warning',\n subject: 'undecided',\n });\n }\n return results;\n}\n\nexport const RULES: readonly Rule[] = [\n {\n id: 'front-matter',\n severity: 'error',\n description: 'Front matter parses, with no duplicate keys and no YAML beyond the supported subset.',\n check: ({ brief }) =>\n (brief.frontMatter?.problems ?? []).map((p) => ({\n line: at(p.line),\n message: p.message,\n hint: 'front matter is flat \"key: value\" lines, with lists as [a, b] or \"- item\" lines',\n })),\n },\n {\n id: 'field',\n severity: 'error',\n description: 'Fields spec-brief reads hold values of the right shape.',\n check: ({ brief }) => brief.problems.map((p) => ({ line: at(p.line), message: p.message, subject: p.field })),\n },\n {\n id: 'unknown-field',\n severity: 'warning',\n description: 'Front-matter keys are ones spec-brief or the configuration knows.',\n check: ({ brief, config }) => {\n const known = knownFields(config);\n return (brief.frontMatter?.entries ?? [])\n .filter((entry) => !known.has(entry.name))\n .map((entry) => {\n const guess = closest(entry.key, BUILT_IN_FIELDS);\n return {\n line: at(entry.line),\n message: `\"${entry.key}\" is not a key spec-brief knows`,\n subject: entry.key,\n hint:\n guess === undefined\n ? `if the repository uses it, list it under \"fields\" in the configuration`\n : `did you mean \"${guess}\"? If not, list \"${entry.key}\" under \"fields\" in the configuration`,\n };\n });\n },\n },\n {\n id: 'status',\n severity: 'error',\n description: 'The status agrees with where the brief lives.',\n check: ({ brief, config }) => {\n const field = config.status.field;\n if (field === null) return [];\n const line = at(lineOfField(brief, field));\n const expected = brief.phase === 'archived' ? config.status.archived : config.status.active;\n if (brief.statusWord === null) {\n return [\n {\n line,\n message: `declares no \"${field}\"`,\n hint: `add \"${field}: ${expected}\" to the front matter`,\n },\n ];\n }\n if (brief.status === null) {\n const words = statusWords(config);\n return [\n {\n line,\n message: `\"${brief.statusWord}\" is not a status here`,\n hint: `use one of ${words.map((w) => `\"${w}\"`).join(', ')}`,\n },\n ];\n }\n if (brief.phase === 'live' && brief.status === 'archived') {\n return [\n {\n line,\n message: `is marked \"${brief.statusWord}\" but lives in ${config.briefs}/`,\n hint: `run \"spec-brief archive ${brief.id ?? brief.name}\", which moves it and writes its banner`,\n },\n ];\n }\n if (brief.phase === 'archived' && brief.status !== 'archived') {\n return [\n {\n line,\n message: `lives in ${config.archive}/ but is marked \"${brief.statusWord}\"`,\n hint: `run \"spec-brief unarchive ${brief.id ?? brief.name}\" to reopen it, or set \"${field}: ${config.status.archived}\"`,\n },\n ];\n }\n return [];\n },\n },\n {\n id: 'id',\n severity: 'error',\n description: 'Every brief has an id with no whitespace or slashes in it.',\n check: ({ brief, config }) => {\n if (brief.id === null) {\n return [\n {\n line: 1,\n message: config.id.source === 'frontmatter' ? 'declares no \"id\"' : 'has no id in its file name',\n hint: config.id.source === 'frontmatter' ? 'add \"id: <id>\" to the front matter' : undefined,\n },\n ];\n }\n if (/[\\s/\\\\]/.test(brief.id)) return [{ line: 1, message: `the id \"${brief.id}\" contains whitespace or a slash` }];\n return [];\n },\n },\n {\n id: 'duplicate-id',\n severity: 'error',\n description: 'No two briefs share an id, live or archived.',\n check: ({ brief, shared }) => {\n if (brief.id === null) return [];\n const group = shared.duplicates.get(idKey(brief.id));\n if (group === undefined || group[0] === brief) return [];\n return [\n {\n line: 1,\n message: `the id \"${brief.id}\" is also ${(group[0] as Brief).file}'s`,\n hint: 'ids are allocated once and never reused; give this brief the next free one',\n },\n ];\n },\n },\n {\n id: 'title',\n severity: 'warning',\n description: 'A brief has a title: a \"title\" field or a level-one heading.',\n check: live(({ brief }) =>\n brief.title === null ? [{ line: at(brief.bodyStart), message: 'has no title', hint: 'start the body with \"# <title>\"' }] : [],\n ),\n },\n {\n id: 'unknown-type',\n severity: 'error',\n description: 'A declared type is one the configuration defines.',\n check: live(({ brief, config }) => {\n if (brief.type === null || config.types[brief.type] !== undefined) return [];\n const names = Object.keys(config.types);\n return [\n {\n line: at(lineOfField(brief, 'type')),\n message: `\"${brief.type}\" is not a brief type here`,\n hint: names.length === 0 ? 'the configuration defines no types' : `use one of ${names.map((n) => `\"${n}\"`).join(', ')}`,\n },\n ];\n }),\n },\n {\n id: 'missing-section',\n severity: 'error',\n description: 'Every required section is present.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config)\n .filter((rule) => !rule.optional && sectionsFilling(brief, rule).length === 0)\n .map((rule) => {\n const heading =\n rule.aliases.length === 0\n ? `add a \"## ${rule.name}\" heading`\n : `add a \"## ${rule.name}\" heading (also accepted: ${rule.aliases.map((a) => `\"${a}\"`).join(', ')})`;\n return {\n line: at(brief.bodyStart),\n message: `has no \"${rule.name}\" section`,\n subject: rule.name,\n hint: rule.hint === undefined ? heading : `${heading}. ${rule.hint}`,\n };\n }),\n ),\n },\n {\n id: 'duplicate-section',\n severity: 'warning',\n description: 'A section appears once.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config).flatMap((rule) =>\n sectionsFilling(brief, rule)\n .slice(1)\n .map((s) => ({ line: at(s.heading.line), message: `a second \"${rule.name}\" section`, hint: 'merge the two', subject: rule.name })),\n ),\n ),\n },\n {\n id: 'empty-section',\n severity: 'error',\n description: 'A section carries content; a comment alone is not content.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config).flatMap((rule) =>\n sectionsFilling(brief, rule)\n .slice(0, 1)\n .filter((s) => contentLines(brief, s).length === 0)\n .map((s) => ({\n line: at(s.heading.line),\n message: `the \"${rule.name}\" section is empty`,\n subject: rule.name,\n hint: rule.hint ?? 'write it; a comment alone is not content',\n severity: leniency(brief),\n })),\n ),\n ),\n },\n {\n id: 'placeholder',\n severity: 'error',\n description: 'A section says something: not only \"TBD\", \"TODO\" or an empty box.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config).flatMap((rule) =>\n sectionsFilling(brief, rule)\n .slice(0, 1)\n .filter((s) => {\n const lines = contentLines(brief, s);\n return lines.length > 0 && lines.every((i) => isPlaceholder(brief.scan.prose[i] as string, config.placeholders));\n })\n .map((s) => ({\n line: at(s.heading.line),\n message: `the \"${rule.name}\" section holds only a placeholder`,\n subject: rule.name,\n hint: rule.hint ?? 'replace the placeholder with what the section must say',\n severity: leniency(brief),\n })),\n ),\n ),\n },\n {\n id: 'missing-checklist',\n severity: 'error',\n description: 'A checklist section holds at least one task item.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config)\n .filter((rule) => rule.checklist)\n .flatMap((rule) =>\n sectionsFilling(brief, rule)\n .slice(0, 1)\n .filter((s) => !brief.tasks.some((t) => t.line > s.heading.line && t.line < s.end))\n .map((s) => ({\n line: at(s.heading.line),\n message: `the \"${rule.name}\" section has no \"- [ ]\" items`,\n subject: rule.name,\n hint: 'write each check as a task item, so it has a state that can be closed',\n severity: leniency(brief),\n })),\n ),\n ),\n },\n {\n id: 'must-contain',\n severity: 'error',\n description: 'A section contains the text the configuration requires of it.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config).flatMap((rule) => {\n const section = sectionsFilling(brief, rule)[0];\n if (section === undefined) return [];\n const body = brief.scan.prose.slice(section.heading.line + 1, section.end).join('\\n');\n return rule.mustContain\n .filter((text) => !body.includes(text))\n .map((text) => ({ line: at(section.heading.line), message: `the \"${rule.name}\" section must contain \"${text}\"`, subject: `${rule.name}: \"${text}\"` }));\n }),\n ),\n },\n {\n id: 'section-order',\n severity: 'error',\n description: 'Sections appear in the configured order, when the configuration asks for one.',\n check: live(({ brief, config }) => {\n if (!config.sectionOrder) return [];\n const placed = sectionRules(brief, config)\n .map((rule) => ({ rule, section: sectionsFilling(brief, rule)[0] }))\n .filter((p): p is { rule: SectionRule; section: Section } => p.section !== undefined);\n for (let i = 1; i < placed.length; i += 1) {\n const before = placed[i - 1] as { rule: SectionRule; section: Section };\n const current = placed[i] as { rule: SectionRule; section: Section };\n if (current.section.heading.line < before.section.heading.line) {\n return [\n {\n line: at(current.section.heading.line),\n message: `\"${current.rule.name}\" comes before \"${before.rule.name}\"`,\n hint: `the order is ${sectionRules(brief, config)\n .map((r) => r.name)\n .join(', ')}`,\n },\n ];\n }\n }\n return [];\n }),\n },\n {\n id: 'dependency',\n severity: 'error',\n description: 'Every dependency names another brief that exists.',\n check: live(({ brief, corpus }) =>\n brief.dependsOn.flatMap((dependency) => {\n const line = at(lineOfField(brief, 'dependsOn'));\n if (brief.id !== null && idKey(dependency) === idKey(brief.id)) {\n return [{ line, message: 'depends on itself', subject: dependency }];\n }\n if (resolveDependency(corpus, dependency) === undefined) {\n return [{ line, message: `depends on \"${dependency}\", which is not a brief here`, subject: dependency }];\n }\n return [];\n }),\n ),\n },\n {\n id: 'dependency-cycle',\n severity: 'error',\n description: 'Dependencies between live briefs form no cycle.',\n check: live(({ brief, shared }) =>\n shared.cycles\n .filter((cycle) => cycle[0] === brief)\n .map((cycle) => ({\n line: at(lineOfField(brief, 'dependsOn')),\n message: `dependencies form a cycle: ${cycle.map((b) => b.id ?? b.name).join(' -> ')}`,\n subject: cycleSubject(cycle),\n hint: 'a cycle can never become ready; remove the dependency that is not real',\n })),\n ),\n },\n {\n id: 'wave-order',\n severity: 'error',\n description: 'A dependency that is still live runs in an earlier wave.',\n check: live(({ brief, corpus }) => {\n const wave = brief.wave;\n if (wave === null) return [];\n return brief.dependsOn.flatMap((dependency) => {\n const target = resolveDependency(corpus, dependency);\n // A self-dependency is reported once, by the dependency rule.\n if (target === undefined || target === brief || target.phase !== 'live' || target.wave === null || target.wave < wave) return [];\n return [\n {\n line: at(lineOfField(brief, 'dependsOn')),\n message: `depends on ${target.id ?? target.name}, which is in wave ${target.wave}, not before wave ${wave}`,\n subject: target.id ?? target.name,\n hint: `move this brief to a wave after ${target.wave}, or ${target.id ?? target.name} to one before ${wave}`,\n },\n ];\n });\n }),\n },\n {\n id: 'deferral-trigger',\n severity: 'error',\n description: 'A deferred brief names in \"trigger\" the observable event that brings it back, not a date.',\n check: live(({ brief, config }) => {\n // A trigger of the wrong shape is the field rule's finding.\n if (brief.status !== 'deferred' || brief.problems.some((p) => p.field === 'trigger')) return [];\n const example = 'such as \"when the second tenant signs\" or \"when p95 exceeds 200 ms\"';\n const trigger = brief.trigger?.trim() ?? '';\n if (trigger === '') {\n const declared = findEntry(brief.frontMatter, 'trigger') !== undefined;\n return [\n {\n line: at(lineOfField(brief, declared ? 'trigger' : (config.status.field as string))),\n message: 'is deferred and names no \"trigger\"',\n hint: `add \"trigger: <the event that brings it back>\", ${example}`,\n },\n ];\n }\n const line = at(lineOfField(brief, 'trigger'));\n const hint = `name what must happen before the work resumes, ${example}`;\n // A note after a placeholder is the event itself: `TBD: when the vendor answers`.\n if (config.placeholders.some((p) => onlyPlaceholder(trigger.toLowerCase(), p.toLowerCase()))) {\n return [{ line, message: `the trigger \"${trigger}\" is a placeholder, not an event`, hint }];\n }\n if (!namesAnEvent(trigger)) {\n return [{ line, message: `the trigger \"${trigger}\" is a date or a time, not an event`, hint: `${hint}; a date arrives whether or not the reason for the work has` }];\n }\n return [];\n }),\n },\n {\n id: 'glob',\n severity: 'error',\n description: 'Every scope pattern is a glob spec-brief can read.',\n check: live(({ brief }) =>\n SCOPE_FIELDS.flatMap((field) =>\n brief[field].flatMap((pattern) => {\n const parsed = parseGlob(pattern);\n if (parsed.ok) return [];\n return [\n {\n line: at(lineOfField(brief, field)),\n message: `\"${pattern}\" in ${field}: ${parsed.error}`,\n subject: `${field}: ${pattern}`,\n hint: 'a scope is a glob relative to the repository root: \"src/auth/\", \"src/**/*.ts\", \"docs/{a,b}.md\"',\n },\n ];\n }),\n ),\n ),\n },\n {\n id: 'scope-contradiction',\n severity: 'error',\n description: 'Something of every affected pattern is writable: no pattern lies wholly inside protectedFiles.',\n check: live(({ brief, repoFiles }) => scopeContradiction(brief, repoFiles)),\n },\n {\n id: 'glob-matches-nothing',\n severity: 'note',\n description: 'A scope pattern matches at least one file in the tree.',\n check: live(({ brief, repoFiles }) => {\n if (repoFiles === null) return [];\n const reading = readingIn(repoFiles);\n return SCOPE_FIELDS.flatMap((field) =>\n patternsOf(brief[field], reading)\n // A literal the tree does not hold is literal-read-as-file's finding.\n .filter((p) => unheldLiterals(p.glob, repoFiles).length === 0 && !repoFiles.some((file) => matchGlob(p.glob, file)))\n .map((p) => ({\n line: at(lineOfField(brief, field)),\n message: `\"${p.pattern}\" in ${field} matches no file in the tree`,\n subject: `${field}: ${p.pattern}`,\n hint: 'expected when the round creates it; otherwise check the spelling',\n })),\n );\n }),\n },\n {\n id: 'literal-read-as-file',\n severity: 'note',\n description: 'A path with no glob syntax that the tree does not hold, and whose name has no extension, says whether it is a directory.',\n check: live(({ brief, repoFiles }) => {\n if (repoFiles === null) return [];\n const reading = readingIn(repoFiles);\n return SCOPE_FIELDS.flatMap((field) =>\n patternsOf(brief[field], reading).flatMap(({ pattern, glob }: ScopePattern) => {\n const paths = unheldLiterals(glob, repoFiles);\n if (paths.length === 0) return [];\n const line = at(lineOfField(brief, field));\n const hint = directoryAdvice(pattern, paths);\n const subject = `${field}: ${pattern}`;\n if (!isGlobSyntax(pattern)) {\n return [{ line, message: `\"${pattern}\" in ${field} is not in the tree and is read as a file`, hint, subject }];\n }\n return [\n {\n line,\n message: `\"${pattern}\" in ${field} names ${inWords(paths)}, which ${paths.length === 1 ? 'is' : 'are'} not in the tree and ${paths.length === 1 ? 'is' : 'are'} read as ${paths.length === 1 ? 'a file' : 'files'}`,\n hint,\n subject,\n },\n ];\n }),\n );\n }),\n },\n {\n id: 'archive-freeze',\n severity: 'error',\n description: 'An archived brief has not changed since it was archived.',\n check: ({ brief }) => {\n if (brief.phase !== 'archived' || brief.integrity === null) return [];\n if (integrityOf(brief.text) === brief.integrity) return [];\n return [\n {\n line: at(lineOfField(brief, 'integrity')),\n message: 'has changed since it was archived',\n hint: 'an archived brief is frozen: restore it from git, or unarchive it to reopen the round',\n },\n ];\n },\n },\n];\n\n/**\n * The rules the wave analyses - `matrix` and `schedule` - report under. They\n * are not run per brief, so they carry no check: they exist so configuration\n * can set their severity and reports can describe them.\n */\nexport const COLLISION_RULES: readonly RuleInfo[] = [\n { id: 'collision', severity: 'error', description: 'Briefs in one wave do not write the same file.' },\n {\n id: 'collision-undecided',\n severity: 'warning',\n description: 'Whether two briefs in one wave can write the same file is decided within the search budget.',\n },\n { id: 'unscoped', severity: 'note', description: 'A brief sharing a wave declares the files it writes.' },\n { id: 'shared-directory', severity: 'off', description: 'Briefs in one wave do not write into the same directory.' },\n {\n id: 'wave-schedule',\n severity: 'error',\n description: 'A brief declares a wave that holds: the one the schedule computes, or one lint and matrix accept, which is a note.',\n },\n];\n\n/**\n * The rules archival reports under beside its refusals. Like the collision\n * rules they carry no check: the planner raises them, and they exist so\n * configuration can set their severity and reports can describe them.\n */\nexport const ARCHIVE_RULES: readonly RuleInfo[] = [\n {\n id: 'scope-unmeasured',\n severity: 'warning',\n description: 'A brief that declares a scope is archived against the changes its round made.',\n },\n {\n id: 'stale-link',\n severity: 'warning',\n description: 'No live brief is left linking to where a moved brief used to be.',\n },\n];\n"]}
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The built-in rules. Each is a pure function of one brief and the corpus\n * around it, and returns what it found with 1-based lines.\n *\n * Structure is checked on live briefs only. An archived brief is a frozen\n * record of the tree before a round, and holding it to today's schema would\n * ask somebody to edit what must not be edited; the rules that do reach the\n * archive are about identity and the freeze itself.\n */\n\nimport { BUILT_IN_FIELDS, type Brief, knownFields, lineOfField } from './brief.js';\nimport { type Config, type SectionRule, statusWords } from './config.js';\nimport { type Corpus, cycleSubject, dependencyCycles, duplicateIds, idKey, resolveDependency } from './corpus.js';\nimport { findEntry } from './frontmatter.js';\nimport { integrityOf } from './integrity.js';\nimport { type Glob, hasExtension, held, isGlobSyntax, matchesAny, parseGlob, readingIn, treeOf, WITNESS_BUDGET, writtenAlternatives } from './glob.js';\nimport { hasContent, type Section } from './markdown.js';\nimport { closest } from './schema.js';\nimport { contradictions, patternsOf, scopeOf, type ScopePattern } from './scope.js';\nimport { inWords, labelMatches } from './text.js';\nimport { namesAnEvent } from './trigger.js';\nimport type { Severity, SeveritySetting } from './types.js';\n\nexport interface RuleResult {\n /** 1-based. */\n readonly line: number;\n readonly message: string;\n readonly hint?: string | undefined;\n /** Lower than the rule's severity for this one finding, as a draft's unwritten sections are. */\n readonly severity?: Severity | undefined;\n /** What the finding is about, where the rule can report more than one thing in a brief: a finding's `subject`. */\n readonly subject?: string | undefined;\n}\n\nexport interface RuleContext {\n readonly brief: Brief;\n readonly corpus: Corpus;\n readonly config: Config;\n /** The files git sees, or every file without git; `null` when unknown. A rule that needs them stays quiet without them. */\n readonly repoFiles: readonly string[] | null;\n /** Analyses computed once per run and shared by every brief. */\n readonly shared: SharedAnalysis;\n /** A plugin's options from the configuration. */\n readonly options?: unknown;\n}\n\n/** What a rule is called, how loud it is by default, and what it checks. */\nexport interface RuleInfo {\n readonly id: string;\n readonly severity: SeveritySetting;\n readonly description: string;\n}\n\nexport interface Rule extends RuleInfo {\n check(context: RuleContext): readonly RuleResult[] | Promise<readonly RuleResult[]>;\n}\n\nexport interface SharedAnalysis {\n readonly cycles: readonly (readonly Brief[])[];\n readonly duplicates: ReadonlyMap<string, readonly Brief[]>;\n}\n\nexport function analyse(corpus: Corpus): SharedAnalysis {\n return { cycles: dependencyCycles(corpus), duplicates: duplicateIds(corpus) };\n}\n\nconst at = (line0: number): number => line0 + 1;\n\n/** The sections a brief must carry: the configured ones, then its type's. */\nexport function sectionRules(brief: Brief, config: Config): SectionRule[] {\n const typed = brief.type === null ? [] : (config.types[brief.type] ?? []);\n return [...config.sections, ...typed];\n}\n\n/** The headings that fill a section rule. */\nexport function sectionsFilling(brief: Brief, rule: SectionRule): Section[] {\n const names = [rule.name, ...rule.aliases];\n return brief.sections.filter((s) => names.some((name) => labelMatches(s.heading.text, name)));\n}\n\n/** A section's own lines that carry content: comments dropped, sub-headings not counted. */\nfunction contentLines(brief: Brief, section: Section): number[] {\n const headingLines = new Set(brief.scan.headings.map((h) => h.line));\n const lines: number[] = [];\n for (let i = section.heading.line + 1; i < section.end; i += 1) {\n if (!headingLines.has(i) && hasContent(brief.scan.prose[i] as string)) lines.push(i);\n }\n return lines;\n}\n\n/** Whether `text` is the placeholder `word`, alone or with the stops that end a sentence: `TBD`, `TBD.`, `TBD?!`. */\nfunction onlyPlaceholder(text: string, word: string): boolean {\n return text.startsWith(word) && /^[.!?;\\u2026]*$/.test(text.slice(word.length));\n}\n\nfunction isPlaceholder(line: string, placeholders: readonly string[]): boolean {\n const text = line\n .replace(/^\\s*(?:[-*+]|\\d{1,9}[.)])\\s+/, '')\n .replace(/^\\[[ xX]\\]\\s*/, '')\n .replace(/[*_]/g, '')\n .trim();\n if (text === '') return true;\n const lower = text.toLowerCase();\n return placeholders.some((p) => {\n const word = p.toLowerCase();\n // A space, a colon or an em dash, after a stop or not, introduces a note on\n // the placeholder: `TBD: ask the vendor`, `TBD. Ask the vendor.`, `TBD - later`.\n // A stop or a hyphen that goes on into a word, `TODO.md`, `TODO-driven`,\n // is part of that word. An em dash joins no words, so none is made across it.\n return lower.startsWith(word) && /^[.!?;\\u2026\\-]*(?:$|[\\s:\\u2014])/.test(lower.slice(word.length));\n });\n}\n\n/** Completeness findings on a draft are reminders, not failures. */\nfunction leniency(brief: Brief): Severity | undefined {\n return brief.status === 'draft' ? 'warning' : undefined;\n}\n\nfunction live(check: (context: RuleContext) => RuleResult[]): (context: RuleContext) => RuleResult[] {\n return (context) => (context.brief.phase === 'live' ? check(context) : []);\n}\n\nconst SCOPE_FIELDS = ['affectedFiles', 'protectedFiles'] as const;\n\nconst quoted = (items: readonly string[]): string => inWords(items.map((item) => `\"${item}\"`));\n\n/**\n * The paths a pattern names with no glob syntax that the tree does not hold\n * and whose names carry no extension. The tree reads each as a file, and the\n * spelling cannot say whether a directory was meant.\n */\nexport function unheldLiterals(glob: Glob, files: readonly string[]): string[] {\n const tree = treeOf(files);\n return glob.literals\n .map((literal) => literal.path)\n .filter((path) => held(tree, path) === null && !hasExtension(path.slice(path.lastIndexOf('/') + 1)));\n}\n\n/**\n * What to write for a directory where a pattern names paths the tree reads as\n * files, built from the pattern as written, as spec-core builds its own\n * advice: the pattern with a `/` ending each alternative that names one, since\n * a trailing `/` inside braces says directory as it does alone, or each such\n * alternative in an entry of its own (ADR-0005, amended 2026-09-29). Where\n * more of the pattern follows braces, `{a,b}/new`, no `/` written inside them\n * ends one alternative alone, so an entry of its own is the advice; and an\n * alternative the reader refuses as an entry, one opening with `!`, is left as\n * written. The reader trims every list item, so the pattern is as meant.\n */\nfunction directoryAdvice(pattern: string, paths: readonly string[]): string {\n const alternatives = writtenAlternatives(pattern) ?? [];\n const named = alternatives.filter(({ written }) => {\n const parsed = parseGlob(written);\n return parsed.ok && parsed.glob.literals.some((literal) => paths.includes(literal.path));\n });\n const entries = (named.length === 0 ? paths : named.map(({ written }) => written)).map((entry) => `${entry}/`);\n const one = entries.length === 1;\n const kind = one ? 'a directory' : 'directories';\n const own = one ? 'an entry of its own' : 'entries of their own';\n if (named.length === 0) return `write ${quoted(entries)} for ${kind}, in ${own}`;\n if (alternatives.length === 1) return `write ${quoted(entries)} for ${kind}`;\n let slashed = '';\n let from = 0;\n for (const { end } of named) {\n slashed += `${pattern.slice(from, end)}/`;\n from = end;\n }\n return `write \"${slashed}${pattern.slice(from)}\" for ${kind}, or ${quoted(entries)} in ${own}`;\n}\n\n/**\n * Affected patterns a brief's own protections cover entirely: one error for\n * all of them, and a warning for those the search could not decide.\n */\nexport function scopeContradiction(brief: Brief, repoFiles: readonly string[] | null, budget: number = WITNESS_BUDGET): RuleResult[] {\n const { covered, undecided } = contradictions(scopeOf(brief, readingIn(repoFiles)), budget);\n const line = at(lineOfField(brief, 'protectedFiles'));\n const results: RuleResult[] = [];\n if (covered.length > 0) {\n const one = covered.length === 1;\n results.push({\n line,\n message: `${quoted(covered)} in affectedFiles ${one ? 'is' : 'are'} entirely protected, so nothing of ${one ? 'it' : 'them'} is writable`,\n hint: `drop ${one ? 'it' : 'them'} from affectedFiles, or narrow protectedFiles so that some of ${one ? 'it' : 'each'} is writable`,\n subject: 'covered',\n });\n }\n if (undecided.length > 0) {\n results.push({\n line,\n message: `whether ${quoted(undecided)} in affectedFiles ${undecided.length === 1 ? 'is' : 'are'} entirely protected is undecided: the search met its budget`,\n hint: 'simplify the patterns until the question can be answered',\n severity: 'warning',\n subject: 'undecided',\n });\n }\n return results;\n}\n\nexport const RULES: readonly Rule[] = [\n {\n id: 'front-matter',\n severity: 'error',\n description: 'Front matter parses, with no duplicate keys and no YAML beyond the supported subset.',\n check: ({ brief }) =>\n (brief.frontMatter?.problems ?? []).map((p) => ({\n line: at(p.line),\n message: p.message,\n hint: 'front matter is flat \"key: value\" lines, with lists as [a, b] or \"- item\" lines',\n })),\n },\n {\n id: 'field',\n severity: 'error',\n description: 'Fields spec-brief reads hold values of the right shape.',\n check: ({ brief }) => brief.problems.map((p) => ({ line: at(p.line), message: p.message, subject: p.field })),\n },\n {\n id: 'unknown-field',\n severity: 'warning',\n description: 'Front-matter keys are ones spec-brief or the configuration knows.',\n check: ({ brief, config }) => {\n const known = knownFields(config);\n return (brief.frontMatter?.entries ?? [])\n .filter((entry) => !known.has(entry.name))\n .map((entry) => {\n const guess = closest(entry.key, BUILT_IN_FIELDS);\n return {\n line: at(entry.line),\n message: `\"${entry.key}\" is not a key spec-brief knows`,\n subject: entry.key,\n hint:\n guess === undefined\n ? `if the repository uses it, list it under \"fields\" in the configuration`\n : `did you mean \"${guess}\"? If not, list \"${entry.key}\" under \"fields\" in the configuration`,\n };\n });\n },\n },\n {\n id: 'status',\n severity: 'error',\n description: 'The status agrees with where the brief lives.',\n check: ({ brief, config }) => {\n const field = config.status.field;\n if (field === null) return [];\n const line = at(lineOfField(brief, field));\n const expected = brief.phase === 'archived' ? config.status.archived : config.status.active;\n if (brief.statusWord === null) {\n return [\n {\n line,\n message: `declares no \"${field}\"`,\n hint: `add \"${field}: ${expected}\" to the front matter`,\n },\n ];\n }\n if (brief.status === null) {\n const words = statusWords(config);\n return [\n {\n line,\n message: `\"${brief.statusWord}\" is not a status here`,\n hint: `use one of ${words.map((w) => `\"${w}\"`).join(', ')}`,\n },\n ];\n }\n if (brief.phase === 'live' && brief.status === 'archived') {\n return [\n {\n line,\n message: `is marked \"${brief.statusWord}\" but lives in ${config.briefs}/`,\n hint: `run \"spec-brief archive ${brief.id ?? brief.name}\", which moves it and writes its banner`,\n },\n ];\n }\n if (brief.phase === 'archived' && brief.status !== 'archived') {\n return [\n {\n line,\n message: `lives in ${config.archive}/ but is marked \"${brief.statusWord}\"`,\n hint: `run \"spec-brief unarchive ${brief.id ?? brief.name}\" to reopen it, or set \"${field}: ${config.status.archived}\"`,\n },\n ];\n }\n return [];\n },\n },\n {\n id: 'id',\n severity: 'error',\n description: 'Every brief has an id with no whitespace or slashes in it.',\n check: ({ brief, config }) => {\n if (brief.id === null) {\n return [\n {\n line: 1,\n message: config.id.source === 'frontmatter' ? 'declares no \"id\"' : 'has no id in its file name',\n hint: config.id.source === 'frontmatter' ? 'add \"id: <id>\" to the front matter' : undefined,\n },\n ];\n }\n if (/[\\s/\\\\]/.test(brief.id)) return [{ line: 1, message: `the id \"${brief.id}\" contains whitespace or a slash` }];\n return [];\n },\n },\n {\n id: 'duplicate-id',\n severity: 'error',\n description: 'No two briefs share an id, live or archived.',\n check: ({ brief, shared }) => {\n if (brief.id === null) return [];\n const group = shared.duplicates.get(idKey(brief.id));\n if (group === undefined || group[0] === brief) return [];\n return [\n {\n line: 1,\n message: `the id \"${brief.id}\" is also ${(group[0] as Brief).file}'s`,\n hint: 'ids are allocated once and never reused; give this brief the next free one',\n },\n ];\n },\n },\n {\n id: 'title',\n severity: 'warning',\n description: 'A brief has a title: a \"title\" field or a level-one heading.',\n check: live(({ brief }) =>\n brief.title === null ? [{ line: at(brief.bodyStart), message: 'has no title', hint: 'start the body with \"# <title>\"' }] : [],\n ),\n },\n {\n id: 'unknown-type',\n severity: 'error',\n description: 'A declared type is one the configuration defines.',\n check: live(({ brief, config }) => {\n if (brief.type === null || config.types[brief.type] !== undefined) return [];\n const names = Object.keys(config.types);\n return [\n {\n line: at(lineOfField(brief, 'type')),\n message: `\"${brief.type}\" is not a brief type here`,\n hint: names.length === 0 ? 'the configuration defines no types' : `use one of ${names.map((n) => `\"${n}\"`).join(', ')}`,\n },\n ];\n }),\n },\n {\n id: 'missing-section',\n severity: 'error',\n description: 'Every required section is present.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config)\n .filter((rule) => !rule.optional && sectionsFilling(brief, rule).length === 0)\n .map((rule) => {\n const heading =\n rule.aliases.length === 0\n ? `add a \"## ${rule.name}\" heading`\n : `add a \"## ${rule.name}\" heading (also accepted: ${rule.aliases.map((a) => `\"${a}\"`).join(', ')})`;\n return {\n line: at(brief.bodyStart),\n message: `has no \"${rule.name}\" section`,\n subject: rule.name,\n hint: rule.hint === undefined ? heading : `${heading}. ${rule.hint}`,\n };\n }),\n ),\n },\n {\n id: 'duplicate-section',\n severity: 'warning',\n description: 'A section appears once.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config).flatMap((rule) =>\n sectionsFilling(brief, rule)\n .slice(1)\n .map((s) => ({ line: at(s.heading.line), message: `a second \"${rule.name}\" section`, hint: 'merge the two', subject: rule.name })),\n ),\n ),\n },\n {\n id: 'empty-section',\n severity: 'error',\n description: 'A section carries content; a comment alone is not content.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config).flatMap((rule) =>\n sectionsFilling(brief, rule)\n .slice(0, 1)\n .filter((s) => contentLines(brief, s).length === 0)\n .map((s) => ({\n line: at(s.heading.line),\n message: `the \"${rule.name}\" section is empty`,\n subject: rule.name,\n hint: rule.hint ?? 'write it; a comment alone is not content',\n severity: leniency(brief),\n })),\n ),\n ),\n },\n {\n id: 'placeholder',\n severity: 'error',\n description: 'A section says something: not only \"TBD\", \"TODO\" or an empty box.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config).flatMap((rule) =>\n sectionsFilling(brief, rule)\n .slice(0, 1)\n .filter((s) => {\n const lines = contentLines(brief, s);\n return lines.length > 0 && lines.every((i) => isPlaceholder(brief.scan.prose[i] as string, config.placeholders));\n })\n .map((s) => ({\n line: at(s.heading.line),\n message: `the \"${rule.name}\" section holds only a placeholder`,\n subject: rule.name,\n hint: rule.hint ?? 'replace the placeholder with what the section must say',\n severity: leniency(brief),\n })),\n ),\n ),\n },\n {\n id: 'missing-checklist',\n severity: 'error',\n description: 'A checklist section holds at least one task item.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config)\n .filter((rule) => rule.checklist)\n .flatMap((rule) =>\n sectionsFilling(brief, rule)\n .slice(0, 1)\n .filter((s) => !brief.tasks.some((t) => t.line > s.heading.line && t.line < s.end))\n .map((s) => ({\n line: at(s.heading.line),\n message: `the \"${rule.name}\" section has no \"- [ ]\" items`,\n subject: rule.name,\n hint: 'write each check as a task item, so it has a state that can be closed',\n severity: leniency(brief),\n })),\n ),\n ),\n },\n {\n id: 'must-contain',\n severity: 'error',\n description: 'A section contains the text the configuration requires of it.',\n check: live(({ brief, config }) =>\n sectionRules(brief, config).flatMap((rule) => {\n const section = sectionsFilling(brief, rule)[0];\n if (section === undefined) return [];\n const body = brief.scan.prose.slice(section.heading.line + 1, section.end).join('\\n');\n return rule.mustContain\n .filter((text) => !body.includes(text))\n .map((text) => ({ line: at(section.heading.line), message: `the \"${rule.name}\" section must contain \"${text}\"`, subject: `${rule.name}: \"${text}\"` }));\n }),\n ),\n },\n {\n id: 'section-order',\n severity: 'error',\n description: 'Sections appear in the configured order, when the configuration asks for one.',\n check: live(({ brief, config }) => {\n if (!config.sectionOrder) return [];\n const placed = sectionRules(brief, config)\n .map((rule) => ({ rule, section: sectionsFilling(brief, rule)[0] }))\n .filter((p): p is { rule: SectionRule; section: Section } => p.section !== undefined);\n for (let i = 1; i < placed.length; i += 1) {\n const before = placed[i - 1] as { rule: SectionRule; section: Section };\n const current = placed[i] as { rule: SectionRule; section: Section };\n if (current.section.heading.line < before.section.heading.line) {\n return [\n {\n line: at(current.section.heading.line),\n message: `\"${current.rule.name}\" comes before \"${before.rule.name}\"`,\n hint: `the order is ${sectionRules(brief, config)\n .map((r) => r.name)\n .join(', ')}`,\n },\n ];\n }\n }\n return [];\n }),\n },\n {\n id: 'dependency',\n severity: 'error',\n description: 'Every dependency names another brief that exists.',\n check: live(({ brief, corpus }) =>\n brief.dependsOn.flatMap((dependency) => {\n const line = at(lineOfField(brief, 'dependsOn'));\n if (brief.id !== null && idKey(dependency) === idKey(brief.id)) {\n return [{ line, message: 'depends on itself', subject: dependency }];\n }\n if (resolveDependency(corpus, dependency) === undefined) {\n return [{ line, message: `depends on \"${dependency}\", which is not a brief here`, subject: dependency }];\n }\n return [];\n }),\n ),\n },\n {\n id: 'dependency-cycle',\n severity: 'error',\n description: 'Dependencies between live briefs form no cycle.',\n check: live(({ brief, shared }) =>\n shared.cycles\n .filter((cycle) => cycle[0] === brief)\n .map((cycle) => ({\n line: at(lineOfField(brief, 'dependsOn')),\n message: `dependencies form a cycle: ${cycle.map((b) => b.id ?? b.name).join(' -> ')}`,\n subject: cycleSubject(cycle),\n hint: 'a cycle can never become ready; remove the dependency that is not real',\n })),\n ),\n },\n {\n id: 'wave-order',\n severity: 'error',\n description: 'A dependency that is still live runs in an earlier wave.',\n check: live(({ brief, corpus }) => {\n const wave = brief.wave;\n if (wave === null) return [];\n return brief.dependsOn.flatMap((dependency) => {\n const target = resolveDependency(corpus, dependency);\n // A self-dependency is reported once, by the dependency rule.\n if (target === undefined || target === brief || target.phase !== 'live' || target.wave === null || target.wave < wave) return [];\n return [\n {\n line: at(lineOfField(brief, 'dependsOn')),\n message: `depends on ${target.id ?? target.name}, which is in wave ${target.wave}, not before wave ${wave}`,\n subject: target.id ?? target.name,\n hint: `move this brief to a wave after ${target.wave}, or ${target.id ?? target.name} to one before ${wave}`,\n },\n ];\n });\n }),\n },\n {\n id: 'deferral-trigger',\n severity: 'error',\n description: 'A deferred brief names in \"trigger\" the observable event that brings it back, not a date.',\n check: live(({ brief, config }) => {\n // A trigger of the wrong shape is the field rule's finding.\n if (brief.status !== 'deferred' || brief.problems.some((p) => p.field === 'trigger')) return [];\n const example = 'such as \"when the second tenant signs\" or \"when p95 exceeds 200 ms\"';\n const trigger = brief.trigger?.trim() ?? '';\n if (trigger === '') {\n const declared = findEntry(brief.frontMatter, 'trigger') !== undefined;\n return [\n {\n line: at(lineOfField(brief, declared ? 'trigger' : (config.status.field as string))),\n message: 'is deferred and names no \"trigger\"',\n hint: `add \"trigger: <the event that brings it back>\", ${example}`,\n },\n ];\n }\n const line = at(lineOfField(brief, 'trigger'));\n const hint = `name what must happen before the work resumes, ${example}`;\n // A note after a placeholder is the event itself: `TBD: when the vendor answers`.\n if (config.placeholders.some((p) => onlyPlaceholder(trigger.toLowerCase(), p.toLowerCase()))) {\n return [{ line, message: `the trigger \"${trigger}\" is a placeholder, not an event`, hint }];\n }\n if (!namesAnEvent(trigger)) {\n return [{ line, message: `the trigger \"${trigger}\" is a date or a time, not an event`, hint: `${hint}; a date arrives whether or not the reason for the work has` }];\n }\n return [];\n }),\n },\n {\n id: 'glob',\n severity: 'error',\n description: 'Every scope pattern is a glob spec-brief can read.',\n check: live(({ brief }) =>\n SCOPE_FIELDS.flatMap((field) =>\n brief[field].flatMap((pattern) => {\n const parsed = parseGlob(pattern);\n if (parsed.ok) return [];\n return [\n {\n line: at(lineOfField(brief, field)),\n message: `\"${pattern}\" in ${field}: ${parsed.error}`,\n subject: `${field}: ${pattern}`,\n hint: 'a scope is a glob relative to the repository root: \"src/auth/\", \"src/**/*.ts\", \"docs/{a,b}.md\"',\n },\n ];\n }),\n ),\n ),\n },\n {\n id: 'scope-contradiction',\n severity: 'error',\n description: 'Something of every affected pattern is writable: no pattern lies wholly inside protectedFiles.',\n check: live(({ brief, repoFiles }) => scopeContradiction(brief, repoFiles)),\n },\n {\n id: 'glob-matches-nothing',\n severity: 'note',\n description: 'A scope pattern matches at least one file in the tree.',\n check: live(({ brief, repoFiles }) => {\n if (repoFiles === null) return [];\n const reading = readingIn(repoFiles);\n return SCOPE_FIELDS.flatMap((field) =>\n patternsOf(brief[field], reading)\n // A literal the tree does not hold is literal-read-as-file's finding.\n .filter((p) => unheldLiterals(p.glob, repoFiles).length === 0 && !matchesAny(p.glob, repoFiles))\n .map((p) => ({\n line: at(lineOfField(brief, field)),\n message: `\"${p.pattern}\" in ${field} matches no file in the tree`,\n subject: `${field}: ${p.pattern}`,\n hint: 'expected when the round creates it; otherwise check the spelling',\n })),\n );\n }),\n },\n {\n id: 'literal-read-as-file',\n severity: 'note',\n description: 'A path with no glob syntax that the tree does not hold, and whose name has no extension, says whether it is a directory.',\n check: live(({ brief, repoFiles }) => {\n if (repoFiles === null) return [];\n const reading = readingIn(repoFiles);\n return SCOPE_FIELDS.flatMap((field) =>\n patternsOf(brief[field], reading).flatMap(({ pattern, glob }: ScopePattern) => {\n const paths = unheldLiterals(glob, repoFiles);\n if (paths.length === 0) return [];\n const line = at(lineOfField(brief, field));\n const hint = directoryAdvice(pattern, paths);\n const subject = `${field}: ${pattern}`;\n if (!isGlobSyntax(pattern)) {\n return [{ line, message: `\"${pattern}\" in ${field} is not in the tree and is read as a file`, hint, subject }];\n }\n return [\n {\n line,\n message: `\"${pattern}\" in ${field} names ${inWords(paths)}, which ${paths.length === 1 ? 'is' : 'are'} not in the tree and ${paths.length === 1 ? 'is' : 'are'} read as ${paths.length === 1 ? 'a file' : 'files'}`,\n hint,\n subject,\n },\n ];\n }),\n );\n }),\n },\n {\n id: 'archive-freeze',\n severity: 'error',\n description: 'An archived brief has not changed since it was archived.',\n check: ({ brief }) => {\n if (brief.phase !== 'archived' || brief.integrity === null) return [];\n if (integrityOf(brief.text) === brief.integrity) return [];\n return [\n {\n line: at(lineOfField(brief, 'integrity')),\n message: 'has changed since it was archived',\n hint: 'an archived brief is frozen: restore it from git, or unarchive it to reopen the round',\n },\n ];\n },\n },\n];\n\n/**\n * The rules the wave analyses - `matrix` and `schedule` - report under. They\n * are not run per brief, so they carry no check: they exist so configuration\n * can set their severity and reports can describe them.\n */\nexport const COLLISION_RULES: readonly RuleInfo[] = [\n { id: 'collision', severity: 'error', description: 'Briefs in one wave do not write the same file.' },\n {\n id: 'collision-undecided',\n severity: 'warning',\n description: 'Whether two briefs in one wave can write the same file is decided within the search budget.',\n },\n { id: 'unscoped', severity: 'note', description: 'A brief sharing a wave declares the files it writes.' },\n { id: 'shared-directory', severity: 'off', description: 'Briefs in one wave do not write into the same directory.' },\n {\n id: 'wave-schedule',\n severity: 'error',\n description: 'A brief declares a wave that holds: the one the schedule computes, or one lint and matrix accept, which is a note.',\n },\n];\n\n/**\n * The rules archival reports under beside its refusals. Like the collision\n * rules they carry no check: the planner raises them, and they exist so\n * configuration can set their severity and reports can describe them.\n */\nexport const ARCHIVE_RULES: readonly RuleInfo[] = [\n {\n id: 'scope-unmeasured',\n severity: 'warning',\n description: 'A brief that declares a scope is archived against the changes its round made.',\n },\n {\n id: 'stale-link',\n severity: 'warning',\n description: 'No live brief is left linking to where a moved brief used to be.',\n },\n];\n"]}
package/dist/scope.js CHANGED
@@ -9,7 +9,7 @@
9
9
  * the tree holds, or else the shortest such path the search builds, as an
10
10
  * example (ADR-0005).
11
11
  */
12
- import { globCovers, globWitness, matchGlob, parseGlob, WITNESS_BUDGET } from './glob.js';
12
+ import { filesMatching, globCovers, globWitness, matchGlob, parseGlob, WITNESS_BUDGET } from './glob.js';
13
13
  /** Patterns that parse, read with one reading. */
14
14
  export function patternsOf(patterns, reading) {
15
15
  return patterns.flatMap((pattern) => {
@@ -34,7 +34,7 @@ function matching(files, glob) {
34
34
  }
35
35
  let found = byGlob.get(glob);
36
36
  if (found === undefined) {
37
- found = new Set(files.filter((file) => matchGlob(glob, file)));
37
+ found = new Set(filesMatching(glob, files));
38
38
  byGlob.set(glob, found);
39
39
  }
40
40
  return found;
package/dist/scope.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A brief's scope, and whether two briefs can write the same file.\n *\n * What a brief may write is its `affectedFiles` less its `protectedFiles`:\n * protection wins, so \"all of `src/` but the schema\" is written\n * `affectedFiles: [src/**]` with `protectedFiles: [src/db/schema.ts]`. Two\n * briefs meet when some file lies in both writable scopes - in a pattern of\n * each, and in neither brief's protections - and the witness is such a file\n * the tree holds, or else the shortest such path the search builds, as an\n * example (ADR-0005).\n */\n\nimport type { Brief } from './brief.js';\nimport { type Glob, globCovers, globWitness, type LiteralReading, matchGlob, parseGlob, WITNESS_BUDGET } from './glob.js';\n\n/** How a literal path is read, as {@link readingIn} answers for a tree. */\nexport type Reading = (path: string) => LiteralReading;\n\nexport interface ScopePattern {\n readonly pattern: string;\n readonly glob: Glob;\n}\n\nexport interface Scope {\n readonly brief: Brief;\n /** The `affectedFiles` that parse. One that does not is the `glob` rule's finding, and scopes nothing. */\n readonly affected: readonly ScopePattern[];\n readonly protected: readonly ScopePattern[];\n}\n\n/** Patterns that parse, read with one reading. */\nexport function patternsOf(patterns: readonly string[], reading: Reading): ScopePattern[] {\n return patterns.flatMap((pattern) => {\n const parsed = parseGlob(pattern, { literal: reading });\n return parsed.ok ? [{ pattern, glob: parsed.glob }] : [];\n });\n}\n\nexport function scopeOf(brief: Brief, reading: Reading): Scope {\n return { brief, affected: patternsOf(brief.affectedFiles, reading), protected: patternsOf(brief.protectedFiles, reading) };\n}\n\n/** A pattern from each scope, and a file both may write. */\nexport interface Overlap {\n readonly patterns: readonly [string, string];\n readonly witness: string;\n /**\n * `true` when the witness is a file the tree holds; `false` when the tree\n * holds none both patterns match outside the protections, and the witness\n * is an example the search built; `null` when no tree was given.\n */\n readonly inTree: boolean | null;\n}\n\nexport interface Meeting {\n /** Every pair of patterns that meets outside both protections, the first scope's pattern first. */\n readonly overlaps: readonly Overlap[];\n /** Pairs of patterns the search could not decide within its budget, and no file of the tree decides. */\n readonly undecided: readonly (readonly [string, string])[];\n}\n\nconst matched = new WeakMap<readonly string[], WeakMap<Glob, ReadonlySet<string>>>();\n\n/**\n * The files of a tree a pattern matches, in the tree's order. Found once per\n * pattern and tree, which every pair a brief is in shares; kept or not, the\n * answer is the same, and only the time differs.\n */\nfunction matching(files: readonly string[], glob: Glob): ReadonlySet<string> {\n let byGlob = matched.get(files);\n if (byGlob === undefined) {\n byGlob = new WeakMap();\n matched.set(files, byGlob);\n }\n let found = byGlob.get(glob);\n if (found === undefined) {\n found = new Set(files.filter((file) => matchGlob(glob, file)));\n byGlob.set(glob, found);\n }\n return found;\n}\n\n/**\n * The first file of the tree, in its order, that both patterns match and no\n * protection does. The engine's list is sorted, so the file named is the same\n * on every run.\n */\nfunction heldInBoth(files: readonly string[], x: Glob, y: Glob, avoid: readonly Glob[]): string | undefined {\n const other = matching(files, y);\n for (const file of matching(files, x)) {\n if (other.has(file) && !avoid.some((glob) => matchGlob(glob, file))) return file;\n }\n return undefined;\n}\n\n/**\n * Where two writable scopes meet. Each pair of affected patterns is searched\n * for a file both cover that neither brief protects: a file one brief protects\n * is one that brief will not write, so it is no collision.\n *\n * The search names the shortest such path, which the tree need not hold:\n * `src/Shop/OrderService.cs` where the tree has `src/Shop/Orders/OrderService.cs`.\n * So where the search finds a meeting, or cannot decide one, the tree's files\n * are read, and the first both patterns match outside the protections is the\n * witness (ADR-0005, amended 2026-09-30). A file that exists and both briefs\n * may write settles a pair the search could not: it is a collision, proved by\n * the file, not a guess. Where the tree holds none, the search's path stands,\n * as an example. A pair the search proves apart has no such file, and the tree\n * is not read for it.\n */\nexport function meet(a: Scope, b: Scope, budget: number = WITNESS_BUDGET, files: readonly string[] | null = null): Meeting {\n const avoid = [...a.protected, ...b.protected].map((p) => p.glob);\n const overlaps: Overlap[] = [];\n const undecided: (readonly [string, string])[] = [];\n for (const x of a.affected) {\n for (const y of b.affected) {\n const witness = globWitness([x.glob, y.glob], avoid, budget);\n if (witness.kind === 'none') continue;\n const patterns = [x.pattern, y.pattern] as const;\n const held = files === null ? undefined : heldInBoth(files, x.glob, y.glob, avoid);\n if (held !== undefined) overlaps.push({ patterns, witness: held, inTree: true });\n else if (witness.kind === 'found') overlaps.push({ patterns, witness: witness.path, inTree: files === null ? null : false });\n else undecided.push(patterns);\n }\n }\n return { overlaps, undecided };\n}\n\n/**\n * A witness as a reader is told it: a file of the tree by its path, and a path\n * the search built with a word that it is an example.\n */\nexport function witnessText(overlap: Overlap): string {\n return overlap.inTree === false ? `${overlap.witness}, an example not in the tree` : overlap.witness;\n}\n\nexport interface Contradiction {\n /** Affected patterns every file of which is protected: nothing of them is writable. */\n readonly covered: readonly string[];\n /** Affected patterns for which the search could not decide within its budget. */\n readonly undecided: readonly string[];\n}\n\n/** The affected patterns a brief's own protections cover entirely. */\nexport function contradictions(scope: Scope, budget: number = WITNESS_BUDGET): Contradiction {\n const covered: string[] = [];\n const undecided: string[] = [];\n const outer = scope.protected.map((p) => p.glob);\n for (const { pattern, glob } of scope.affected) {\n const answer = globCovers(outer, glob, budget);\n if (answer === true) covered.push(pattern);\n else if (answer === 'undecided') undecided.push(pattern);\n }\n return { covered, undecided };\n}\n"]}
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * A brief's scope, and whether two briefs can write the same file.\n *\n * What a brief may write is its `affectedFiles` less its `protectedFiles`:\n * protection wins, so \"all of `src/` but the schema\" is written\n * `affectedFiles: [src/**]` with `protectedFiles: [src/db/schema.ts]`. Two\n * briefs meet when some file lies in both writable scopes - in a pattern of\n * each, and in neither brief's protections - and the witness is such a file\n * the tree holds, or else the shortest such path the search builds, as an\n * example (ADR-0005).\n */\n\nimport type { Brief } from './brief.js';\nimport { filesMatching, type Glob, globCovers, globWitness, type LiteralReading, matchGlob, parseGlob, WITNESS_BUDGET } from './glob.js';\n\n/** How a literal path is read, as {@link readingIn} answers for a tree. */\nexport type Reading = (path: string) => LiteralReading;\n\nexport interface ScopePattern {\n readonly pattern: string;\n readonly glob: Glob;\n}\n\nexport interface Scope {\n readonly brief: Brief;\n /** The `affectedFiles` that parse. One that does not is the `glob` rule's finding, and scopes nothing. */\n readonly affected: readonly ScopePattern[];\n readonly protected: readonly ScopePattern[];\n}\n\n/** Patterns that parse, read with one reading. */\nexport function patternsOf(patterns: readonly string[], reading: Reading): ScopePattern[] {\n return patterns.flatMap((pattern) => {\n const parsed = parseGlob(pattern, { literal: reading });\n return parsed.ok ? [{ pattern, glob: parsed.glob }] : [];\n });\n}\n\nexport function scopeOf(brief: Brief, reading: Reading): Scope {\n return { brief, affected: patternsOf(brief.affectedFiles, reading), protected: patternsOf(brief.protectedFiles, reading) };\n}\n\n/** A pattern from each scope, and a file both may write. */\nexport interface Overlap {\n readonly patterns: readonly [string, string];\n readonly witness: string;\n /**\n * `true` when the witness is a file the tree holds; `false` when the tree\n * holds none both patterns match outside the protections, and the witness\n * is an example the search built; `null` when no tree was given.\n */\n readonly inTree: boolean | null;\n}\n\nexport interface Meeting {\n /** Every pair of patterns that meets outside both protections, the first scope's pattern first. */\n readonly overlaps: readonly Overlap[];\n /** Pairs of patterns the search could not decide within its budget, and no file of the tree decides. */\n readonly undecided: readonly (readonly [string, string])[];\n}\n\nconst matched = new WeakMap<readonly string[], WeakMap<Glob, ReadonlySet<string>>>();\n\n/**\n * The files of a tree a pattern matches, in the tree's order. Found once per\n * pattern and tree, which every pair a brief is in shares; kept or not, the\n * answer is the same, and only the time differs.\n */\nfunction matching(files: readonly string[], glob: Glob): ReadonlySet<string> {\n let byGlob = matched.get(files);\n if (byGlob === undefined) {\n byGlob = new WeakMap();\n matched.set(files, byGlob);\n }\n let found = byGlob.get(glob);\n if (found === undefined) {\n found = new Set(filesMatching(glob, files));\n byGlob.set(glob, found);\n }\n return found;\n}\n\n/**\n * The first file of the tree, in its order, that both patterns match and no\n * protection does. The engine's list is sorted, so the file named is the same\n * on every run.\n */\nfunction heldInBoth(files: readonly string[], x: Glob, y: Glob, avoid: readonly Glob[]): string | undefined {\n const other = matching(files, y);\n for (const file of matching(files, x)) {\n if (other.has(file) && !avoid.some((glob) => matchGlob(glob, file))) return file;\n }\n return undefined;\n}\n\n/**\n * Where two writable scopes meet. Each pair of affected patterns is searched\n * for a file both cover that neither brief protects: a file one brief protects\n * is one that brief will not write, so it is no collision.\n *\n * The search names the shortest such path, which the tree need not hold:\n * `src/Shop/OrderService.cs` where the tree has `src/Shop/Orders/OrderService.cs`.\n * So where the search finds a meeting, or cannot decide one, the tree's files\n * are read, and the first both patterns match outside the protections is the\n * witness (ADR-0005, amended 2026-09-30). A file that exists and both briefs\n * may write settles a pair the search could not: it is a collision, proved by\n * the file, not a guess. Where the tree holds none, the search's path stands,\n * as an example. A pair the search proves apart has no such file, and the tree\n * is not read for it.\n */\nexport function meet(a: Scope, b: Scope, budget: number = WITNESS_BUDGET, files: readonly string[] | null = null): Meeting {\n const avoid = [...a.protected, ...b.protected].map((p) => p.glob);\n const overlaps: Overlap[] = [];\n const undecided: (readonly [string, string])[] = [];\n for (const x of a.affected) {\n for (const y of b.affected) {\n const witness = globWitness([x.glob, y.glob], avoid, budget);\n if (witness.kind === 'none') continue;\n const patterns = [x.pattern, y.pattern] as const;\n const held = files === null ? undefined : heldInBoth(files, x.glob, y.glob, avoid);\n if (held !== undefined) overlaps.push({ patterns, witness: held, inTree: true });\n else if (witness.kind === 'found') overlaps.push({ patterns, witness: witness.path, inTree: files === null ? null : false });\n else undecided.push(patterns);\n }\n }\n return { overlaps, undecided };\n}\n\n/**\n * A witness as a reader is told it: a file of the tree by its path, and a path\n * the search built with a word that it is an example.\n */\nexport function witnessText(overlap: Overlap): string {\n return overlap.inTree === false ? `${overlap.witness}, an example not in the tree` : overlap.witness;\n}\n\nexport interface Contradiction {\n /** Affected patterns every file of which is protected: nothing of them is writable. */\n readonly covered: readonly string[];\n /** Affected patterns for which the search could not decide within its budget. */\n readonly undecided: readonly string[];\n}\n\n/** The affected patterns a brief's own protections cover entirely. */\nexport function contradictions(scope: Scope, budget: number = WITNESS_BUDGET): Contradiction {\n const covered: string[] = [];\n const undecided: string[] = [];\n const outer = scope.protected.map((p) => p.glob);\n for (const { pattern, glob } of scope.affected) {\n const answer = globCovers(outer, glob, budget);\n if (answer === true) covered.push(pattern);\n else if (answer === 'undecided') undecided.push(pattern);\n }\n return { covered, undecided };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@descent-vtt/spec-brief",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Lifecycle management for task briefs: lint the contract, map parallel collisions, and archive a round in one atomic command.",
5
5
  "keywords": [
6
6
  "agents",