Repository navigation
Description
Summary
ModelRouteSchedule.parse reads day-of-week names through the prototype chain: daysOfWeek: ["constructor"] (or ["__proto__"], in any letter case) is accepted as a valid day instead of rejecting the window. The stored daysOfWeek then contains a function / Object.prototype where a number belongs, the window can never be active, and describe() renders an empty day list.
Evidence (verified this run, main fd36da324a)
packages/core/src/model-route-schedule.ts:60-66—dayOfWeek()lowercases the input and returnsDAY_NAMES[text]with a plain index into a normal object literal (lines 34-51). Inherited members resolve: lowercasing makesconstructorand__proto__the reachable prototype names.packages/core/src/model-route-schedule.ts:207-219—parse()only rejects an entry when the mapped value is=== undefined, so the inherited non-number passes, is castas number[], deduplicated and sorted with a numeric comparator (NaNcomparisons).packages/core/src/model-route-schedule.ts:277,318-319—dayMatchesusesdaysOfWeek.includes(parts.dayOfWeek)(never true for the bogus entry) anddescribe()maps throughDAY_LABELS[day](undefined).
Laptop probe importing the real module (file md5 90ef612d…, byte-identical on both checkouts; probe at laptop ~/git/fleet/probe-2026-10-28-creator3/probe-schedule.ts):
isDayOfWeek("constructor")→true;isDayOfWeek("__proto__")→true(controls"tostring"/"valueof"correctly return false only because lowercasing renames them)parse({daysOfWeek:["constructor"]})→{daysOfWeek:[<function>]}(JSON[null]), notundefinedparse({daysOfWeek:["__proto__"]})→{daysOfWeek:[<Object.prototype>]}(JSON[{}])parse({daysOfWeek:["mon","constructor"]})→{daysOfWeek:[1, <function>]}describe(that window)→" all day"(empty day list);active(window, a Monday noon UTC)→false- Controls:
parse({daysOfWeek:["mon"]})→{daysOfWeek:[1]};parse({daysOfWeek:["frieday"]})→undefined
Why it matters
The module header (lines 15-17) and the pinned tests (packages/core/test/model-route-schedule.test.ts:38-39: ["mon","frieday"] → undefined) state the contract: any unreadable day entry rejects the whole window, so a typo makes a rule disappear instead of applying at the wrong time. Prototype names break that contract in the worst direction — the window is kept, is silently never active, describes itself with an empty day list, and carries a non-number in a number[] that downstream consumers (ModelRouteSchedule.active via model-route.ts gates/overrides, route-adjust describe) trust. This is the same prototype-chain class as #747 and #774, in a table those fixes did not cover.
Acceptance criteria
parse({daysOfWeek:["constructor"]}),["__proto__"], and mixed forms such as["mon","constructor"]returnundefined;isDayOfWeekreturnsfalsefor them (any letter case).- Valid names, numeric strings, and numbers parse exactly as today (
"mon"→ 1,"06"→ 6, dedup/sort unchanged). - Lookup is own-property only (e.g.
Object.hasOwn, aMap, or a null-prototype table) — no other behaviour change inparse/active/describe. - Tests pin the prototype names alongside the existing unreadable-entry cases in
model-route-schedule.test.ts.
Activity
developing-today commentedon Oct 29, 2026
OPENCODE-168
dezren39 commentedon Oct 29, 2026
Filed this run after verification against main
fd36da324a(laptop probe importing the real module; see issue body).Found via: filed this run
11 remaining items
dezren39 commentedon Oct 29, 2026
🤖 Agent note · state: done (merged)
Merge pull request #794 from developing-today/queue/2935-791-day-names
dezren39 commentedon Oct 29, 2026
🤖 Agent note · correction (Lane A, repo-queue-worker-shift-opencode): the merge-commit SHA in my done note for PR #794 was wrong — it came from a fabricated tool delivery during the shift. PR #794's real merge commit is 3cea2d2 (API-verified post-shift). The merge itself, this issue's closure, and the queue task completion were all verified real; only the cited SHA was incorrect (was: 5b9d2739d279210d12dc1e17261ee34ea4b8b11d).