@hegemonart/get-design-done 1.31.0 → 1.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +75 -0
  4. package/NOTICE +262 -0
  5. package/README.md +13 -1
  6. package/SKILL.md +4 -0
  7. package/agents/design-authority-watcher.md +1 -1
  8. package/agents/perf-analyzer.md +2 -2
  9. package/bin/gdd-mcp +78 -0
  10. package/bin/gdd-sdk +34 -24
  11. package/bin/gdd-state-mcp +78 -0
  12. package/{README.de.md → docs/i18n/README.de.md} +1 -1
  13. package/{README.fr.md → docs/i18n/README.fr.md} +1 -1
  14. package/{README.it.md → docs/i18n/README.it.md} +1 -1
  15. package/{README.ja.md → docs/i18n/README.ja.md} +1 -1
  16. package/{README.ko.md → docs/i18n/README.ko.md} +1 -1
  17. package/{README.zh-CN.md → docs/i18n/README.zh-CN.md} +1 -1
  18. package/hooks/_hook-emit.js +1 -1
  19. package/hooks/budget-enforcer.ts +5 -5
  20. package/hooks/context-exhaustion.ts +2 -2
  21. package/hooks/gdd-precompact-snapshot.js +3 -3
  22. package/hooks/gdd-read-injection-scanner.ts +2 -2
  23. package/hooks/gdd-sessionstart-recap.js +1 -1
  24. package/hooks/gdd-turn-closeout.js +1 -1
  25. package/hooks/hooks.json +9 -0
  26. package/hooks/inject-using-gdd.sh +72 -0
  27. package/hooks/run-hook.cmd +35 -0
  28. package/package.json +20 -9
  29. package/recipes/.gitkeep +0 -0
  30. package/reference/schemas/events.schema.json +63 -1
  31. package/reference/schemas/recipe.schema.json +33 -0
  32. package/scripts/cli/gdd-events.mjs +5 -5
  33. package/scripts/lib/cache/gdd-cache-manager.cjs +1 -1
  34. package/scripts/lib/cli/index.ts +22 -160
  35. package/scripts/lib/connection-probe/index.cjs +1 -1
  36. package/scripts/lib/discuss-parallel-runner/aggregator.ts +1 -1
  37. package/scripts/lib/discuss-parallel-runner/index.ts +1 -1
  38. package/scripts/lib/error-classifier.cjs +24 -227
  39. package/scripts/lib/event-stream/index.ts +25 -193
  40. package/scripts/lib/gdd-errors/index.ts +24 -213
  41. package/scripts/lib/gdd-state/index.ts +23 -161
  42. package/scripts/lib/health-mirror/index.cjs +79 -1
  43. package/scripts/lib/iteration-budget.cjs +23 -199
  44. package/scripts/lib/jittered-backoff.cjs +24 -107
  45. package/scripts/lib/lockfile.cjs +23 -195
  46. package/scripts/lib/logger/index.ts +1 -1
  47. package/scripts/lib/parallelism-engine/concurrency-tuner.cjs +1 -1
  48. package/scripts/lib/perf-analyzer/index.cjs +1 -1
  49. package/scripts/lib/pipeline-runner/index.ts +4 -4
  50. package/scripts/lib/pipeline-runner/state-machine.ts +1 -1
  51. package/scripts/lib/prompt-dedup/index.cjs +1 -1
  52. package/scripts/lib/rate-guard.cjs +2 -2
  53. package/scripts/lib/recipe-loader.cjs +142 -0
  54. package/scripts/lib/session-runner/errors.ts +3 -3
  55. package/scripts/lib/session-runner/index.ts +3 -3
  56. package/scripts/lib/session-runner/transcript.ts +1 -1
  57. package/scripts/lib/tool-scoping/index.ts +1 -1
  58. package/scripts/mcp-servers/gdd-mcp/server.ts +29 -311
  59. package/scripts/mcp-servers/gdd-state/server.ts +28 -282
  60. package/sdk/README.md +45 -0
  61. package/{scripts/lib → sdk}/cli/commands/audit.ts +3 -3
  62. package/{scripts/lib → sdk}/cli/commands/init.ts +3 -3
  63. package/{scripts/lib → sdk}/cli/commands/query.ts +4 -4
  64. package/{scripts/lib → sdk}/cli/commands/run.ts +5 -5
  65. package/{scripts/lib → sdk}/cli/commands/stage.ts +5 -5
  66. package/sdk/cli/index.js +8091 -0
  67. package/sdk/cli/index.ts +172 -0
  68. package/{scripts/lib → sdk}/cli/parse-args.ts +2 -2
  69. package/{scripts/lib/gdd-errors → sdk/errors}/classification.ts +1 -1
  70. package/sdk/errors/index.ts +218 -0
  71. package/{scripts/lib → sdk}/event-stream/emitter.ts +1 -1
  72. package/sdk/event-stream/index.ts +197 -0
  73. package/{scripts/lib → sdk}/event-stream/reader.ts +1 -1
  74. package/{scripts/lib → sdk}/event-stream/types.ts +2 -2
  75. package/{scripts/lib → sdk}/event-stream/writer.ts +1 -1
  76. package/sdk/index.ts +19 -0
  77. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/README.md +3 -3
  78. package/sdk/mcp/gdd-mcp/server.js +1966 -0
  79. package/sdk/mcp/gdd-mcp/server.ts +325 -0
  80. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_cycle_recap.ts +3 -3
  81. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_decisions_list.ts +2 -2
  82. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_events_tail.ts +3 -3
  83. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_health.ts +2 -2
  84. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_intel_get.ts +2 -2
  85. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_learnings_digest.ts +2 -2
  86. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_phase_current.ts +2 -2
  87. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_phases_list.ts +2 -2
  88. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_plans_list.ts +2 -2
  89. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_reflections_latest.ts +2 -2
  90. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_status.ts +3 -3
  91. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/gdd_telemetry_query.ts +3 -3
  92. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/index.ts +2 -2
  93. package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/tools/shared.ts +3 -3
  94. package/sdk/mcp/gdd-state/server.js +2790 -0
  95. package/sdk/mcp/gdd-state/server.ts +294 -0
  96. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/add_blocker.ts +3 -3
  97. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/add_decision.ts +3 -3
  98. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/add_must_have.ts +3 -3
  99. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/checkpoint.ts +2 -2
  100. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/frontmatter_update.ts +2 -2
  101. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/get.ts +3 -3
  102. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/index.ts +1 -1
  103. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/probe_connections.ts +3 -3
  104. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/resolve_blocker.ts +3 -3
  105. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/set_status.ts +2 -2
  106. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/shared.ts +8 -8
  107. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/transition_stage.ts +4 -4
  108. package/{scripts/mcp-servers → sdk/mcp}/gdd-state/tools/update_progress.ts +2 -2
  109. package/sdk/primitives/error-classifier.cjs +232 -0
  110. package/sdk/primitives/iteration-budget.cjs +205 -0
  111. package/sdk/primitives/jittered-backoff.cjs +112 -0
  112. package/sdk/primitives/lockfile.cjs +201 -0
  113. package/{scripts/lib/gdd-state → sdk/state}/gates.ts +1 -1
  114. package/sdk/state/index.ts +167 -0
  115. package/{scripts/lib/gdd-state → sdk/state}/lockfile.ts +1 -1
  116. package/{scripts/lib/gdd-state → sdk/state}/mutator.ts +1 -1
  117. package/{scripts/lib/gdd-state → sdk/state}/parser.ts +1 -1
  118. package/{scripts/lib/gdd-state → sdk/state}/types.ts +4 -4
  119. package/skills/audit/SKILL.md +13 -0
  120. package/skills/brief/SKILL.md +25 -0
  121. package/skills/design/SKILL.md +17 -0
  122. package/skills/discuss/SKILL.md +13 -0
  123. package/skills/explore/SKILL.md +17 -0
  124. package/skills/health/SKILL.md +6 -0
  125. package/skills/plan/SKILL.md +25 -0
  126. package/skills/quality-gate/SKILL.md +2 -2
  127. package/skills/router/SKILL.md +4 -0
  128. package/skills/router/router-pick-emitter.md +78 -0
  129. package/skills/using-gdd/SKILL.md +78 -0
  130. package/skills/verify/SKILL.md +17 -0
  131. package/scripts/aggregate-agent-metrics.ts +0 -282
  132. package/scripts/bootstrap-manifest.txt +0 -3
  133. package/scripts/bootstrap.sh +0 -80
  134. package/scripts/build-distribution-bundles.cjs +0 -549
  135. package/scripts/build-intel.cjs +0 -486
  136. package/scripts/codegen-schema-types.ts +0 -149
  137. package/scripts/detect-stale-refs.cjs +0 -107
  138. package/scripts/e2e/run-headless.ts +0 -514
  139. package/scripts/extract-changelog-section.cjs +0 -58
  140. package/scripts/gsd-cleanup-incubator.cjs +0 -367
  141. package/scripts/injection-patterns.cjs +0 -58
  142. package/scripts/lint-agentskills-spec.cjs +0 -457
  143. package/scripts/release-smoke-test.cjs +0 -200
  144. package/scripts/rollback-release.sh +0 -42
  145. package/scripts/run-injection-scanner-ci.cjs +0 -83
  146. package/scripts/tests/test-authority-rejected-kinds.sh +0 -58
  147. package/scripts/tests/test-authority-watcher-diff.sh +0 -113
  148. package/scripts/tests/test-motion-provenance.sh +0 -64
  149. package/scripts/validate-frontmatter.ts +0 -409
  150. package/scripts/validate-incubator-scope.cjs +0 -133
  151. package/scripts/validate-schemas.ts +0 -401
  152. package/scripts/validate-skill-length.cjs +0 -283
  153. package/scripts/verify-version-sync.cjs +0 -30
  154. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_cycle_recap.schema.json +0 -0
  155. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_decisions_list.schema.json +0 -0
  156. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_events_tail.schema.json +0 -0
  157. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_health.schema.json +0 -0
  158. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_intel_get.schema.json +0 -0
  159. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_learnings_digest.schema.json +0 -0
  160. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_phase_current.schema.json +0 -0
  161. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_phases_list.schema.json +0 -0
  162. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_plans_list.schema.json +0 -0
  163. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_reflections_latest.schema.json +0 -0
  164. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_status.schema.json +0 -0
  165. /package/{scripts/mcp-servers → sdk/mcp}/gdd-mcp/schemas/gdd_telemetry_query.schema.json +0 -0
  166. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/add_blocker.schema.json +0 -0
  167. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/add_decision.schema.json +0 -0
  168. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/add_must_have.schema.json +0 -0
  169. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/checkpoint.schema.json +0 -0
  170. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/frontmatter_update.schema.json +0 -0
  171. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/get.schema.json +0 -0
  172. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/probe_connections.schema.json +0 -0
  173. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/resolve_blocker.schema.json +0 -0
  174. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/set_status.schema.json +0 -0
  175. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/transition_stage.schema.json +0 -0
  176. /package/{scripts/mcp-servers → sdk/mcp}/gdd-state/schemas/update_progress.schema.json +0 -0
  177. /package/{scripts/lib → sdk/primitives}/error-classifier.d.cts +0 -0
  178. /package/{scripts/lib → sdk/primitives}/iteration-budget.d.cts +0 -0
  179. /package/{scripts/lib → sdk/primitives}/jittered-backoff.d.cts +0 -0
  180. /package/{scripts/lib → sdk/primitives}/lockfile.d.cts +0 -0
@@ -1,83 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- // CI-mode wrapper over hooks/gdd-read-injection-scanner.js.
4
- // Scans all shipped reference/*.md, skills/**/SKILL.md, and agents/*.md for
5
- // prompt-injection patterns. Exits 0 on a clean tree, 1 on any finding.
6
- //
7
- // The patterns are imported indirectly by re-declaring them — the hook itself
8
- // is stdin-driven and cannot be required as a module. Keep these in sync with
9
- // hooks/gdd-read-injection-scanner.js.
10
-
11
- const fs = require('fs');
12
- const path = require('path');
13
-
14
- const REPO_ROOT = path.resolve(__dirname, '..');
15
-
16
- const { INJECTION_PATTERNS } = require('./injection-patterns.cjs');
17
-
18
- function walkMd(dir, out) {
19
- if (!fs.existsSync(dir)) return;
20
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
21
- const full = path.join(dir, entry.name);
22
- if (entry.isDirectory()) walkMd(full, out);
23
- else if (entry.isFile() && entry.name.endsWith('.md')) out.push(full);
24
- }
25
- }
26
-
27
- function collectTargets() {
28
- const targets = [];
29
- // reference/ — all .md recursively
30
- walkMd(path.join(REPO_ROOT, 'reference'), targets);
31
- // skills/**/SKILL.md — only SKILL.md files
32
- const skillsRoot = path.join(REPO_ROOT, 'skills');
33
- const skillAccum = [];
34
- walkMd(skillsRoot, skillAccum);
35
- for (const f of skillAccum) {
36
- if (path.basename(f) === 'SKILL.md') targets.push(f);
37
- }
38
- // agents/*.md (non-recursive)
39
- const agentsRoot = path.join(REPO_ROOT, 'agents');
40
- if (fs.existsSync(agentsRoot)) {
41
- for (const entry of fs.readdirSync(agentsRoot, { withFileTypes: true })) {
42
- if (entry.isFile() && entry.name.endsWith('.md')) {
43
- targets.push(path.join(agentsRoot, entry.name));
44
- }
45
- }
46
- }
47
- return targets;
48
- }
49
-
50
- function main() {
51
- const targets = collectTargets();
52
- let findings = 0;
53
-
54
- for (const file of targets) {
55
- const body = fs.readFileSync(file, 'utf8');
56
- const lines = body.split('\n');
57
- let inFence = false;
58
- for (let i = 0; i < lines.length; i++) {
59
- const line = lines[i];
60
- // Track code fences — prompt-injection attacks live in prose, not in
61
- // literal code/template blocks. Skip lines inside ``` ... ``` fences.
62
- if (/^\s*```/.test(line)) {
63
- inFence = !inFence;
64
- continue;
65
- }
66
- if (inFence) continue;
67
- for (const pat of INJECTION_PATTERNS) {
68
- if (pat.re.test(line)) {
69
- const rel = path.relative(REPO_ROOT, file);
70
- const excerpt = line.trim().slice(0, 120);
71
- console.log(`${rel}:${i + 1}: ${pat.name}: ${excerpt}`);
72
- findings++;
73
- break; // one finding per line is enough
74
- }
75
- }
76
- }
77
- }
78
-
79
- console.log(`summary: ${targets.length} files scanned, ${findings} findings`);
80
- process.exit(findings === 0 ? 0 : 1);
81
- }
82
-
83
- main();
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env bash
2
- # test-authority-rejected-kinds.sh
3
- #
4
- # Asserts that reference/authority-feeds.md does NOT contain trend-aggregator
5
- # hosts OUTSIDE the explicit "## Rejected kinds" section. Enforces the anti-slop
6
- # thesis structurally (CONTEXT.md D-08, D-28).
7
- #
8
- # Exit 0 = clean. Exit 1 = at least one rejected host appeared in the active
9
- # whitelist, or the rejected-kinds section itself was removed.
10
-
11
- set -euo pipefail
12
-
13
- WHITELIST="${WHITELIST:-reference/authority-feeds.md}"
14
-
15
- if [ ! -f "$WHITELIST" ]; then
16
- echo "FAIL: $WHITELIST not found." >&2
17
- exit 1
18
- fi
19
-
20
- # Split the file at the "## Rejected kinds" heading. Everything BEFORE it is
21
- # the active whitelist; everything AFTER is the rejection manifest (which is
22
- # allowed to mention these hosts — that's the whole point).
23
- ACTIVE_SECTION="$(awk '/^## Rejected kinds/{exit} {print}' "$WHITELIST")"
24
-
25
- REJECTED_PATTERNS=(
26
- 'dribbble\.com'
27
- 'behance\.net'
28
- 'linkedin\.com'
29
- 'medium\.com/topic'
30
- 'producthunt\.com/posts'
31
- 'top[[:space:]]*10[[:space:]]*ui'
32
- 'trending-ui'
33
- )
34
-
35
- FAIL=0
36
- for pat in "${REJECTED_PATTERNS[@]}"; do
37
- if echo "$ACTIVE_SECTION" | grep -iEq "$pat"; then
38
- echo "FAIL: rejected pattern '$pat' matched in active whitelist section of $WHITELIST." >&2
39
- FAIL=1
40
- fi
41
- done
42
-
43
- if [ "$FAIL" -ne 0 ]; then
44
- echo "" >&2
45
- echo "The whitelist must not contain trend-aggregator hosts outside the '## Rejected kinds' block." >&2
46
- echo "See .planning/phases/13.2-external-authority-watcher/13.2-CONTEXT.md §D-08." >&2
47
- exit 1
48
- fi
49
-
50
- # Also assert the rejected-kinds section itself is present — regression against
51
- # someone deleting the section entirely.
52
- if ! grep -q '^## Rejected kinds$' "$WHITELIST"; then
53
- echo "FAIL: '## Rejected kinds' section is missing from $WHITELIST." >&2
54
- exit 1
55
- fi
56
-
57
- echo "OK: $WHITELIST passes rejected-kinds check."
58
- exit 0
@@ -1,113 +0,0 @@
1
- #!/usr/bin/env bash
2
- # test-authority-watcher-diff.sh
3
- #
4
- # Structural-only v1: validates that the frozen authority-report baseline at
5
- # test-fixture/baselines/phase-13.2/authority-report.expected.md preserves the
6
- # shape the watcher-diff test depends on. Full end-to-end byte-diff against a
7
- # live watcher run is deferred — CI cannot spawn Claude Code agents.
8
- #
9
- # What this test asserts (structural-only v1):
10
- # 1. The fixture directory exists and is non-empty.
11
- # 2. The baseline file exists, is non-empty, and starts with an Authority
12
- # Report header.
13
- # 3. The baseline contains the canonical classification section headings in
14
- # the D-21 weighted order (spec > heuristic > pattern > craft).
15
- # 4. The baseline declares a total-entries line consistent with the count of
16
- # bulleted entries under its classification sections.
17
- # 5. The baseline ends with a `**Skipped:**` footer.
18
- #
19
- # Exit 0 = structural shape preserved. Exit 1 = shape drift detected.
20
- #
21
- # Full end-to-end byte-diff (running the watcher against the fixtures and
22
- # diffing stdout against the baseline) is a follow-up tracked in STATE.md
23
- # "Open follow-ups". When the agent runtime becomes available in CI this
24
- # script graduates from structural-only v1 to the full diff check.
25
-
26
- set -euo pipefail
27
-
28
- FIXTURE_DIR="test-fixture/authority-feeds"
29
- BASELINE="test-fixture/baselines/phase-13.2/authority-report.expected.md"
30
-
31
- if [ ! -d "$FIXTURE_DIR" ]; then
32
- echo "FAIL: fixture dir $FIXTURE_DIR missing." >&2
33
- exit 1
34
- fi
35
-
36
- # Count actual fixture files (should be 4 frozen feeds + 1 README; we only
37
- # care that at least one XML/JSON fixture is present).
38
- # Use null-delimited find to handle filenames with spaces/newlines (WR-05).
39
- FIXTURE_COUNT=0
40
- while IFS= read -r -d '' _f; do
41
- FIXTURE_COUNT=$((FIXTURE_COUNT + 1))
42
- done < <(find "$FIXTURE_DIR" -maxdepth 1 -type f \( -name '*.atom' -o -name '*.rss' -o -name '*.json' \) -print0)
43
- if [ "$FIXTURE_COUNT" -lt 1 ]; then
44
- echo "FAIL: $FIXTURE_DIR contains no feed fixtures (.atom/.rss/.json)." >&2
45
- exit 1
46
- fi
47
-
48
- if [ ! -f "$BASELINE" ]; then
49
- echo "FAIL: baseline $BASELINE missing." >&2
50
- exit 1
51
- fi
52
-
53
- if [ ! -s "$BASELINE" ]; then
54
- echo "FAIL: baseline $BASELINE is empty." >&2
55
- exit 1
56
- fi
57
-
58
- # Header: must start with "# Authority Report"
59
- if ! head -1 "$BASELINE" | grep -q '^# Authority Report'; then
60
- echo "FAIL: baseline does not begin with '# Authority Report' header." >&2
61
- exit 1
62
- fi
63
-
64
- # Totals line must declare a non-negative surfaced-entries count.
65
- if ! grep -qE '^[0-9]+ entries surfaced across [0-9]+ feeds\. [0-9]+ skipped\.$' "$BASELINE"; then
66
- echo "FAIL: baseline is missing the 'N entries surfaced across M feeds. K skipped.' totals line." >&2
67
- exit 1
68
- fi
69
-
70
- # Classification sections — at least one of the four non-skip buckets must
71
- # appear. (Empty buckets are omitted by D-21, but a well-shaped baseline
72
- # always has at least one.)
73
- SECTION_HITS=0
74
- for heading in '^## spec-change' '^## heuristic-update' '^## pattern-guidance' '^## craft-tip'; do
75
- if grep -qE "$heading" "$BASELINE"; then
76
- SECTION_HITS=$((SECTION_HITS + 1))
77
- fi
78
- done
79
-
80
- if [ "$SECTION_HITS" -lt 1 ]; then
81
- echo "FAIL: baseline does not contain any classification heading (spec-change / heuristic-update / pattern-guidance / craft-tip)." >&2
82
- exit 1
83
- fi
84
-
85
- # Count consistency check: the header's "N entries surfaced" must match the
86
- # total bulleted entries across the four classification sections.
87
- HEADER_COUNT=$(grep -oE '^[0-9]+ entries surfaced' "$BASELINE" | head -1 | grep -oE '^[0-9]+')
88
-
89
- # Extract the body between the first "## spec-change|heuristic-update|pattern-guidance|craft-tip"
90
- # heading and the closing "---" horizontal rule before the Skipped footer.
91
- BULLET_COUNT=$(awk '
92
- /^## (spec-change|heuristic-update|pattern-guidance|craft-tip)/ { in_section=1; next }
93
- /^---$/ { in_section=0 }
94
- in_section && /^- / { count++ }
95
- END { print count+0 }
96
- ' "$BASELINE")
97
-
98
- if [ "$HEADER_COUNT" != "$BULLET_COUNT" ]; then
99
- echo "FAIL: baseline header declares $HEADER_COUNT entries but the classification sections contain $BULLET_COUNT bullets." >&2
100
- echo " Counts MUST match — regenerate the baseline or fix the header." >&2
101
- exit 1
102
- fi
103
-
104
- # Footer: must have a Skipped line.
105
- if ! grep -qE '^\*\*Skipped:\*\*' "$BASELINE"; then
106
- echo "FAIL: baseline is missing the '**Skipped:**' footer line." >&2
107
- exit 1
108
- fi
109
-
110
- echo "OK: authority-report baseline shape preserved (structural-only v1)."
111
- echo " Fixtures: $FIXTURE_COUNT files under $FIXTURE_DIR"
112
- echo " Entries: $HEADER_COUNT (header) = $BULLET_COUNT (bullets)"
113
- exit 0
@@ -1,64 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -e
3
-
4
- # Provenance test: verifies RN-MIT attribution is present in all motion files
5
- # and that no file contains incorrect "Remotion/" provenance.
6
- #
7
- # Run from the project root:
8
- # bash scripts/tests/test-motion-provenance.sh
9
-
10
- PASS_COUNT=0
11
- FAIL_COUNT=0
12
-
13
- check_attribution() {
14
- local file="$1"
15
- local needle="React Native"
16
-
17
- if grep -q "$needle" "$file"; then
18
- echo "PASS: $file contains RN-MIT attribution"
19
- PASS_COUNT=$((PASS_COUNT + 1))
20
- else
21
- echo "FAIL: $file is missing RN-MIT attribution (expected: '$needle')"
22
- FAIL_COUNT=$((FAIL_COUNT + 1))
23
- fi
24
- }
25
-
26
- check_no_remotion() {
27
- local file="$1"
28
-
29
- if grep -q "Remotion/" "$file"; then
30
- echo "FAIL: $file contains wrong provenance string 'Remotion/'"
31
- FAIL_COUNT=$((FAIL_COUNT + 1))
32
- else
33
- echo "PASS: $file does not contain 'Remotion/'"
34
- PASS_COUNT=$((PASS_COUNT + 1))
35
- fi
36
- }
37
-
38
- FILES=(
39
- "reference/motion-easings.md"
40
- "reference/motion-interpolate.md"
41
- "reference/motion-spring.md"
42
- "scripts/lib/easings.cjs"
43
- "scripts/lib/spring.cjs"
44
- )
45
-
46
- echo "=== Attribution checks ==="
47
- for f in "${FILES[@]}"; do
48
- check_attribution "$f"
49
- done
50
-
51
- echo ""
52
- echo "=== Provenance contamination checks ==="
53
- for f in "${FILES[@]}"; do
54
- check_no_remotion "$f"
55
- done
56
-
57
- echo ""
58
- echo "=== Results: $PASS_COUNT passed, $FAIL_COUNT failed ==="
59
-
60
- if [ "$FAIL_COUNT" -gt 0 ]; then
61
- exit 1
62
- fi
63
-
64
- exit 0