Public: anyone can read this; the crew can change it.

A feature declares a schedule in forge.json, and a malformed one is refused with a reason that names it #9947

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

A feature can now declare `"schedule": [{ "tool": "scan", "every": "1h" }]` in `forge.json`, and `parseFeature` checks it. Nothing fires yet: no timer, no sweep, no server boot code touched.

shipped production is serving it deploy 9e8c29c

opened this

A feature can now declare "schedule": [{ "tool": "scan", "every": "1h" }] in forge.json, and parseFeature checks it. Nothing fires yet: no timer, no sweep, no server boot code touched.

What changed

  • src/apps/feature.ts: schedule is on the allowed-fields list, and FeatureSpec carries schedule: readonly { tool, everyMs }[]. It is empty when not declared, so existing features parse unchanged.

- At most 4 entries. - tool must be one of the feature's own tools. - every is one of 15m, 1h, 6h or 1d. - A refusal names the field and the entry, for example feature: schedule entry 1 (scan): every is one of 15m, 1h, 6h, 1d.

  • Extra field (not in the issue): an entry with a field other than tool and every is refused as unknown field, matching how the settings errors treat extra fields.
  • test/feature-schedule.test.ts: covers absent, a valid entry, an unknown tool, an unknown interval, more than 4 entries, a non-array, and the extra-field case. I did not run the refusal tests against main to confirm each fails there; none of them can pass without the new parser.
  • docs/features/absorb.md: the sentence calling the schedule the app's own timer is gone. A new "Schedule" paragraph describes the declaration and says firing is not done yet.

How to try it: bun test test/feature-schedule.test.ts test/features.test.ts test/feature-tools.test.ts test/apps-features.test.ts gives 58 passing, and bun x tsc --noEmit is clean. scripts/gate.ts ran and printed nothing.

I could not use the keep_plan tool; it is not available in this session, so there is no plan on the issue.

Closes #9925

commented

A feature can now declare "schedule": [{ "tool": "scan", "every": "1h" }] in forge.json, and parseFeature checks it. Nothing fires yet: no timer, no sweep, no server boot code touched.

What changed

  • src/apps/feature.ts: schedule is on the allowed-fields list, and FeatureSpec carries schedule: readonly { tool, everyMs }[]. It is empty when not declared, so existing features parse unchanged.

- At most 4 entries. - tool must be one of the feature's own tools. - every is one of 15m, 1h, 6h or 1d. - A refusal names the field and the entry, for example feature: schedule entry 1 (scan): every is one of 15m, 1h, 6h, 1d.

  • Extra field (not in the issue): an entry with a field other than tool and every is refused as unknown field, matching how the settings errors treat extra fields.
  • test/feature-schedule.test.ts: covers absent, a valid entry, an unknown tool, an unknown interval, more than 4 entries, a non-array, and the extra-field case. I did not run the refusal tests against main to confirm each fails there; none of them can pass without the new parser.
  • docs/features/absorb.md: the sentence calling the schedule the app's own timer is gone. A new "Schedule" paragraph describes the declaration and says firing is not done yet.

How to try it: bun test test/feature-schedule.test.ts test/features.test.ts test/feature-tools.test.ts test/apps-features.test.ts gives 58 passing, and bun x tsc --noEmit is clean. scripts/gate.ts ran and printed nothing.

I could not use the keep_plan tool; it is not available in this session, so there is no plan on the issue.

Approved

Clean. The parser is a small, pure function. It checks the tool against the feature own tools, the interval against a fixed table, the entry count, and extra fields. Refusals name the field and entry. Tests cover each refusal. The docs paragraph is in docs/features, not README, and says firing is not done. No input reaches a shell or SQL; no new dependency. Nit, not blocking: a non-string tool prints as tool undefined in the message.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs