Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 1 Nov 2026. What's built · Install 0.2.0
jadpo
Reference: Built-in services

Built-in services

Flags: changed, listed and removed

On this page

jadpo flags reads and changes jadpo_flags in the flags' store, found as jadpo schedules finds its database, and runs none of the app's code (jadpo flags).

Setting a value

jadpo flags set <flag> [<value>] changes one part of the flag's state and leaves the rest:

  • With no option, <value> becomes everyone's value.
  • --users <id>,<id> gives those users <value>, each id a Uuid.
  • --percent <n> replaces the shares with one, <value> for n% of users; --percent 0 removes them.
  • --split <value>=<n>,… replaces the shares with one for each value, in the order written, the percentages adding up to 100 or less. It takes no <value>, and not with --percent.

--users and --percent go together. A Bool flag's <value> is true when an option is given without one. A value is written as a test's flags: writes it, true or a variant's name.

jadpo flags reset <flag> gives everyone the default: again, its row deleted; with --users, only those users stop being named.

The log

Each change writes a row of jadpo_flag_changes in the same statement as the change: when, the flag, set or reset, its state before and after, the name the operator's machine gives (USER, else LOGNAME or USERNAME), and the database role PostgreSQL authenticated (session_user), which the statement reads itself so it can't be faked. The screen shows both, as jadpo deliveries does. A row is kept for good: changes are few, and a flag's history is what a reviewer reads when a release went wrong. Its rows, like jadpo_flags, hold named users' ids; a user's erasure removes them from both, which comes with erasures (Erasures). A change is made only to the row as it was read, so of two operators acting at once, one acts and the other is told it changed (flags.unavailable).

There is no production guard and no prompt. Changing a flag is the point of a running app's flags; a change is logged, reversible and reaches every server within ten seconds.

Ready to remove

A flag is ready to remove when every caller gets one value (each named user's, each share's with a percentage above 0 and everyone's are the same) and its row last changed seven days ago or more. A flag never changed has no row, so it is never marked: it hasn't been released.

Both values tested

flag.value_untested follows the calls each test makes, through the actions and fixtures it reaches and the routes it sends requests through (their run: and the action it runs), to every flags.<name> in the bodies it reaches, whichever branch of them it takes. A test gives each flag its flags: value, or the default:. A read the reaching tests don't give every value is an error at the read, naming the values missing, and it can't be declined. A test's own read of a flag isn't counted.

Removing

jadpo flags remove <flag> --keep <value> refuses a project that doesn't check, and refuses <value> that isn't one of the flag's. Then:

  • A read that is an if's whole condition, alone, behind !, or compared with == or != to a value, decides the if: its block or its else stays, unwrapped to the enclosing block, and an else if chain keeps its own conditions. When the kept block ends by returning, what came after it in the same block can't run and goes.

  • Every other read becomes the kept value, true or Type.variant.

  • The declaration goes from flags { }. When it was the last, flags { } stays, empty, so jadpo_flags and its log stay: dropping them is a migration of its own, which comes with dropping tables.

  • Each test's flags: line for it goes, and flags: with it when it was the last. A test whose value was another and that reached a read goes whole; here a read inside an if another flag decides is reached only by the tests whose values take that branch.

  • An enum flag's type goes too when nothing uses it any more, and its file when nothing else is in it.

Imports a change leaves unused go, and each file is formatted as it was. The result is checked, and undone with its errors when it doesn't check. A flag a route's run: passes on is refused before anything changes, since a route's run: passes no value written out: the action reads the flag itself first.

GET /flags

Each API with a record gets GET <prefix>/flags while a flag has client: true. It is authenticated as the API's routes are, and answers with a JSON object of each client: true flag by name, a Bool as true or false and an enum as its variant's name, worked out for the caller as an action's read is, with cache-control: no-store. The OpenAPI document gives its schema, the enum's values listed. A route the app writes at that path is route.path_overlap.

Markdown for agents: /docs/flags-changed-listed-and-removed.md.Built from Jadpo main at e00e61f.