universal-dev-standards 6.14.0-beta.3 → 6.14.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/uds.js +7 -1
- package/bundled/ai/standards/ai-response-navigation.ai.yaml +43 -3
- package/bundled/ai/standards/checkin-standards.ai.yaml +25 -6
- package/bundled/ai/standards/full-coverage-testing.ai.yaml +46 -5
- package/bundled/ai/standards/pipeline-security-gates.ai.yaml +5 -1
- package/bundled/core/ai-response-navigation.md +128 -12
- package/bundled/core/full-coverage-testing.md +57 -3
- package/bundled/extensions/frameworks/fat-free-patterns.md +937 -0
- package/bundled/extensions/languages/csharp-style.md +464 -0
- package/bundled/extensions/languages/php-style.md +700 -0
- package/bundled/extensions/locales/zh-cn.md +717 -0
- package/bundled/extensions/locales/zh-tw.md +717 -0
- package/bundled/locales/COVERAGE.md +5 -4
- package/bundled/locales/zh-CN/CHANGELOG.md +54 -3
- package/bundled/locales/zh-CN/README.md +2 -2
- package/bundled/locales/zh-CN/SECURITY.md +1 -1
- package/bundled/locales/zh-CN/core/ai-response-navigation.md +110 -12
- package/bundled/locales/zh-CN/core/full-coverage-testing.md +61 -7
- package/bundled/locales/zh-CN/docs/CHEATSHEET.md +3 -1
- package/bundled/locales/zh-CN/docs/FEATURE-REFERENCE.md +8 -5
- package/bundled/locales/zh-CN/skills/README.md +1 -0
- package/bundled/locales/zh-CN/skills/comprehension-ladder/SKILL.md +289 -0
- package/bundled/locales/zh-CN/skills/comprehension-ladder/eval-cases.md +261 -0
- package/bundled/locales/zh-TW/CHANGELOG.md +54 -3
- package/bundled/locales/zh-TW/README.md +2 -2
- package/bundled/locales/zh-TW/SECURITY.md +1 -1
- package/bundled/locales/zh-TW/core/ai-response-navigation.md +110 -12
- package/bundled/locales/zh-TW/core/full-coverage-testing.md +61 -7
- package/bundled/locales/zh-TW/docs/CHEATSHEET.md +3 -1
- package/bundled/locales/zh-TW/docs/FEATURE-REFERENCE.md +8 -5
- package/bundled/locales/zh-TW/skills/README.md +1 -0
- package/bundled/locales/zh-TW/skills/comprehension-ladder/SKILL.md +289 -0
- package/bundled/locales/zh-TW/skills/comprehension-ladder/eval-cases.md +261 -0
- package/bundled/skills/README.md +1 -0
- package/bundled/skills/comprehension-ladder/SKILL.md +283 -0
- package/bundled/skills/comprehension-ladder/eval-cases.md +255 -0
- package/bundled/templates/gates/check-anti-fake-tests.mjs +991 -0
- package/bundled/templates/gates/check-stubs.mjs +644 -0
- package/package.json +3 -3
- package/src/commands/audit.js +11 -0
- package/src/commands/check.js +124 -24
- package/src/commands/init.js +45 -9
- package/src/commands/update.js +183 -21
- package/src/core/install-records.js +2 -1
- package/src/i18n/messages.js +50 -9
- package/src/installers/standards-installer.js +16 -23
- package/src/reconciler/backup-manager.js +418 -82
- package/src/reconciler/index.js +27 -5
- package/src/reconciler/install-roots.js +90 -0
- package/src/reconciler/plan-executor.js +33 -13
- package/src/uninstallers/hook-uninstaller.js +7 -4
- package/src/utils/command-hash-ownership.js +103 -0
- package/src/utils/copier.js +78 -1
- package/src/utils/gate-scripts.js +141 -0
- package/src/utils/git-hooks.js +8 -4
- package/src/utils/health-scorer.js +10 -7
- package/src/utils/locale.js +19 -0
- package/src/utils/skill-hash-ownership.js +64 -0
- package/src/utils/skills-installer.js +12 -1
- package/src/utils/test-change-check.js +160 -0
- package/src/utils/test-policy.js +214 -0
- package/src/utils/update-summary.js +29 -0
- package/standards-registry.json +21 -7
package/bin/uds.js
CHANGED
|
@@ -106,9 +106,13 @@ program
|
|
|
106
106
|
// Fallback to OS environment variable detection
|
|
107
107
|
setLanguage(detectLanguage(null));
|
|
108
108
|
})
|
|
109
|
-
.hook('postAction', async (thisCommand) => {
|
|
109
|
+
.hook('postAction', async (thisCommand, actionCommand) => {
|
|
110
110
|
const cmd = thisCommand.name();
|
|
111
111
|
if (!shouldCheckUpdateForCommand(cmd)) return;
|
|
112
|
+
// XSPEC-454 R3: --offline promises no network. This hook runs after every command and
|
|
113
|
+
// asks the npm registry for the latest version; it ignored the flag, so `check --offline`
|
|
114
|
+
// and `audit --offline` still made that request (whenever the terminal was interactive).
|
|
115
|
+
if (actionCommand?.opts?.().offline) return;
|
|
112
116
|
await printUpdateNoticeIfAvailable();
|
|
113
117
|
});
|
|
114
118
|
|
|
@@ -253,6 +257,8 @@ program
|
|
|
253
257
|
.option('--gh', 'Force gh CLI for submission')
|
|
254
258
|
.option('--format <format>', 'Output format (json)')
|
|
255
259
|
.option('--quiet', 'Summary only')
|
|
260
|
+
// XSPEC-454 R3: `check` and `update` already take --offline; `audit` rejected it with "unknown option".
|
|
261
|
+
.option('--offline', 'No network access at all: no CLI version check, and --report does not submit')
|
|
256
262
|
.option('--score', 'Run multi-dimensional health score analysis')
|
|
257
263
|
.option('--self', 'Self mode: analyze UDS repo itself (use with --score)')
|
|
258
264
|
.option('--save', 'Save score snapshot for trend tracking (use with --score)')
|
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
id: ai-response-navigation
|
|
5
5
|
meta:
|
|
6
|
-
version: "1.
|
|
7
|
-
updated: "2026-
|
|
6
|
+
version: "1.4.0"
|
|
7
|
+
updated: "2026-10-05"
|
|
8
8
|
source: core/ai-response-navigation.md
|
|
9
9
|
description: >
|
|
10
10
|
Every substantive AI response must include contextual next-step suggestions with recommended
|
|
11
11
|
options (rules 1-6, required). Optional rules 7-11 govern the answer itself: lead with the
|
|
12
12
|
finding, restate state across turns, no preamble, plain language as the subject, and a
|
|
13
|
-
trade-off on every option rather than only the recommended one.
|
|
13
|
+
trade-off on every option rather than only the recommended one. Rule 12 is controlled
|
|
14
|
+
language: one required clause (a simplified text keeps the writer's hedges, never turning
|
|
15
|
+
"might" into "is") and optional language-neutral plain-writing principles. It ships no
|
|
16
|
+
English dictionary.
|
|
14
17
|
|
|
15
18
|
rules:
|
|
16
19
|
- id: navigation-footer
|
|
@@ -127,6 +130,8 @@ rules:
|
|
|
127
130
|
Distinct from lead-with-the-finding: that rule orders finding before evidence, this one
|
|
128
131
|
governs register. A response can lead with its finding and still state that finding in
|
|
129
132
|
vocabulary only its author holds; both leave the reader unable to act.
|
|
133
|
+
Putting a claim in plain words is a rewrite, and a rewrite is where hedges get lost: when
|
|
134
|
+
the claim was hedged, keep-uncertainty-markers (rule 12.1, required) governs.
|
|
130
135
|
priority: optional
|
|
131
136
|
|
|
132
137
|
- id: every-option-carries-its-trade-off
|
|
@@ -143,6 +148,41 @@ rules:
|
|
|
143
148
|
costlier to read, so the 1-5 cap matters more, not less.
|
|
144
149
|
priority: optional
|
|
145
150
|
|
|
151
|
+
# ── Rule 12 (v1.4.0): controlled language, split into two entries ──
|
|
152
|
+
# One rule in the Markdown, two entries here because priority is one value per entry and the
|
|
153
|
+
# two halves are not the same strength. 12.1 is required: it is the only part whose failure makes
|
|
154
|
+
# the reader believe something untrue, and it needs no calibration (compare before and after).
|
|
155
|
+
# 12.2 is optional: its ranges are uncalibrated starting points with no checker, and a required
|
|
156
|
+
# rule with a threshold nobody can verify produces mechanical compliance.
|
|
157
|
+
# Takes the principles of ASD-STE100 and none of its English dictionary or tense rules.
|
|
158
|
+
|
|
159
|
+
- id: keep-uncertainty-markers
|
|
160
|
+
trigger: shortening, simplifying, rewriting or translating text for a reader who is not its author
|
|
161
|
+
instruction: >
|
|
162
|
+
Keep the writer's hedges (might, could, probably, appears to, not yet confirmed; 可能, 推斷,
|
|
163
|
+
大概, 尚未確認). Do NOT turn an uncertain claim into a certain one, do NOT drop a hedge to save
|
|
164
|
+
words, and do NOT add a fact the source did not state (an invented cause, an invented
|
|
165
|
+
"confirmed"). A shorter sentence is the goal; a more certain one is not allowed. A hedge may go
|
|
166
|
+
only when the claim has since been verified, and then the verification (what was checked, with
|
|
167
|
+
what result) takes its place; deleting the hedge alone is not verification.
|
|
168
|
+
priority: required
|
|
169
|
+
|
|
170
|
+
- id: controlled-language
|
|
171
|
+
trigger: writing for a non-specialist reader who has to judge or approve something from the text
|
|
172
|
+
instruction: >
|
|
173
|
+
Apply language-neutral plain-writing principles, each in the unit the language itself uses and
|
|
174
|
+
with no word list: (1) short sentences, one idea each, counted in the language's own unit —
|
|
175
|
+
as a starting range not a limit, roughly 15-25 words in English and 25-40 characters in
|
|
176
|
+
Chinese, calibrated per language and reader; (2) one name per thing for the whole text;
|
|
177
|
+
(3) a clear subject and the active voice, the passive only when the actor is unknown or
|
|
178
|
+
irrelevant; (4) one step, one action, as a numbered list; (5) few semicolons; (6) numbers carry
|
|
179
|
+
units. Do NOT use ASD-STE100's approved dictionary or tense restrictions: they depend on English
|
|
180
|
+
and do not apply to Chinese or other non-English text. Do NOT gauge non-English text with a
|
|
181
|
+
counter that splits on whitespace or ASCII; it reads a Chinese paragraph as one word and always
|
|
182
|
+
passes. Optional because the ranges are uncalibrated and unchecked; keep-uncertainty-markers is
|
|
183
|
+
the part that does not bend.
|
|
184
|
+
priority: optional
|
|
185
|
+
|
|
146
186
|
related_standards:
|
|
147
187
|
- ai-command-behavior
|
|
148
188
|
- ai-instruction-standards
|
|
@@ -12,7 +12,7 @@ standard:
|
|
|
12
12
|
- "Documentation: docs updated, CHANGELOG updated"
|
|
13
13
|
|
|
14
14
|
meta:
|
|
15
|
-
version: "2.2.
|
|
15
|
+
version: "2.2.1"
|
|
16
16
|
updated: "2026-07-09"
|
|
17
17
|
source: core/checkin-standards.md
|
|
18
18
|
description: Quality gates that must be passed before committing code
|
|
@@ -167,10 +167,29 @@ standard:
|
|
|
167
167
|
|
|
168
168
|
physical_spec:
|
|
169
169
|
type: custom_script
|
|
170
|
+
# Fail-closed (XSPEC-444 R1): a failing lint or test script fails this check.
|
|
171
|
+
# A script that is genuinely absent is reported (printed) and does not fail it —
|
|
172
|
+
# the hint is printed only for that case, never as a fallback for a failure.
|
|
173
|
+
# Inline Node keeps it portable (sh and cmd.exe) and lets it read package.json
|
|
174
|
+
# instead of guessing from exit codes. The npm-init placeholder test script
|
|
175
|
+
# ("no test specified") counts as absent. A package.json that exists but cannot
|
|
176
|
+
# be read fails the check. No package.json (not an npm project): hint, no failure.
|
|
170
177
|
validator:
|
|
171
178
|
command: >
|
|
172
|
-
|
|
173
|
-
(
|
|
174
|
-
(
|
|
175
|
-
|
|
176
|
-
|
|
179
|
+
node -e "
|
|
180
|
+
const fs=require('fs'),cp=require('child_process');
|
|
181
|
+
console.log('🔍 UDS Check-in Gates:');
|
|
182
|
+
let pkg;
|
|
183
|
+
try{pkg=JSON.parse(fs.readFileSync('package.json','utf8').replace(/^\uFEFF/,''))}
|
|
184
|
+
catch(e){if(e.code!=='ENOENT'){console.error('package.json cannot be read: '+e.message);process.exit(1)}}
|
|
185
|
+
if(pkg===undefined){console.log('ℹ️ No package.json - lint and tests were NOT run by this check (not an npm project)')}
|
|
186
|
+
else{const sc=(pkg&&pkg.scripts)||{};
|
|
187
|
+
for(const n of ['lint','test']){
|
|
188
|
+
const s=sc[n];
|
|
189
|
+
if(!s||(n==='test'&&/no test specified/.test(s))){console.log('ℹ️ No '+n+' script');continue}
|
|
190
|
+
const r=cp.spawnSync('npm run '+n,{stdio:'inherit',shell:true});
|
|
191
|
+
if(r.status!==0){console.error('FAILED: npm run '+n+' exited with '+r.status);process.exit(1)}
|
|
192
|
+
}}
|
|
193
|
+
if(!fs.existsSync('CHANGELOG.md'))console.log('ℹ️ No CHANGELOG.md');
|
|
194
|
+
"
|
|
195
|
+
rule: "checkin_gates_passed"
|
|
@@ -8,11 +8,11 @@ standard:
|
|
|
8
8
|
description: Behavior-completeness full coverage paradigm replacing pyramid thresholds. Enforces anti-fake-test rules, STUB marker protocol, ratchet CI, and @ac traceability.
|
|
9
9
|
|
|
10
10
|
meta:
|
|
11
|
-
version: "1.
|
|
12
|
-
updated: "2026-06
|
|
11
|
+
version: "1.2.0"
|
|
12
|
+
updated: "2026-10-06"
|
|
13
13
|
source: core/full-coverage-testing.md
|
|
14
14
|
replaces: "testing pyramid thresholds (UT≥80%/IT≥70%/E2E happy-path-only)"
|
|
15
|
-
xspec: "XSPEC-178"
|
|
15
|
+
xspec: "XSPEC-178, XSPEC-444"
|
|
16
16
|
description: AI-era full coverage paradigm — cost of writing tests equals cost of writing code, so there is no reason to set lower thresholds for any test layer.
|
|
17
17
|
|
|
18
18
|
rationale: |
|
|
@@ -180,6 +180,32 @@ standard:
|
|
|
180
180
|
trigger: '"// WARNING: STUB" marker found in src/'
|
|
181
181
|
message: "[STUB-WARN] STUB markers found. Must remove before merging to main."
|
|
182
182
|
|
|
183
|
+
# XSPEC-444 R2 + R5: what UDS itself ships so these rules are not only prose.
|
|
184
|
+
# Everything here WARNS by default; `mode: block` in the policy file tightens it.
|
|
185
|
+
shipped_gates:
|
|
186
|
+
default_mode: warn
|
|
187
|
+
policy_file: ".standards/test-policy.json" # optional; every list adds to the defaults
|
|
188
|
+
scripts: # written to scripts/ by `uds init`; never overwritten
|
|
189
|
+
- file: scripts/check-anti-fake-tests.mjs
|
|
190
|
+
finds: [no-assertion, tautology, all-skipped]
|
|
191
|
+
exit: "0 clean | 1 findings | 2 could not judge (never a pass)"
|
|
192
|
+
- file: scripts/check-stubs.mjs
|
|
193
|
+
finds: [stub-marker, not-implemented, empty-function]
|
|
194
|
+
exit: "0 clean | 1 findings | 2 could not judge (never a pass)"
|
|
195
|
+
pre_commit_checks: # run by `uds check` on what is staged
|
|
196
|
+
- id: code-without-test
|
|
197
|
+
finds: "code files changed and no test file changed in the same commit"
|
|
198
|
+
exempt: ["pure rename (git R100)", "policy exempt entry WITH a reason"]
|
|
199
|
+
- id: unclassified-file
|
|
200
|
+
finds: "a changed file of a type UDS does not recognise — listed, never assumed fine, never blocks"
|
|
201
|
+
language_coverage:
|
|
202
|
+
test_files: [javascript, typescript, python, java, kotlin, scala, csharp, go, rust, ruby, elixir, php, swift, dart, lua, cpp]
|
|
203
|
+
empty_function: [javascript, typescript, python, go, rust, ruby, php]
|
|
204
|
+
other_languages: "listed as NOT scanned — never counted as clean"
|
|
205
|
+
not_implemented_yet:
|
|
206
|
+
- "ratchet on the number of unpaired changes (spec does not define the baseline location or unit)"
|
|
207
|
+
- "per-commit exemption reason (a pre-commit hook cannot read the commit message)"
|
|
208
|
+
|
|
183
209
|
migration_from_pyramid:
|
|
184
210
|
deprecated:
|
|
185
211
|
- "UT ≥ 80% coverage threshold"
|
|
@@ -225,7 +251,22 @@ standard:
|
|
|
225
251
|
|
|
226
252
|
physical_spec:
|
|
227
253
|
type: custom_script
|
|
254
|
+
# XSPEC-444 R5: this used to check that two scripts EXIST — scripts UDS did not ship.
|
|
255
|
+
# Now it RUNS them (`uds check --standard full-coverage-testing`); a missing script,
|
|
256
|
+
# or a scanner that exits non-zero, fails the check. The scanners' findings go to stderr
|
|
257
|
+
# (`stdio: ['ignore', 2, 2]`) because a failing validator's stdout is not shown. Inline Node
|
|
258
|
+
# keeps it portable.
|
|
228
259
|
validator:
|
|
229
260
|
command: >
|
|
230
|
-
|
|
231
|
-
|
|
261
|
+
node -e "
|
|
262
|
+
const fs=require('fs'),cp=require('child_process');
|
|
263
|
+
let bad=0;
|
|
264
|
+
for(const f of ['check-anti-fake-tests.mjs','check-stubs.mjs']){
|
|
265
|
+
const p='scripts/'+f;
|
|
266
|
+
if(!fs.existsSync(p)){console.error('MISSING: '+p+' (uds update offers to write it)');bad=1;continue}
|
|
267
|
+
const r=cp.spawnSync(process.execPath,[p],{stdio:['ignore',2,2]});
|
|
268
|
+
if(r.status!==0){console.error('FAILED: '+p+' exited with '+r.status);bad=1}
|
|
269
|
+
}
|
|
270
|
+
process.exit(bad)
|
|
271
|
+
"
|
|
272
|
+
rule: "full_coverage_gate_scripts_clean"
|
|
@@ -81,5 +81,9 @@ integration_points:
|
|
|
81
81
|
physical_spec:
|
|
82
82
|
type: custom_script
|
|
83
83
|
validator:
|
|
84
|
-
|
|
84
|
+
# Fail-closed (XSPEC-444 R1 class sweep): the old form piped grep into `head -1`
|
|
85
|
+
# and fell back to `|| echo 'no-ci-pipeline'` — `head` always exits 0, so the
|
|
86
|
+
# check passed even when no pipeline mentioned any security gate. -q makes grep's
|
|
87
|
+
# own exit status the verdict: 0 only when a gate keyword is found.
|
|
88
|
+
command: "grep -rqE 'secrets|sast|sca|dast' .github/workflows/ .gitlab-ci.yml Jenkinsfile 2>/dev/null"
|
|
85
89
|
rule: "security_gates_in_pipeline"
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
> **Language**: English | [繁體中文](../locales/zh-TW/core/ai-response-navigation.md) | [简体中文](../locales/zh-CN/core/ai-response-navigation.md)
|
|
4
4
|
|
|
5
|
-
**Version**: 1.
|
|
6
|
-
**Last Updated**: 2026-
|
|
5
|
+
**Version**: 1.4.0
|
|
6
|
+
**Last Updated**: 2026-10-05
|
|
7
7
|
**Applicability**: All projects using AI-assisted development
|
|
8
8
|
**Scope**: universal
|
|
9
9
|
**Industry Standards**: None (Emerging AI tool practice)
|
|
@@ -19,12 +19,15 @@ This standard defines navigation behavior for AI responses: every substantive AI
|
|
|
19
19
|
|
|
20
20
|
**Solution**: A standard "Navigation Footer" appended to every substantive AI response, with contextual templates, recommendation marking, and adaptive option quantities.
|
|
21
21
|
|
|
22
|
-
**Scope note (v1.2.0, extended in 1.3.0)**: Rules 1–6 govern what comes *after* the answer.
|
|
23
|
-
Rules 7–
|
|
24
|
-
across turns (R8), no preamble (R9), plain language as the subject (R10),
|
|
25
|
-
option rather than only the recommended one (R11)
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
**Scope note (v1.2.0, extended in 1.3.0 and 1.4.0)**: Rules 1–6 govern what comes *after* the answer.
|
|
23
|
+
Rules 7–12 govern the answer itself: lead with the finding (R7), restate state
|
|
24
|
+
across turns (R8), no preamble (R9), plain language as the subject (R10), a trade-off on every
|
|
25
|
+
option rather than only the recommended one (R11), and controlled language (R12). Rules 7–11 are
|
|
26
|
+
**optional**. **Rule 12 is the one exception, and only in part**: its clause that a simplified text
|
|
27
|
+
must keep the writer's hedges is **required**; the rest of R12 is optional. They exist because a
|
|
28
|
+
response can satisfy every one of Rules 1–6 while burying its conclusion, stating it in vocabulary
|
|
29
|
+
only its author holds, listing options the reader still has to compare themselves, or being made
|
|
30
|
+
easy to read by being made more certain than the evidence.
|
|
28
31
|
|
|
29
32
|
---
|
|
30
33
|
|
|
@@ -104,11 +107,14 @@ Tier names are **vendor-neutral**. Each tool or platform maps these tiers to its
|
|
|
104
107
|
|
|
105
108
|
---
|
|
106
109
|
|
|
107
|
-
## The Answer Before the Navigation (Rules 7–
|
|
110
|
+
## The Answer Before the Navigation (Rules 7–12)
|
|
108
111
|
|
|
109
112
|
> **R7–R9 borrowed from**: [`ayghri/i-have-adhd`](https://github.com/ayghri/i-have-adhd) (MIT), 3 of its 10 rules.
|
|
110
113
|
> **R10–R11 added in 1.3.0** from a different source — a user telling the author, twice in one session,
|
|
111
114
|
> that a correct and complete answer was unreadable. R7–R9 had already shipped and were being followed.
|
|
115
|
+
> **R12 added in 1.4.0** from a third source: a public suggestion to ask an LLM to write at "about
|
|
116
|
+
> 80% of the way to" ASD-STE100, a controlled-English standard for technical documentation. Only its
|
|
117
|
+
> principles are taken; its English dictionary and tense rules are not (see Rule 12).
|
|
112
118
|
> The other 7 were dropped: 2 are already covered by Rules 1–2 above, and 5 either conflict with
|
|
113
119
|
> this standard (its "no recap / no closers" contradicts Rule 1's Navigation Footer; its
|
|
114
120
|
> "cap lists at 5" would truncate evidence tables and traversal denominators) or duplicate
|
|
@@ -119,10 +125,12 @@ itself — a response could bury its conclusion under a wall of evidence and sti
|
|
|
119
125
|
in this standard by appending a correct Navigation Footer. A reader who cannot find the answer is
|
|
120
126
|
not helped by being told what to do next.
|
|
121
127
|
|
|
122
|
-
**
|
|
128
|
+
**Rules 7–11 are optional**, in the same sense as Rule 6: adopting projects are not required
|
|
123
129
|
to enable them, and existing skills need no retroactive update. A project MAY promote any of them to
|
|
124
|
-
required in its own configuration.
|
|
125
|
-
|
|
130
|
+
required in its own configuration. **Rule 12 has one required clause** (12.1) and an optional rest
|
|
131
|
+
(12.2); the split is argued inside the rule. What is *not* optional anywhere is that every rule has
|
|
132
|
+
a precise trigger — a rule phrased so loosely that it never fires is indistinguishable from not
|
|
133
|
+
having the rule.
|
|
126
134
|
|
|
127
135
|
### Rule 7: Lead With the Finding, Not the Process (Optional)
|
|
128
136
|
|
|
@@ -187,6 +195,11 @@ It governs which of the two is the subject of the sentence.
|
|
|
187
195
|
response can lead with its finding and still state that finding in vocabulary only its author
|
|
188
196
|
holds. Both failures leave the reader unable to act; they are different failures.
|
|
189
197
|
|
|
198
|
+
**Plain wording must not buy its plainness with certainty.** Putting an explanation in the
|
|
199
|
+
reader's words is a rewrite, and a rewrite is exactly where "might" quietly becomes "is". When R10
|
|
200
|
+
is applied to a claim the writer had hedged, [Rule 12](#rule-12-controlled-language-partly-required)
|
|
201
|
+
clause 12.1 (required) governs: the hedge stays.
|
|
202
|
+
|
|
190
203
|
### Rule 11: Every Option Carries Its Own Trade-off (Optional)
|
|
191
204
|
|
|
192
205
|
**Trigger**: a response that asks the reader to choose between two or more courses of action.
|
|
@@ -214,6 +227,107 @@ worth stating, say so explicitly rather than leaving the column empty — an emp
|
|
|
214
227
|
**Composes with Rule 4**: the option count stays bounded (1–5). Trade-offs make each option
|
|
215
228
|
costlier to read, so this rule makes Rule 4's cap matter more, not less.
|
|
216
229
|
|
|
230
|
+
### Rule 12: Controlled Language (Partly Required)
|
|
231
|
+
|
|
232
|
+
**Trigger**: writing, rewriting, shortening, simplifying or translating text for a reader who is
|
|
233
|
+
not its author — typically a non-specialist who has to judge or approve something from it.
|
|
234
|
+
|
|
235
|
+
Controlled languages (writing rules that trade variety for predictability) make text easier to
|
|
236
|
+
read. They have a known way of failing: the easiest sentence to read is a confident one, so
|
|
237
|
+
"simplification" drifts toward certainty. This rule takes the principles of controlled writing and
|
|
238
|
+
puts a hard stop on that drift.
|
|
239
|
+
|
|
240
|
+
#### 12.1 A simplified text keeps its hedges (Required)
|
|
241
|
+
|
|
242
|
+
A hedge is a word that tells the reader how far to trust a claim: *might, could, probably,
|
|
243
|
+
appears to, not yet confirmed* — 可能、推斷、大概、尚未確認. It is information, not padding.
|
|
244
|
+
|
|
245
|
+
When you shorten, simplify, rewrite or translate:
|
|
246
|
+
|
|
247
|
+
- **Do not turn an uncertain claim into a certain one.** If the source says "might", the result
|
|
248
|
+
says "might" (or the equivalent in the language of the result).
|
|
249
|
+
- **Do not drop the hedge to save words.** A shorter sentence is the goal; a more certain one is
|
|
250
|
+
not allowed.
|
|
251
|
+
- **Do not add facts the source did not state** — an invented cause or an invented "confirmed" is
|
|
252
|
+
the same failure in another form.
|
|
253
|
+
- A hedge may go only when the claim has since been verified, and then the verification (what was
|
|
254
|
+
checked, with what result) takes its place. Deleting the hedge alone is not verification.
|
|
255
|
+
|
|
256
|
+
**Why this one is required and the rest are not**: it is the only part whose failure misleads the
|
|
257
|
+
reader about what is true, rather than only making the text harder to read. It also needs no
|
|
258
|
+
calibration — the check is a comparison of the text before and after, which a person or a model
|
|
259
|
+
can do in any language — whereas every threshold below depends on language and audience.
|
|
260
|
+
|
|
261
|
+
#### 12.2 Plain-writing principles (Optional)
|
|
262
|
+
|
|
263
|
+
Apply these when the reader is a non-specialist. They are language-neutral: each is stated in the
|
|
264
|
+
unit the language itself uses, with no word list.
|
|
265
|
+
|
|
266
|
+
| Principle | What it asks for |
|
|
267
|
+
|-----------|------------------|
|
|
268
|
+
| **Short sentences, counted in the language's own unit** | One idea per sentence. As a *starting range*, not a limit: roughly 15–25 words in English, roughly 25–40 characters in Chinese. A sentence far beyond the range is a signal to split it, not a defect to count. Calibrate per language and per reader |
|
|
269
|
+
| **One thing, one name** | Pick one name for each thing and use it for the whole text. Do not vary it for style: a reader who sees a second name assumes a second thing |
|
|
270
|
+
| **A clear subject and the active voice** | Say who does what. The passive is acceptable when the actor is unknown or does not matter |
|
|
271
|
+
| **One step, one action** | A procedure is a numbered list with one action per item, not a paragraph |
|
|
272
|
+
| **Few semicolons** | A semicolon joins two ideas the reader must hold at once. Split into two sentences or a list |
|
|
273
|
+
| **Numbers carry units** | "30 seconds", "3 files", "NT$1,200" — never a bare "30" |
|
|
274
|
+
|
|
275
|
+
**Why optional**: the ranges above are starting points that have not been calibrated against
|
|
276
|
+
reader outcomes, and no checker enforces them. A *required* rule with a threshold nobody can
|
|
277
|
+
verify produces mechanical compliance — sentences split until they stop reading as sentences —
|
|
278
|
+
and an expert reader may be better served by denser text. These principles are guidance a writer
|
|
279
|
+
applies with judgment; 12.1 is the part that does not bend.
|
|
280
|
+
|
|
281
|
+
#### What this rule does not take from ASD-STE100
|
|
282
|
+
|
|
283
|
+
ASD-STE100's **approved dictionary** (one meaning per approved English word, with a closed list
|
|
284
|
+
of allowed words) and its **tense restrictions** depend on the English language. They do not apply
|
|
285
|
+
to Chinese or to other non-English text, and this standard ships **no word list of any kind**.
|
|
286
|
+
Only the principles in 12.2 are taken, restated so that each can be applied in any language.
|
|
287
|
+
|
|
288
|
+
For the same reason, do not use a counter that splits on whitespace or ASCII characters to gauge
|
|
289
|
+
non-English text: it reads a Chinese paragraph as one "word" and passes it however long it is. A
|
|
290
|
+
gauge that is always green on a language measures nothing in that language.
|
|
291
|
+
|
|
292
|
+
#### Example: one passage, three rewrites, and one that is not allowed
|
|
293
|
+
|
|
294
|
+
The example is in Chinese on purpose: the rule is language-neutral, and Chinese is where an
|
|
295
|
+
English-only approach does not carry over. The three valid versions keep the hedges 可能 (might),
|
|
296
|
+
推斷 (inferred) and 尚未 (not yet) and add no fact the original lacks.
|
|
297
|
+
|
|
298
|
+
**Original**
|
|
299
|
+
|
|
300
|
+
```text
|
|
301
|
+
經過檢查,登入頁面在高流量時段回應變慢,這個問題可能是資料庫連線池被耗盡所造成的,我們推斷是因為上週的改版新增了一個會長時間佔用連線的查詢;目前尚未在測試環境重現,所以修復後的效果還需要被確認,建議在確認之前先不要對外宣布已經解決。
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**About 80%** — shorter sentences, still reads as prose
|
|
305
|
+
|
|
306
|
+
```text
|
|
307
|
+
登入頁面在高流量時段回應變慢。原因可能是資料庫連線池被耗盡。我們推斷,上週改版新增了一個查詢,它會長時間佔用連線。這一點尚未在測試環境重現,修復後有沒有效,也還沒確認。確認之前,建議先不要對外宣布已經解決。
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Strict** — one idea per line, labelled, hedges kept
|
|
311
|
+
|
|
312
|
+
```text
|
|
313
|
+
登入頁面在高流量時段回應變慢。
|
|
314
|
+
1. 原因:可能是資料庫連線池被耗盡。
|
|
315
|
+
2. 推斷:上週改版新增了一個查詢,這個查詢可能長時間佔用連線。
|
|
316
|
+
3. 狀態:尚未在測試環境重現。
|
|
317
|
+
4. 修復效果:尚未確認。
|
|
318
|
+
5. 建議:確認之前,不要對外宣布已解決。
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**Not a valid rewrite** — shortest of all, and wrong
|
|
322
|
+
|
|
323
|
+
```text
|
|
324
|
+
登入頁面變慢,原因是資料庫連線池被耗盡,已確認由上週改版造成。
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
The last version is the shortest and the easiest to read, and it fails 12.1 twice: "可能" became
|
|
328
|
+
a flat statement of cause, and "尚未重現" became "已確認" (confirmed), a fact the original never
|
|
329
|
+
stated. A reader who approves a fix on the strength of it has been given something untrue.
|
|
330
|
+
|
|
217
331
|
---
|
|
218
332
|
|
|
219
333
|
## Contextual Templates
|
|
@@ -408,6 +522,7 @@ Each tool's integration layer is responsible for rendering the Navigation Footer
|
|
|
408
522
|
| R9 | *(Optional)* No preamble. Closers still required — see R1 |
|
|
409
523
|
| R10 | *(Optional)* Plain language is the subject; identifiers support it, after the claim |
|
|
410
524
|
| R11 | *(Optional)* Every option states what it buys and costs — not only the recommended one |
|
|
525
|
+
| R12 | **12.1 *(Required)***: when simplifying, shortening or translating, keep the hedges — never turn "might" into "is". 12.2 *(Optional)*: short sentences in the language's own unit, one name per thing, active voice, one action per step, few semicolons, numbers with units. No English dictionary — it does not carry to other languages |
|
|
411
526
|
|
|
412
527
|
| Exempt | Not Exempt |
|
|
413
528
|
|--------|------------|
|
|
@@ -431,6 +546,7 @@ Each tool's integration layer is responsible for rendering the Navigation Footer
|
|
|
431
546
|
|
|
432
547
|
| Version | Date | Changes |
|
|
433
548
|
|---------|------|---------|
|
|
549
|
+
| 1.4.0 | 2026-10-05 | Add R12, controlled language, language-neutral. One clause is required (12.1: a simplified text keeps the writer's hedges — "might" does not become "is" and no unstated fact is added); the rest (12.2: sentence length in the language's own unit, one name per thing, active voice, one action per step, few semicolons, numbers with units) is optional, with the reason recorded. Takes the principles of ASD-STE100 and none of its English dictionary or tense rules, and says so in the standard. Ships a Chinese before/after example in three strictness levels plus one rewrite that is shorter and wrong. R10 now points to R12, because putting a claim in plain words is a rewrite and a rewrite is where hedges get lost |
|
|
434
550
|
| 1.3.0 | 2026-08-17 | Add optional R10–R11. R10 governs register: plain language is the subject of the sentence and identifiers support it — distinct from R7, which orders finding before evidence, because a response can lead with its finding and still state it in vocabulary only its author holds. R11 extends Rule 2 from the recommended option to all of them: a list where only the recommendation is argued hands the comparison back to the reader, and an option shown without its cost reads as having none |
|
|
435
551
|
| 1.2.0 | 2026-08-17 | Add optional R7–R9 governing the answer itself (lead with the finding, restate state, no preamble). Borrowed from `ayghri/i-have-adhd` (MIT), 3 of its 10 rules; the other 7 were dropped as duplicated by R1–R2, in conflict with R1, or covered by estimation-standards. Rules 1–6 could all be satisfied by a response that buries its conclusion — R7–R9 close that |
|
|
436
552
|
| 1.1.0 | 2026-06-10 | Add R6 optional model tier annotation (`〔model: Fast\|Standard\|Capable〕`); vendor-neutral; no forced changes to existing skills |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Full Coverage Testing Standards
|
|
2
2
|
|
|
3
3
|
> **AI-optimized version**: `ai/standards/full-coverage-testing.ai.yaml`
|
|
4
|
-
> **XSPEC**: XSPEC-178
|
|
4
|
+
> **XSPEC**: XSPEC-178, XSPEC-444 (R2, R5 — pre-commit warnings and shipped gate scripts)
|
|
5
5
|
> **Replaces**: Pyramid threshold model (UT≥80%, IT≥70%, E2E happy-path-only)
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
@@ -228,6 +228,60 @@ Axis ⑨ is satisfied when this section declares all three: **derive** (Step 1 m
|
|
|
228
228
|
|
|
229
229
|
---
|
|
230
230
|
|
|
231
|
+
## Pre-commit Warnings and Gate Scripts Shipped by UDS (XSPEC-444 R2, R5)
|
|
232
|
+
|
|
233
|
+
The rules above used to depend on scripts the standard told you to write yourself. `uds init` now writes the scanners for you, and `uds check` — the command UDS's pre-commit hook runs — prints what they and one more check find. **All of it warns by default and blocks nothing**; tightening is opt-in (see "Warn first, tighten later").
|
|
234
|
+
|
|
235
|
+
### The two scanners (`uds init` writes them to `scripts/`)
|
|
236
|
+
|
|
237
|
+
| Script | Finds |
|
|
238
|
+
|--------|-------|
|
|
239
|
+
| `scripts/check-anti-fake-tests.mjs` | a test with **no assertion**; a test whose only assertions are **tautologies** (`expect(true).toBe(true)`, `assert 200 == 200`); a test file in which **every test is skipped or todo** |
|
|
240
|
+
| `scripts/check-stubs.mjs` | `// WARNING: STUB` markers; a body that says it is **not implemented** (`raise NotImplementedError`, `todo!()`, `TODO()` ...) with no marker beside it; a named function whose body is **empty** with no marker beside it |
|
|
241
|
+
|
|
242
|
+
- Pure Node, no dependencies, no test framework assumed. They are **your files**: edit them, wire them into CI. Run on its own, each exits non-zero when it finds something — `node scripts/check-stubs.mjs` is the pre-push/deploy gate this standard's deployment gates describe.
|
|
243
|
+
- `uds init` never overwrites a file that exists, and `uds update` never overwrites one either; for a project initialised earlier, `uds update` offers to write them (the prompt defaults to no; `uds update -y` answers it yes).
|
|
244
|
+
- With files staged they read only those files; with nothing staged (a CI run, a manual `uds check`) each walks the whole project — the walk stops at 200,000 files, and `uds check` gives each scanner 120 seconds (past that it reports "could not judge", never a pass) — so in a very large repository run them in CI rather than expecting them to be instant.
|
|
245
|
+
- A placeholder is *declared* by `STUB` or `COVERAGE_EXEMPT` on its line or the three above; a declared placeholder is reported once, as its marker.
|
|
246
|
+
- **Languages.** Test-file rules exist for JavaScript/TypeScript, Python, Java/Kotlin/Scala/C#, Go, Rust, Ruby, Elixir, PHP, Swift, Dart, Lua and C/C++. A test file in any **other** language is listed as "NOT scanned" — never counted as clean. Empty-function rules exist for JavaScript/TypeScript, Python, Go, Rust, Ruby and PHP; elsewhere markers and "not implemented" bodies are still found and the output says which languages had no empty-function rule.
|
|
247
|
+
- They read text; they do not run your tests. A helper that asserts under a name the scanner cannot recognise is reported as "no-assertion": name it `assert*` / `verify*` / `expect*`, or list its pattern under `assertionPatterns` in the policy file.
|
|
248
|
+
- Each run first checks itself against known fakes and known good tests; if that fails it exits `2` ("could not judge"), which is never a pass.
|
|
249
|
+
|
|
250
|
+
### Code changed without a test (`uds check`, on staged changes)
|
|
251
|
+
|
|
252
|
+
When files are staged for commit, `uds check` compares what changed:
|
|
253
|
+
|
|
254
|
+
- code files changed and **no test file** changed in the same commit → a warning that lists the code files;
|
|
255
|
+
- a changed file of a type UDS does not recognise → a warning that lists it and says how to classify it (never assumed fine, never blocks);
|
|
256
|
+
- a deletion is not a change that needs a test; a **pure rename** (git's `R100`) and a path matching an `exempt` entry are exempt, and the output records the reason.
|
|
257
|
+
|
|
258
|
+
With nothing staged (a CI run, a manual `uds check`) the diff check says nothing; the two scanners then look at the whole project.
|
|
259
|
+
|
|
260
|
+
### The policy file `.standards/test-policy.json` (optional)
|
|
261
|
+
|
|
262
|
+
Which paths are tests and which are code is data with defaults for the common ecosystems, not a list of frameworks. Every list **adds to** the defaults:
|
|
263
|
+
|
|
264
|
+
```json
|
|
265
|
+
{
|
|
266
|
+
"mode": "warn",
|
|
267
|
+
"testDirs": ["integration"],
|
|
268
|
+
"testPatterns": ["*.itest.*"],
|
|
269
|
+
"sourceExtensions": ["zig"],
|
|
270
|
+
"nonCodeExtensions": ["gradle"],
|
|
271
|
+
"ignore": ["generated/**"],
|
|
272
|
+
"exempt": [{ "pattern": "src/gen/**", "reason": "generated by protoc" }],
|
|
273
|
+
"assertionPatterns": ["\\bmustMatch\\w*\\s*\\("]
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
An `exempt` entry without a `reason` is not honored and is reported: an exemption must say why.
|
|
278
|
+
|
|
279
|
+
### Warn first, tighten later
|
|
280
|
+
|
|
281
|
+
`"mode": "warn"` (the default) prints and lets the commit through. `"mode": "block"` makes `uds check` exit non-zero — and so stops the commit — when a scanner finds something, a scanner cannot judge, or code changed without a test. A file type UDS does not recognise never blocks. **Not implemented yet** (the specification does not say where a baseline would live or what it counts): a ratchet on the number of unpaired changes, and a per-commit exemption reason (a pre-commit hook cannot read the commit message).
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
231
285
|
## Migration from Pyramid Model
|
|
232
286
|
|
|
233
287
|
If your project previously used pyramid thresholds:
|
|
@@ -235,8 +289,8 @@ If your project previously used pyramid thresholds:
|
|
|
235
289
|
1. **Delete** any hardcoded coverage thresholds from `jest.config.js` / `vitest.config.ts` (`coverageThreshold` option)
|
|
236
290
|
2. **Install** `.coverage-baseline.json` with current coverage as the starting ratchet
|
|
237
291
|
3. **Add** `scripts/check-coverage-ratchet.sh` to CI
|
|
238
|
-
4. **Add** `scripts/check-stubs.
|
|
239
|
-
5. **Add** `scripts/check-anti-fake-tests.
|
|
292
|
+
4. **Add** `scripts/check-stubs.mjs` to deploy.sh and pre-push hook (written by `uds init`; `uds update` offers it to an existing project)
|
|
293
|
+
5. **Add** `scripts/check-anti-fake-tests.mjs` to pre-commit or CI (written by `uds init`; `uds check` already runs it and warns)
|
|
240
294
|
|
|
241
295
|
The ratchet starts at your current coverage. From that point on, it can only increase.
|
|
242
296
|
|