Skip to content

Declaring a project

{project.file} is the first file an adopting repository writes. It is found by walking up from wherever a run starts, and every relative path in it resolves against its own directory — so a case that names what it drives can be moved to another checkout unchanged.

Every key is optional, and that matters more than it sounds. A reading that needs a key this file does not declare is recorded as not taken, never quietly skipped, so an incomplete declaration is safe to start from and an unasked question never reads like an answered one. The last column below is what each omission actually does.

KeyHoldsWhat it declaresLeft out
executablea paththe binary a launch starts, resolved against this file's own directoryasking for it refuses, naming the key and that it was launching the application under test; a run that attaches to a process already running never asks
sourceRoota paththe source a staleness check compares the built binary againstthe staleness reading is recorded as not taken, so a run cannot report on a build from last week and say nothing about it
fingerprintStorea paththe region of the machine a run must leave exactly as it found it — where the application keeps the settings and caches it ownsnothing is fingerprinted, so a run that drove a path writing a real setting finishes quietly
capturesa path to a directorywhere a picture a case asks for is written; the case's own name is the folder inside it, so two cases asking for 'the menu' do not answer each othera capture step refuses at the door rather than after launching the application
languageFilesan array of pathsthe strings this application ships, which is what lets a locator say {a.key} and an expectation derive a label instead of typing words a translation rewritesthere is no well to derive from, and every claim that reads one is refused where it is written rather than at run time
loadingan array of keysthe keys of the strings shown while a page is still computing, so a page still saying it is loading is a failure rather than a photograph
refuses a key none of the languageFiles carries — a check that silently matches nothing reports every page as finished forever
no page is held to having finished computing
sourceIgnorean array of directory nameswhat the staleness walk steps past, by simple name at any depththe names DefaultSourceIgnore lists stand — build output and tooling state, which is the set that matters: with bin counted as source the binary is always newer than itself
timeoutsan object of names to millisecondshow long this project is willing to wait, by name, declared once rather than typed into the case that needed it
refuses a value that is not a positive number
the names Timeouts.Defaults seeds stand, and a declared name nothing seeds is simply this project's own
languagean objecthow the run works out which language the application is actually inthe display language is the whole of the resolution
attemptsa whole numberhow many times a flaky act may be attempted — a fact about this project rather than about a case
refuses a number outside Retry's own bounds, named against this file rather than thrown once per step about an argument out of range
Retry.DefaultCap stands
destructivean array of {"id"} or {"key"} entriesthe entries that end the run, which no step may touch without saying it meant to
refuses a bare name where the project ships more than one language, a name being exactly the field a translation rewrites
nothing is destructive, and no step has to say it meant it
reportedSetsan object of names to argument arraysthe sets the application reports about itself, each with the arguments that make it print one per line — for a set that is this machine's data rather than a string the product ships
refuses an entry with no name, or one with no arguments, since nothing would then say how the application is asked
'covers' has only the language files to derive from
reportedValuesan object of names to argument arraysthe single values the application reports about itself, for a fact about this machine that no case may type
refuses an entry with no name, or one with no arguments
'expectReported' has no well to ask
KeyHoldsWhat it declaresLeft out
preferenceFilea paththe JSON file this application saves the user's chosen language inthe display language is the whole of the resolution
preferenceKeya key, dotted for a nested onewhere inside that file the chosen language sitsthe preference file is not read
fallbacka language tagthe language the application itself falls back to when it ships no strings for the one the machine is inthere is no fallback to make, and reading a label in a language nobody declared is refused rather than answered in English

Three keys have defaults rather than an absence, and they are read off the engine on every build rather than written here.

attempts is 3.

timeouts is seeded with these, in milliseconds. A declared name replaces the seeded one; a name nothing seeds is simply this project’s own.

  • resolve — 5,000 ms
  • act — 2,000 ms
  • launch — 15,000 ms
  • stop — 5,000 ms
  • poll — 25 ms

sourceIgnore is seeded with the directories a staleness walk must not read as source:

  • bin
  • obj
  • .git
  • .vs
  • .idea
  • node_modules
  • TestResults
  • .roadkeep

That last default is the one worth understanding rather than copying. With build output counted as source, the binary is always newer than itself, nothing is ever stale, and the staleness check quietly answers nothing — which is a green about a build from last week.

The two refusals worth reading before you meet them

Section titled “The two refusals worth reading before you meet them”

Every key above, so there is nothing to discover later:

{
"executable": "bin/Debug/net10.0-windows/YourApp.exe",
"sourceRoot": "src/YourApp",
"sourceIgnore": ["bin", "obj"],
"fingerprintStore": "%APPDATA%/YourApp",
"captures": "TestResults/captures",
"languageFiles": ["strings.en.json", "strings.pt-BR.json"],
"loading": ["report.computing", "common.pleaseWait"],
"reportedSets": { "profiles": ["--print-profiles"] },
"reportedValues": { "activeProfile": ["--print-active-profile"] },
"language": { "preferenceFile": "settings.json", "preferenceKey": "ui.language", "fallback": "en" },
"timeouts": { "resolve": 5000, "stop": 5000 },
"attempts": 3,
"destructive": [{ "id": "quitCommand" }, { "key": "menu.exit" }]
}

An environment variable is expanded, so an installed application can be named without a path that only exists on one machine.

  • Your first case — the file this declaration is for, and the four calls that run it.
  • The case format — every field a case may carry, including the ones that read the wells declared here.
  • The verbs — what each verb needs before it can answer.