Featurevisor

Use cases

Scheduled releases

Deploy checkout with its launch time already configured, then enable it from that instant without another deployment. Featurevisor has no clock or scheduler: your application supplies the current time whenever it evaluates.

Declare the current time

Start with the default scaffold, which already declares userId. Add a timestamp attribute called now. This is an ordinary attribute name, not a reserved key:

attributes/now.yml
description: Current application time
type: string
format: date-time

Set the launch instant

Release at 2026-11-27T00:00:00Z. after is strict, so compare with one millisecond earlier to include the launch instant:

segments/afterCheckoutLaunch.yml
description: Checkout launch has arrived
conditions:
- attribute: now
operator: after
value: '2026-11-26T23:59:59.999Z'

An after operand of the launch instant itself would exclude that exact millisecond. For an end time, add before with the end instant to make the end exclusive. Both sides must use portable timestamps.

Do not use not around a date comparison as a substitute for the opposite operator. Missing or invalid dates make direct comparisons return false, which not may invert into a match.

Gate checkout

Replace the scaffold's checkout definition with this rule:

features/checkout.yml
description: Scheduled checkout release
bucketBy: userId
rules:
- key: launched
conditions: afterCheckoutLaunch
percentage: 100

Before launch, no rule matches and checkout is disabled. At launch, every user with a valid current timestamp gets it.

Refresh the context

Pass a fresh instant for each evaluation:

const context = {
userId: '8f2a',
now: new Date(),
}
const enabled = f.isEnabled('checkout', context)

An existing Date object does not advance with time. Replacing or refreshing the context is required, not only calling the getter again with an old value. Evaluate on each server request, on navigation or on an application timer.

React hooks are not driven by a clock and do not update because the launch time passes. Have your application refresh now in the context and trigger evaluation through its context update flow. The visible boundary depends on how often it does this.

Use a trusted server clock for access decisions or anything where timing matters. Users can change device clocks and browser context. Client evaluation controls presentation, not authorisation. Enforce protected operations on the server.

Test the boundary

Fix the time in test contexts instead of reading a real clock:

tests/features/checkout.spec.yml
feature: checkout
assertions:
- description: Off just before launch
at: 50
context:
userId: '8f2a'
now: '2026-11-26T23:59:59.999Z'
expectedToBeEnabled: false
- description: On at launch
at: 50
context:
userId: '8f2a'
now: '2026-11-27T00:00:00Z'
expectedToBeEnabled: true
- description: On after launch
at: 50
context:
userId: '8f2a'
now: '2026-11-27T00:00:00.001Z'
expectedToBeEnabled: true
Commands
npx featurevisor lint
npx featurevisor test

Lint validates authoring and warns about malformed context. Test executes the assertions without a validation gate. To inspect the launch instant:

Command
npx featurevisor evaluate \
--feature=checkout \
--context='{"userId":"8f2a","now":"2026-11-27T00:00:00Z"}' \
--explain

Deploy and roll back

Run lint and tests, then build and deploy the datafile before launch. Applications need to load that datafile and refresh their context, but no configuration change is needed at the launch instant.

Alternatively, merge and deploy a rule enabling checkout at launch time. That avoids clock based targeting, but the release then depends on CI, deployment and each application's datafile refresh. Choose that workflow when an operator must approve the moment.

To cancel the scheduled launch or roll it back, set the rule's percentage to 0, test and deploy the new datafile. The change takes effect when applications load it. Restoring a datafile that still contains the schedule will not disable checkout after its launch instant.

Previous
Decoupled releases