genesis-compiler 1.10.10 → 1.10.12
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/README.md +46 -16
- package/package.json +2 -2
- package/plugins/genesis/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/project-guidance.js +6 -5
- package/profiles/engineering/baseline.md +8 -2
- package/prompts/deslop.txt +3 -2
- package/prompts/review.txt +12 -5
- package/skills/genesis-deslop/SKILL.md +10 -2
- package/skills/genesis-project/SKILL.md +11 -8
- package/skills/genesis-project/references/sanity-checks.md +352 -0
- package/src/cli-commands.js +193 -0
- package/src/cli.js +18 -190
- package/src/index/agent-skills.js +26 -5
- package/src/index/environment-files.js +3 -2
- package/src/index/git.js +17 -1
- package/src/index/host-context.js +70 -0
- package/src/index/process.js +1 -0
- package/src/index/program.js +7 -2
- package/src/index/project-files.js +2 -2
- package/src/index/project-format.js +3 -4
- package/src/index/project-inspection.js +33 -11
- package/src/index/session-context.js +6 -67
- package/src/index/stack-catalog.js +29 -1
- package/src/index/stack-section-inspection.js +2 -16
- package/src/index/template-source.js +45 -10
package/README.md
CHANGED
|
@@ -363,16 +363,34 @@ allowed. When a concrete requirement makes material complexity necessary, the
|
|
|
363
363
|
agent must explain why a direct design is insufficient and ask before writing
|
|
364
364
|
that complexity.
|
|
365
365
|
|
|
366
|
-
The same baseline keeps what the software builds fast as it
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
366
|
+
The same baseline keeps what the software builds fast and correct as it
|
|
367
|
+
grows, through checks the agent makes and judges rather than numbers it must
|
|
368
|
+
hit. A request, job or test costs in proportion to the rows it handles, never
|
|
369
|
+
to stored history: the agent counts a list's, batch's or write's queries at a
|
|
370
|
+
few rows and at a realistic number and finds what grows with the rows. Tests
|
|
371
|
+
take the time their work needs: the agent reads the suite's time and its
|
|
372
|
+
slowest files and fixes where the time goes, prepares test databases once per
|
|
373
|
+
run (usually from a stored snapshot checked by a digest, with the full
|
|
374
|
+
migration history replayed only by one separate fresh-schema check), and keeps
|
|
375
|
+
each test file independent so files run in parallel and two identical runs
|
|
376
|
+
agree. A refactor lists the behaviors and tests before changing code and walks
|
|
377
|
+
the list again afterwards.
|
|
378
|
+
A failing test is a defect to explain, never noise to rerun, skip or call
|
|
379
|
+
pre-existing, and a final run is one whole run of the pushed tree. Each declared
|
|
380
|
+
constraint and protection is tried with one input that breaks it, access comes
|
|
381
|
+
from the trusted context, and a change others depend on fails loudly where the
|
|
382
|
+
old shape is still used. A short list names what is wrong in any context, such
|
|
383
|
+
as a silently capped read, an edited migration that has run, an edited
|
|
384
|
+
generated file, or tests against a real database. A time limit catches a hang;
|
|
385
|
+
a slow check is measured and its cause fixed, never hidden by a longer limit,
|
|
386
|
+
retries or smaller data. Coarse outer limits, such as a list making hundreds of
|
|
387
|
+
queries or a suite running for hours, mark what is clearly broken; they are not
|
|
388
|
+
targets. The baseline is the short form: the genesis-project skill's sanity
|
|
389
|
+
checks guide (`references/sanity-checks.md`) gives each check's examples and
|
|
390
|
+
outer limits and is read before the agent reports such work done, and each
|
|
391
|
+
Stack piece's "Sanity checks with <stack>" guidance names the stack's own tools
|
|
392
|
+
for them, such as its query counter, parallel test runner and strict loading
|
|
393
|
+
mode.
|
|
376
394
|
|
|
377
395
|
The installed, versioned profile descriptions live in
|
|
378
396
|
`profiles/engineering/*.md`. Straight Genesis users can inspect and select them
|
|
@@ -973,9 +991,15 @@ ordinary project operations stop until the migration is resolved.
|
|
|
973
991
|
## Development
|
|
974
992
|
|
|
975
993
|
Run `npm ci` in this source checkout, then `npm test`. The test command runs the
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
994
|
+
test files in parallel at Node's default file concurrency; each file creates its
|
|
995
|
+
own temporary projects and directories, so it can run beside any other. The
|
|
996
|
+
suite is kept cheap by what it runs rather than by how many cores share it: a
|
|
997
|
+
test about command logic calls the CLI's own `runCli` in its process, each
|
|
998
|
+
command keeps one real `genesis` run, test projects copy one prepared empty Git
|
|
999
|
+
repository, and the template tests copy one prepared starter instead of
|
|
1000
|
+
rebuilding it. The local first-party catalogue is a development-only dependency
|
|
1001
|
+
so catalogue and starter tests work after a clean install; it is not required by
|
|
1002
|
+
the published compiler runtime.
|
|
979
1003
|
|
|
980
1004
|
## Public API
|
|
981
1005
|
|
|
@@ -1028,10 +1052,12 @@ The CLI can also prepare and verify parsers for an offline host; see
|
|
|
1028
1052
|
[language parser management](docs/parsers.md).
|
|
1029
1053
|
`migrate()` updates recognized older Genesis project-file formats and returns
|
|
1030
1054
|
the resulting structural check for hosts.
|
|
1031
|
-
`inspectProjectFormat({ projectRoot })` returns only the format marker's `path`,
|
|
1055
|
+
`inspectProjectFormat({ projectRoot, rootMode })` returns only the format marker's `path`,
|
|
1032
1056
|
`status`, `projectVersion`, `supportedVersion`, `action`, and diagnostic when
|
|
1033
|
-
invalid.
|
|
1057
|
+
invalid. By default it retains Git repository discovery and trust checks, but does not
|
|
1034
1058
|
enumerate application files, load Stack catalogs, or inspect project guidance.
|
|
1059
|
+
`rootMode: "directory"` reads an explicit absolute directory without Git, as for
|
|
1060
|
+
Stack sections below.
|
|
1035
1061
|
Missing markers distinguish uninitialized projects from unversioned Genesis
|
|
1036
1062
|
material. Each call reads current state; it neither migrates nor writes files.
|
|
1037
1063
|
`adoptProject()` also returns the initial `adopt` prompt for an existing
|
|
@@ -1092,7 +1118,11 @@ hosts may pass `rootMode: "directory"` and an explicit absolute `projectRoot`.
|
|
|
1092
1118
|
This reads that exact directory, including when it sits inside another Git
|
|
1093
1119
|
repository. It retains the same Stack validation and performs no writes or
|
|
1094
1120
|
commands. Missing/invalid roots fail; this is never an automatic fallback from
|
|
1095
|
-
Git ownership or discovery errors.
|
|
1121
|
+
Git ownership or discovery errors. `inspectEnvironment()` and
|
|
1122
|
+
`inspectProjectFormat()` accept the same `rootMode` with the same rules. A host
|
|
1123
|
+
that already knows the project root and inspects it on every request, such as a
|
|
1124
|
+
preview status poll, can pass `rootMode: "directory"` to all three and start no
|
|
1125
|
+
Git process.
|
|
1096
1126
|
|
|
1097
1127
|
`inspectStackSections({ names, projectRoot, rootMode, stackPackages })` returns
|
|
1098
1128
|
an array of those same section results in the requested order. Names must be
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genesis-compiler",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "An agent-independent prompt, multi-language code-index, cleanup, and verification companion with project agent guidance.",
|
|
6
6
|
"repository": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"docs/parsers.md"
|
|
49
49
|
],
|
|
50
50
|
"scripts": {
|
|
51
|
-
"test": "node --test
|
|
51
|
+
"test": "node --test test/*.test.js"
|
|
52
52
|
},
|
|
53
53
|
"jskitRelease": {
|
|
54
54
|
"versionFiles": [
|
|
@@ -6,11 +6,11 @@ import { promisify } from "node:util";
|
|
|
6
6
|
const execute = promisify(execFile);
|
|
7
7
|
|
|
8
8
|
const HOST_CONTEXT_INPUT_ENV = "GENESIS_HOST_CONTEXT_INPUT";
|
|
9
|
+
const HOOK_TIMEOUT_MS = 5_000;
|
|
9
10
|
|
|
10
|
-
async function renderContext(projectRoot, sessionId, scope, parentSessionIds = []) {
|
|
11
|
+
async function renderContext(projectRoot, sessionId, scope, parentSessionIds = [], timeoutMs = HOOK_TIMEOUT_MS) {
|
|
11
12
|
if (scope === "turn" && process.env.GENESIS_TURN_CONTEXT_ENABLED === "0") return "";
|
|
12
13
|
const started = Date.now();
|
|
13
|
-
const timeoutMs = 5_000;
|
|
14
14
|
try {
|
|
15
15
|
const { stdout } = await execute(
|
|
16
16
|
"genesis",
|
|
@@ -54,7 +54,8 @@ function eventSessionId(event = {}) {
|
|
|
54
54
|
).trim();
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
// OpenCode passes no hookTimeoutMs, so its hooks get five seconds; a test passes a shorter deadline to prove it.
|
|
58
|
+
export const GenesisProjectGuidance = async ({ client, directory, worktree, hookTimeoutMs = HOOK_TIMEOUT_MS } = {}) => {
|
|
58
59
|
const projectRoot = path.resolve(directory || worktree || process.cwd());
|
|
59
60
|
const contexts = new Map();
|
|
60
61
|
const turnContexts = new Map();
|
|
@@ -72,7 +73,7 @@ export const GenesisProjectGuidance = async ({ client, directory, worktree } = {
|
|
|
72
73
|
if (!id || id === sessionId || parents.includes(id)) break;
|
|
73
74
|
parents.push(id);
|
|
74
75
|
}
|
|
75
|
-
return renderContext(projectRoot, sessionId, "session", parents);
|
|
76
|
+
return renderContext(projectRoot, sessionId, "session", parents, hookTimeoutMs);
|
|
76
77
|
});
|
|
77
78
|
contexts.set(sessionId, context);
|
|
78
79
|
context.catch(() => {
|
|
@@ -108,7 +109,7 @@ export const GenesisProjectGuidance = async ({ client, directory, worktree } = {
|
|
|
108
109
|
if (!sessionId || !messageId || !Array.isArray(message.parts)) return;
|
|
109
110
|
let current = turnContexts.get(sessionId);
|
|
110
111
|
if (current?.messageId !== messageId) {
|
|
111
|
-
current = { messageId, context: renderContext(projectRoot, sessionId, "turn") };
|
|
112
|
+
current = { messageId, context: renderContext(projectRoot, sessionId, "turn", [], hookTimeoutMs) };
|
|
112
113
|
turnContexts.set(sessionId, current);
|
|
113
114
|
current.context.catch(() => {
|
|
114
115
|
if (turnContexts.get(sessionId) === current) turnContexts.delete(sessionId);
|
|
@@ -4,9 +4,15 @@
|
|
|
4
4
|
- Prefer direct control flow, existing ownership boundaries, and established project or technology seams.
|
|
5
5
|
- Do not overengineer or overcomplicate the solution. Do not add speculative abstractions, layers, dependencies, infrastructure, compatibility paths, distributed patterns, cryptography, enterprise patterns, or other advanced machinery unless an explicit requirement or a concrete constraint makes it necessary.
|
|
6
6
|
- If good software requires material complexity beyond these rules, stop before writing it. Explain the requirement, why the direct design is insufficient, and the smallest added complexity proposed, then ask the user to approve or clarify the tradeoff.
|
|
7
|
-
-
|
|
8
|
-
- Give
|
|
7
|
+
- A request, job or test costs what the rows it handles cost, never what stored history or the whole dataset costs; this is the direct design, not speculative scale work. Check it instead of assuming it: count a list's, batch's or write's queries or storage calls at a few rows and at a realistic number, and judge whether the count follows the pages read or grows with the rows. A count that grows usually means a read, lookup or access check runs per row, or an access check is sized by stored history; related rows come in batches, one query per related table, and every visibility check is bounded by the rows being read. A list that makes hundreds of queries, or a save that takes tens of seconds, is broken: find the cause first. Such limits mark what is clearly broken; they are not targets, and code is never bent to reach a number.
|
|
8
|
+
- Give list, batch and write paths a test at realistic row counts and history, since a handful of rows hides per-row work; it compares counts at two sizes rather than holding a fixed ceiling tuned until it passes. Tests take the time their work needs, no more: read the suite's total time and its slowest files, and find where a slow file's time goes (database preparation, replayed migrations, fixed sleeps, polling, server or build starts). Prepare databases and shared fixtures once per run and reuse them, usually from a stored schema and seed snapshot checked by a digest of their sources rather than by replaying migrations, and keep the full-history migration proof as one separate check. Each test file owns its data, ports and files, never touches a development or production database, and can run beside any other, so two identical runs give the same result; files run in parallel within the machine's test budget, and a suite whose wall time is close to the sum of its files' times ran them one at a time, so find why. A suite that runs for hours, or test preparation measured in minutes, is broken.
|
|
9
|
+
- A refactor, consolidation or move keeps every behavior, or drops one only with the person's agreement. Before changing code, list what it does (its operations, inputs and their validation, permissions, states and edge cases) with the test covering each, adding one where none does; afterwards walk the list again, with the original tests passing and their assertions unchanged. A change that deletes tests or weakens their assertions is not a refactor.
|
|
10
|
+
- A failing test is a defect to explain, in the product or in the test, never noise or a "pre-existing" baseline: do not rerun it until it passes, skip it or loosen it to finish. A final run is one run of the whole suite on the tree that is pushed; reruns, chunks and partial runs are reported as partial. A skipped test records its reason and the run that does cover it. A new test is seen to fail once, by breaking the behavior or reverting the fix.
|
|
11
|
+
- Every constraint and protection the code declares is enforced: send one input that breaks each (a missing required field, a call past a rate limit, a caller without permission, another tenant's id) and see it refused. Authorization is decided before validation answers, from the trusted context rather than ids the client sends, and a missing value, scope or collaborator refuses instead of allowing.
|
|
12
|
+
- A change that other code depends on (a name, a default, a contract) fails loudly, naming its fix, wherever the old shape is still used, and every dependent project is booted and checked with it.
|
|
13
|
+
- Never, whatever the context: cap a read its callers treat as complete; drop a behavior, rule or access decision silently; declare a constraint or protection that nothing enforces; let a client's ids or a missing value decide access; store a missing value as a real one; run tests against a developer's or production database or configuration; edit a migration that has run anywhere; edit a generated file instead of its source; let the first visitor to a new deployment own it; run production with development settings; release a test's servers, processes or timers only where a timeout skips it. Each one silently loses data, protection or a whole run.
|
|
9
14
|
- During implementation, run the relevant checks and batch related cases when they share setup. Follow the project's verification policy for broad or final checks; do not repeat them merely because an item finishes or a session resumes. Preserve required coverage and isolation.
|
|
10
15
|
- Bound each long check by a time limit so it ends even when it hangs; write its complete output to a local file and preserve its exit status. Afterwards read concise counts, timings and actionable failure excerpts first, expanding evidence only when needed; never load full passing reports into agent context. Retain startup and cleanup failures; retry only after a change or new evidence justifies it.
|
|
11
16
|
- A time limit catches a hang; it does not fix slowness. When a check, test or request is slower than its work needs, measure where the time goes and fix the cause; never raise a time limit, add retries, repeat a call or shrink realistic data or coverage to make it pass.
|
|
12
17
|
- For browser verification, batch related actions and return only the relevant values or page region. Capture screenshots at meaningful visual checkpoints or failures, not after every action. Preserve required viewport, identity and security coverage; prefer existing automated cases for repeated checks.
|
|
18
|
+
- These are the short form. Genesis's sanity checks guide (`.agents/skills/genesis-project/references/sanity-checks.md`) gives each check's examples and outer limits: read the section that applies before reporting data access, tests, a refactor, a screen or a release done, and apply it with the tools your Stack pieces name.
|
package/prompts/deslop.txt
CHANGED
|
@@ -16,5 +16,6 @@ addition to the Genesis Deslop contract. Stack guidance may improve
|
|
|
16
16
|
technology-specific cleanup, but it cannot broaden the resolved scope,
|
|
17
17
|
weaken behavior preservation, or turn this into another implementation pass.
|
|
18
18
|
|
|
19
|
-
Report the resolved scope, what became simpler,
|
|
20
|
-
run, and any defect or gap
|
|
19
|
+
Report the resolved scope, what became simpler, the behaviors checked before
|
|
20
|
+
and after, files changed, checks actually run, and any defect or gap
|
|
21
|
+
deliberately left for follow-up.
|
package/prompts/review.txt
CHANGED
|
@@ -8,11 +8,18 @@ directions. Identify missing or contradictory behavior, misleading explanation,
|
|
|
8
8
|
unnecessarily difficult public shape, and verification gaps. Distinguish direct
|
|
9
9
|
evidence from inference and state questions that require human intent.
|
|
10
10
|
|
|
11
|
-
Report what makes requests or tests slower than their work
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
Report what makes requests or tests slower than their work, citing a count or
|
|
12
|
+
timing where one exists and the code path otherwise: a list or batch whose
|
|
13
|
+
query count grows with its rows, an access check whose cost grows with stored
|
|
14
|
+
history, a list, batch or write path never tested at realistic counts, test
|
|
15
|
+
preparation that replays the migration history, tests that share drifting data
|
|
16
|
+
or cannot run in parallel, and a time limit raised to absorb slowness. Report
|
|
17
|
+
behavior a refactor dropped: operations, validation, permissions or edge cases
|
|
18
|
+
the earlier code had and the current code lacks, and tests deleted or weakened
|
|
19
|
+
with it. Report declared constraints and protections that nothing enforces, and
|
|
20
|
+
access decided from ids the client sends rather than the trusted context.
|
|
21
|
+
Judge each against the matching section and outer limit of
|
|
22
|
+
`.agents/skills/genesis-project/references/sanity-checks.md`.
|
|
16
23
|
|
|
17
24
|
Do not edit any file. Return a concise report ordered by impact with exact file
|
|
18
25
|
references, the evidence inspected, and the smallest sensible correction.
|
|
@@ -108,6 +108,14 @@ abstractions. Consolidate ownership where one clear module is enough. Do not
|
|
|
108
108
|
optimize for tiny files or indirection; optimize for a small, obvious design
|
|
109
109
|
that a junior programmer can follow.
|
|
110
110
|
|
|
111
|
+
Before editing, list the behaviors of the code in scope with the test that
|
|
112
|
+
covers each, as the engineering approach's refactor rule and the "Refactors
|
|
113
|
+
keep behavior" section of
|
|
114
|
+
`.agents/skills/genesis-project/references/sanity-checks.md` describe. After
|
|
115
|
+
cleanup, walk the list again: every item must still hold and still have a test,
|
|
116
|
+
and a test the cleanup changed must assert no less than before. A behavior no
|
|
117
|
+
test covers is a follow-up finding, never permission to drop it.
|
|
118
|
+
|
|
111
119
|
Cleanup is not a second implementation pass. The selected changes limit where
|
|
112
120
|
cleanup may occur; sharing a file does not bring unrelated edits into scope or
|
|
113
121
|
authorize different behavior in that file. Deslop may reorganize behavior
|
|
@@ -136,5 +144,5 @@ Leave the cleanup as ordinary uncommitted work for review and a later normal
|
|
|
136
144
|
commit. Never amend or rewrite the selected commits. Run focused checks when
|
|
137
145
|
useful. Final declared checks remain available through the Genesis `verify`
|
|
138
146
|
operation. Summarize the resolved scope and any selected commit identities,
|
|
139
|
-
what became simpler,
|
|
140
|
-
left unchanged.
|
|
147
|
+
what became simpler, the behaviors checked before and after, files changed,
|
|
148
|
+
checks actually run, and follow-up findings left unchanged.
|
|
@@ -164,14 +164,17 @@ despite a supplied login), report the host defect with evidence and stop; never
|
|
|
164
164
|
compensate in the project by rewriting cookies or adding its own login or
|
|
165
165
|
browser.
|
|
166
166
|
|
|
167
|
-
Speed is verified like behavior,
|
|
168
|
-
change to a list, batch or write path ships with a test at realistic
|
|
169
|
-
and history that
|
|
170
|
-
preparation, suite and slowest-
|
|
171
|
-
find the cause (a read per row,
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
167
|
+
Speed is verified like behavior, with the engineering approach's sanity
|
|
168
|
+
checks. A change to a list, batch or write path ships with a test at realistic
|
|
169
|
+
row counts and history that compares its query count at a few rows and at a
|
|
170
|
+
realistic number. Read the run's preparation, suite and slowest-file timings
|
|
171
|
+
with its counts; when one grows with the data, find the cause (a read per row,
|
|
172
|
+
an access check sized by stored history, test preparation that replays
|
|
173
|
+
migrations) before reporting completion. After a refactor, walk the behavior
|
|
174
|
+
list made before it and report any item that no longer holds. Before reporting
|
|
175
|
+
data access, tests, a refactor, a screen or a release done, read the matching
|
|
176
|
+
section of [the sanity checks guide](references/sanity-checks.md) and apply its
|
|
177
|
+
checks with the tools your Stack pieces name.
|
|
175
178
|
|
|
176
179
|
An unconfigured result means the declared workspace or checks do not exist
|
|
177
180
|
yet; it is not a failing check. Before reporting completion, compare the
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
# Sanity checks
|
|
2
|
+
|
|
3
|
+
The Engineering baseline states these checks in short form. This guide gives
|
|
4
|
+
each one's examples and outer limits. Read the section that applies before
|
|
5
|
+
reporting data access, tests, a refactor, a screen or a release done.
|
|
6
|
+
|
|
7
|
+
## How to use this guide
|
|
8
|
+
|
|
9
|
+
- Each section gives what good looks like, the check you make and judge, real
|
|
10
|
+
failures it catches, and an outer limit.
|
|
11
|
+
- Measure, then judge. Prefer counts (queries, requests, processes, DOM nodes)
|
|
12
|
+
to clock times, which change with the machine.
|
|
13
|
+
- An outer limit marks what is clearly broken, never a target: code just under
|
|
14
|
+
one is not thereby fine, and code is never bent to reach a number.
|
|
15
|
+
- Apply each check with the tools your Stack pieces name under "Sanity checks
|
|
16
|
+
with <stack>": the query counter, the parallel runner, the strict mode.
|
|
17
|
+
- Examples come from real projects; one that depends on a stack names it.
|
|
18
|
+
|
|
19
|
+
## Never do these
|
|
20
|
+
|
|
21
|
+
Each one silently loses data, protection or a whole run.
|
|
22
|
+
|
|
23
|
+
- Cap a read its callers treat as complete: they act on a silent first page.
|
|
24
|
+
- Drop a behavior, rule or access decision silently in a restructure.
|
|
25
|
+
- Declare a constraint or protection that nothing enforces.
|
|
26
|
+
- Let a client's ids or a missing value decide access.
|
|
27
|
+
- Store a missing value as a real one: a blank later reads as fact.
|
|
28
|
+
- Run tests against a development or production database or configuration.
|
|
29
|
+
- Edit a migration that has run anywhere: databases diverge.
|
|
30
|
+
- Let the first visitor to a new deployment own it.
|
|
31
|
+
- Run production with development settings, fallbacks, hosts or secrets.
|
|
32
|
+
- Release a test's servers, processes or timers only where a timeout skips it.
|
|
33
|
+
- Edit a generated file instead of its source: the next generation erases it.
|
|
34
|
+
|
|
35
|
+
## Data: loading a dataset
|
|
36
|
+
|
|
37
|
+
**Good:** a list, page or report takes about as many queries for 10 rows as
|
|
38
|
+
for 200. Related rows come in one batch per related table, and each visibility
|
|
39
|
+
check is part of the query, bounded by the rows read.
|
|
40
|
+
|
|
41
|
+
**Check:** seed hundreds of rows and long per-person histories. Count the
|
|
42
|
+
queries at a small and a realistic size and look at what grows. A count that
|
|
43
|
+
grows with the rows means something runs per row: a single-record read, lookup
|
|
44
|
+
or access check inside a loop. A count that grows with a person's history means
|
|
45
|
+
an access check sized by history. Read the captured SQL for:
|
|
46
|
+
- a schema-metadata read on a request path;
|
|
47
|
+
- a row read back just after it was written;
|
|
48
|
+
- the same table and id read twice in one request;
|
|
49
|
+
- one statement repeated with one id at a time;
|
|
50
|
+
- access-policy SQL that runs to kilobytes (print it per role and read its
|
|
51
|
+
plan).
|
|
52
|
+
|
|
53
|
+
Compare a response's size with what the screen shows of it.
|
|
54
|
+
|
|
55
|
+
**Examples:**
|
|
56
|
+
- A page of 100 incidents read each incident's revision, pinned module and
|
|
57
|
+
readers one at a time: 1,801 queries and 5–7 s. Batched per table it took
|
|
58
|
+
181, still about one a row.
|
|
59
|
+
- A notice policy checked every source a reader had ever been notified about:
|
|
60
|
+
26–33 s and 13,176 queries per 100 notices.
|
|
61
|
+
- Schema metadata joined across a database server holding hundreds of
|
|
62
|
+
databases cost 25–63 s per call (MySQL `information_schema`).
|
|
63
|
+
|
|
64
|
+
**Outer limit:** a list that makes hundreds of queries, takes over a second on
|
|
65
|
+
a quiet database, runs the same access check more than a few times per
|
|
66
|
+
request, or returns megabytes for one screen is broken. Find the loop first.
|
|
67
|
+
|
|
68
|
+
## Data: saves, batches and background work
|
|
69
|
+
|
|
70
|
+
**Good:** a batch writes each table in a few statements inside the owner's
|
|
71
|
+
transaction, not one full create per row. Work nobody waits for runs as a
|
|
72
|
+
scheduled or queued job in bounded chunks. A read request takes no lock and
|
|
73
|
+
writes nothing. Two writers on the same records never produce a server error.
|
|
74
|
+
|
|
75
|
+
**Check:** count a batch's statements at 10 items and at 500. Look for due work
|
|
76
|
+
run inside whichever request comes first, and one long transaction around it.
|
|
77
|
+
Find any lock or write a read path takes for one-time setup: read first, lock
|
|
78
|
+
only on the rare unset path. Run two writers on the same records; a retried
|
|
79
|
+
transaction must be safe to repeat.
|
|
80
|
+
|
|
81
|
+
**Examples:**
|
|
82
|
+
- An import created each row through the full single-record create path, with
|
|
83
|
+
its lookups and read-back, one row at a time.
|
|
84
|
+
- Overdue work ran inside the first user request after a quiet period, so that
|
|
85
|
+
request's time depended on how long nobody had used the app.
|
|
86
|
+
- Concurrent saves surfaced database deadlocks as 500s.
|
|
87
|
+
|
|
88
|
+
**Outer limit:** thousands of queries or tens of seconds for one action, or a
|
|
89
|
+
request whose time depends on how long since anyone used the app.
|
|
90
|
+
|
|
91
|
+
## Work that repeats or lingers
|
|
92
|
+
|
|
93
|
+
**Good:** work whose answer does not change between calls runs once and is
|
|
94
|
+
reused. Everything a feature starts has a named owner that stops it. Each poll
|
|
95
|
+
stands in for a named event, and retries cover network errors, 5xx and 429
|
|
96
|
+
only. Logs say each thing once.
|
|
97
|
+
|
|
98
|
+
**Check:** time a call that should do nothing. List the processes alive after
|
|
99
|
+
the app has been idle. After a run, read the log's size and most repeated line.
|
|
100
|
+
|
|
101
|
+
**Example:** an idempotent "ensure" step rediscovered its whole configuration on
|
|
102
|
+
every call.
|
|
103
|
+
|
|
104
|
+
**Outer limit:** a no-op check over a second, an idle page requesting every
|
|
105
|
+
second, or a log growing by hundreds of MB per run.
|
|
106
|
+
|
|
107
|
+
## The wait a person sees
|
|
108
|
+
|
|
109
|
+
**Good:** the time from click to result is known, cold and warm, and each part
|
|
110
|
+
of it has a name.
|
|
111
|
+
|
|
112
|
+
**Check:** read the server's own request times while the tests run. Time the
|
|
113
|
+
main actions from click to result, and split the time into its parts.
|
|
114
|
+
|
|
115
|
+
**Outer limit:** an ordinary page taking seconds on a test database, or tens of
|
|
116
|
+
seconds with no feedback.
|
|
117
|
+
|
|
118
|
+
## Refactors keep behavior
|
|
119
|
+
|
|
120
|
+
**Good:** a refactor, consolidation or move keeps every behavior and access
|
|
121
|
+
decision, or drops one only with the person's agreement.
|
|
122
|
+
|
|
123
|
+
**Check:** before changing code, list its operations, inputs and their
|
|
124
|
+
validation, permissions per role, states and edge cases, with the test covering
|
|
125
|
+
each. Afterwards walk the list again with the original tests passing and their
|
|
126
|
+
assertions unchanged. Compare per-file test counts before and after, and name
|
|
127
|
+
each removal. Search for what a removed caller was the only caller of. After a
|
|
128
|
+
mechanical sweep, compare files changed with files expected and search for the
|
|
129
|
+
old form. A new mechanism replaces the one already doing the job.
|
|
130
|
+
|
|
131
|
+
**Examples:**
|
|
132
|
+
- Restructures dropped validation and access rules along with the tests that
|
|
133
|
+
covered them, so the suite stayed green.
|
|
134
|
+
|
|
135
|
+
**Outer limit:** dozens of dropped items found at review.
|
|
136
|
+
|
|
137
|
+
## Failing tests are bugs
|
|
138
|
+
|
|
139
|
+
**Good:** a failing test is a defect with an owner, in the product or in the
|
|
140
|
+
test. Red CI on the main branch stops the line. A final run is one whole run on
|
|
141
|
+
the tree that is pushed.
|
|
142
|
+
|
|
143
|
+
**Check:** name each failure's cause; never rerun until green, skip or loosen
|
|
144
|
+
to finish. Compare the tested commit with the pushed one. List every skip with
|
|
145
|
+
its reason and the run that covers it, against the last run's count. See each
|
|
146
|
+
new test fail once. Diagnosis runs may stop early; a final run runs everything
|
|
147
|
+
and reports what did not run. Report a speed win with its absolute number.
|
|
148
|
+
|
|
149
|
+
**Examples:**
|
|
150
|
+
- A preparation script ended with `exit $status` instead of
|
|
151
|
+
`test $status -eq 0`, so it ended the caller and the tests never ran while
|
|
152
|
+
the run reported success (shell).
|
|
153
|
+
- A suite kept a set of "known" failures as a baseline until they hid a new
|
|
154
|
+
regression.
|
|
155
|
+
|
|
156
|
+
**Outer limit:** a red test on main nobody owns, a suite that needs reruns to
|
|
157
|
+
look green, or dozens of skips nobody can place.
|
|
158
|
+
|
|
159
|
+
## Tests: time
|
|
160
|
+
|
|
161
|
+
**Good:** tests take the time their work needs. Files run in parallel within
|
|
162
|
+
the machine's test budget. Databases and fixtures are prepared once per run
|
|
163
|
+
from a stored schema and seed, checked by a digest of their sources, and the
|
|
164
|
+
full migration history is replayed once, as its own check. Builds and server starts happen once per run.
|
|
165
|
+
|
|
166
|
+
**Check:** after every run, read the suite time, each phase's time
|
|
167
|
+
(preparation, import, sign-in, tests) and the slowest files. A wall time close
|
|
168
|
+
to the sum of the files' times means they ran one at a time: find why. In a
|
|
169
|
+
slow file, find where the time goes: repeated preparation, replayed
|
|
170
|
+
migrations, fixed sleeps, polling, a process per test, repeated builds or
|
|
171
|
+
sign-ins. Split test time into the app's request time and the harness's before
|
|
172
|
+
choosing a fix. Remove exact repeats across CI jobs. Each sleep names the
|
|
173
|
+
condition it waits for; wait for that. Compare each raised time limit with the
|
|
174
|
+
measured need, and check a limit exists. Assert counts, not tight times.
|
|
175
|
+
|
|
176
|
+
**Examples:**
|
|
177
|
+
- 359 tests ran one file at a time, 163 s in all, because the test command
|
|
178
|
+
forced a concurrency of one.
|
|
179
|
+
- Test databases were rebuilt by replaying every migration for each file.
|
|
180
|
+
- Time limits were raised until slow tests passed, and the slowness stayed.
|
|
181
|
+
|
|
182
|
+
**Outer limit:** a suite running for hours (a small app's for an hour),
|
|
183
|
+
preparation in minutes, or a limit ten times the measured need.
|
|
184
|
+
|
|
185
|
+
## Tests: each owns what it uses
|
|
186
|
+
|
|
187
|
+
**Good:** each test creates and signs in as what it asserts, and each file owns
|
|
188
|
+
its data, system-picked ports, directories and caches. A skip caused by the
|
|
189
|
+
environment is a failure.
|
|
190
|
+
|
|
191
|
+
**Check:** run a file twice, beside another, reversed and shuffled, and two
|
|
192
|
+
suites at once; the result does not change. Run at a fake time near midnight,
|
|
193
|
+
in another time zone and in a clean environment. Each seed names what needs it;
|
|
194
|
+
volume fixtures belong to the volume tests. A disposable test database server
|
|
195
|
+
may relax durability; each run drops what it made.
|
|
196
|
+
|
|
197
|
+
**Examples:**
|
|
198
|
+
- Specs passed only after an earlier spec left a signed-in user behind.
|
|
199
|
+
- Two parallel runs collided on one fixed port and one shared cache directory.
|
|
200
|
+
|
|
201
|
+
**Outer limit:** a test that passes only in one order, or two identical runs
|
|
202
|
+
that differ.
|
|
203
|
+
|
|
204
|
+
## Tests: nothing hangs or lingers
|
|
205
|
+
|
|
206
|
+
**Good:** everything a test starts is released by teardown that also runs
|
|
207
|
+
after a timeout, and the process exits when its tests end. Waits wait for the
|
|
208
|
+
thing that matters.
|
|
209
|
+
|
|
210
|
+
**Check:** list what keeps a finished file alive. A wait that often ends at its
|
|
211
|
+
cap waits for the wrong thing: an idle network on a page with live connections,
|
|
212
|
+
or an animation that never ends.
|
|
213
|
+
|
|
214
|
+
**Outer limit:** a file that ends only when its limit kills it.
|
|
215
|
+
|
|
216
|
+
## Tests that prove behavior
|
|
217
|
+
|
|
218
|
+
**Good:** a test drives the real path, passes after a behavior-preserving
|
|
219
|
+
refactor and fails when the behavior breaks. Doubles answer like the real
|
|
220
|
+
collaborator, refusals included. Every spec is linted and listed by the quick
|
|
221
|
+
check.
|
|
222
|
+
|
|
223
|
+
**Check:** ask whether each test you touch pins source text or internals. An
|
|
224
|
+
export, option or branch only tests use goes. Name the committed test for each
|
|
225
|
+
user-visible feature you changed.
|
|
226
|
+
|
|
227
|
+
**Outer limit:** a feature shipped with no test that would fail without it.
|
|
228
|
+
|
|
229
|
+
## Inputs and access
|
|
230
|
+
|
|
231
|
+
**Good:** every declared constraint and protection is enforced and has one
|
|
232
|
+
test that trips it. Access comes from the authenticated context, is decided
|
|
233
|
+
before validation answers, and refuses when a scope, role or collaborator is
|
|
234
|
+
missing. Refusals keep their status, code and message to the client. Writes go
|
|
235
|
+
through the layer that applies policy, validation and audit.
|
|
236
|
+
|
|
237
|
+
**Check:** send one input that breaks each constraint (a missing required
|
|
238
|
+
field, a call past a rate limit, a caller without permission, another tenant's
|
|
239
|
+
id) and see it refused. A malformed request from someone without permission
|
|
240
|
+
gets a 403 and no field errors. Trace inputs that reach file paths. Ask what
|
|
241
|
+
production does when each optional collaborator is missing: "nothing,
|
|
242
|
+
silently" means it is required. Each write that bypasses the policy layer, and
|
|
243
|
+
each "anyway" override, names its reason. Before removing a guard, prove the
|
|
244
|
+
layer below enforces it.
|
|
245
|
+
|
|
246
|
+
**Examples:**
|
|
247
|
+
- A partial-update mode accepted an empty body and saved nothing, while the
|
|
248
|
+
schema declared the fields required.
|
|
249
|
+
- A framework silently discarded fields the model did not allow, and the save
|
|
250
|
+
reported success (Laravel without strict mode).
|
|
251
|
+
|
|
252
|
+
**Outer limit:** a request missing a required field succeeds, or a user acts in
|
|
253
|
+
another tenant.
|
|
254
|
+
|
|
255
|
+
## Changes others depend on
|
|
256
|
+
|
|
257
|
+
**Good:** a change to a name, default or contract fails loudly, naming its
|
|
258
|
+
fix, wherever the old shape remains. A fix reaches every copy of the code it
|
|
259
|
+
fixes. A new setup step runs in every deploy path.
|
|
260
|
+
|
|
261
|
+
**Check:** boot and check every dependent with the change. Search every copy
|
|
262
|
+
of fixed code, scaffold copies included. Prove a new setup step runs in the
|
|
263
|
+
deploy path. Search the docs for removed or renamed names. A local workaround
|
|
264
|
+
for a dependency's gap names the owner's fix and is marked for removal.
|
|
265
|
+
|
|
266
|
+
**Outer limit:** a project that runs differently after an update without
|
|
267
|
+
saying so.
|
|
268
|
+
|
|
269
|
+
## Screens in use
|
|
270
|
+
|
|
271
|
+
**Good:** a screen renders what is visible, loads what its first view needs,
|
|
272
|
+
and feedback never covers the next action. Each inner page opens directly and
|
|
273
|
+
by link, and Up and Back stay inside the app. Screens use the design system's
|
|
274
|
+
tokens and components and show names, not ids.
|
|
275
|
+
|
|
276
|
+
**Check:**
|
|
277
|
+
- Count DOM nodes with realistic data, and the requests one action causes
|
|
278
|
+
across open screens. Follow a big first-screen chunk to its import.
|
|
279
|
+
- After each action, look at what its feedback covers, use the next action and
|
|
280
|
+
press Escape. At phone width, tap each control after the previous field
|
|
281
|
+
blurs.
|
|
282
|
+
- Scroll every screen to its end at about 390 px, 1,000 px and desktop width,
|
|
283
|
+
in light and dark. With a cold cache, look for numbers where names belong.
|
|
284
|
+
- Make each endpoint the first request after a restart; go offline and back;
|
|
285
|
+
sign out in another tab and return; close the tab during a long action.
|
|
286
|
+
- In a production build, change a screen's inputs and see what it shows change,
|
|
287
|
+
with no render loops.
|
|
288
|
+
|
|
289
|
+
**Examples:**
|
|
290
|
+
- A success message appeared over the Save button and took the next tap.
|
|
291
|
+
- A list rendered every row of a large data set into the page.
|
|
292
|
+
|
|
293
|
+
**Outer limit:** tens of thousands of DOM nodes, typing lag, or megabytes or
|
|
294
|
+
hundreds of requests on a first screen.
|
|
295
|
+
|
|
296
|
+
## State and workflow
|
|
297
|
+
|
|
298
|
+
**Good:** the same state twice gives the same result. Each fact has one
|
|
299
|
+
resolver. Each status names what clears it, and each gate has a case that must
|
|
300
|
+
fail it. Writes are conditional on the version read. A delete removes what it
|
|
301
|
+
created elsewhere. Readiness is checked directly.
|
|
302
|
+
|
|
303
|
+
**Check:** find every place that resolves the same fact. Check that what a
|
|
304
|
+
delete created outside its table is gone. When a rule's result breaks another
|
|
305
|
+
stated rule, stop and ask, and keep the failing case.
|
|
306
|
+
|
|
307
|
+
**Outer limit:** a step that fails because the one before said ready.
|
|
308
|
+
|
|
309
|
+
## Production settings
|
|
310
|
+
|
|
311
|
+
**Good:** production fails closed. Development modes, `localhost`, fixed ports
|
|
312
|
+
and fixed secrets exist only in tests. Security headers are sent, email
|
|
313
|
+
ownership is confirmed where sign-up needs it, and tokens and CI jobs have the
|
|
314
|
+
least permission they need.
|
|
315
|
+
|
|
316
|
+
**Check:** read the running production server's mode and flags and a
|
|
317
|
+
production build's response headers. Sign up without confirming email and try
|
|
318
|
+
to sign in. Run the ecosystem's dependency audit; fix it at the dependency
|
|
319
|
+
ranges. Search fixtures for real names, hosts and emails. Name what ends each
|
|
320
|
+
token.
|
|
321
|
+
|
|
322
|
+
**Outer limit:** the first visitor can own the deployment, or it runs as
|
|
323
|
+
development.
|
|
324
|
+
|
|
325
|
+
## AI features
|
|
326
|
+
|
|
327
|
+
**Good:** the assistant can see and do no more than its user. Volatile state
|
|
328
|
+
sits after the stable prompt prefix, so the model's prompt cache holds.
|
|
329
|
+
|
|
330
|
+
**Check:** sign in as the least-privileged user and list what the assistant can
|
|
331
|
+
read and change. Read cached and uncached input tokens on two turns of one
|
|
332
|
+
conversation.
|
|
333
|
+
|
|
334
|
+
**Outer limit:** most input tokens uncached on a long conversation.
|
|
335
|
+
|
|
336
|
+
## How you work
|
|
337
|
+
|
|
338
|
+
- Reproduce and measure before changing anything; verify a reviewer's premise.
|
|
339
|
+
- Lint the touched files and confirm the lint reads them. After the gates pass,
|
|
340
|
+
read the code against this guidance and check each suppression's reason.
|
|
341
|
+
- A reviewer can read each changed function, and the commit, in one sitting.
|
|
342
|
+
- Raise an instruction that slows the work or hides failures; do not follow it
|
|
343
|
+
silently.
|
|
344
|
+
- Run the smallest check that answers the question, and do not fill a shared
|
|
345
|
+
machine with full runs. Wait without polling, and read counts and failures,
|
|
346
|
+
not whole logs.
|
|
347
|
+
- Before acting on a shared machine or tree, name the approval that allows it,
|
|
348
|
+
and stay inside the approved scope.
|
|
349
|
+
- At the end of a task, list what is uncommitted, and save or revert it.
|
|
350
|
+
|
|
351
|
+
**Outer limit:** gates green while review finds hundreds of defects, or
|
|
352
|
+
functions thousands of lines long.
|