Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
## 2026-07-12 - Optimize renderTaskRow DOM allocations
**Learning:** Caching unattached template nodes and instantiating them via `.cloneNode(false)` reduces DOM instantiation overhead in O(N) render loops significantly.
**Action:** Apply this optimization to other hot-path rendering elements such as rows, cells, and stack containers.
## 2026-08-21 - 핫 패스(hot paths)에서의 문자열 패딩 오버헤드
**Learning:** 이 날짜 포맷팅 루프를 대상으로 한 Node/V8 마이크로벤치마크에서는 `String.padStart(2, '0')`를 제거한 구현의 실행 시간이 더 짧았습니다. 이 결과는 런타임/JIT에 종속적이며, 보편적인 GC 비용이나 JS-C++ 경계 전환 메커니즘을 입증하는 근거로 확장하지 않습니다.
**Action:** 현재 포맷터에는 출력 의미와 `padStart` 비사용을 고정하는 결정적 회귀 테스트를 유지하고, 다른 경로나 브라우저 런타임으로 최적화를 확대하기 전에는 해당 실행 환경에서 다시 측정합니다.
18 changes: 13 additions & 5 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2684,20 +2684,28 @@ function clamp(value, min, max) {

function formatDateInput(date) {
const year = date.getUTCFullYear();
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
const day = String(date.getUTCDate()).padStart(2, '0');
const m = date.getUTCMonth() + 1;
const month = m < 10 ? '0' + m : m;
const d = date.getUTCDate();
const day = d < 10 ? '0' + d : d;
return `${year}-${month}-${day}`;
}

function formatLocalDateInput(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const m = date.getMonth() + 1;
const month = m < 10 ? '0' + m : m;
const d = date.getDate();
const day = d < 10 ? '0' + d : d;
return `${year}-${month}-${day}`;
}

function formatCompactDate(date) {
return `${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, '0')}${String(date.getDate()).padStart(2, '0')}`;
const m = date.getMonth() + 1;
const month = m < 10 ? '0' + m : m;
const d = date.getDate();
const day = d < 10 ? '0' + d : d;
return `${date.getFullYear()}${month}${day}`;
}

function formatPercent(value, digits) {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
"coverage": "npm run test:coverage",
"server": "node server/server.mjs",
"test:api": "node tests/api/auth-secret.test.mjs && node tests/api/smoke.mjs && node tests/api/ratelimit.test.mjs && node tests/api/attachment-status.test.mjs && node tests/api/session-revocation.test.mjs && node tests/api/orchestrator-attribution.test.mjs",
"test:unit": "node tests/unit/opencode-config.test.mjs && node tests/unit/changelog-release-notes.test.mjs && node tests/unit/analytics.test.mjs && node tests/unit/cpm.test.mjs && node tests/unit/baseline-compare.test.mjs && node tests/unit/workload.test.mjs && node tests/unit/cost-evm.test.mjs && node tests/unit/msproject.test.mjs && node tests/unit/auth-password.test.mjs && node tests/unit/editor-unsaved.test.mjs && node tests/unit/static-coverage-evidence.test.mjs && node tests/unit/dep-types.test.mjs && node tests/unit/weekly-report.test.mjs && node tests/unit/clearfolio.test.mjs && node tests/unit/clearfolio-adapter-mock-hmac.test.mjs && node tests/unit/orchestrator.test.mjs && node tests/unit/orchestrator-coverage.test.mjs && node tests/unit/orchestrator-attribution.test.mjs && node tests/unit/sprint-stats.test.mjs && node tests/unit/burndown.test.mjs && node tests/unit/pm-analysis.test.mjs && node tests/unit/cloud-sync-security.test.mjs && node tests/unit/attachment-status.test.mjs && node tests/unit/clearfolio-status-signal.test.mjs && node tests/unit/coverage-script-contract.test.mjs && node tests/unit/toast-accessibility.test.mjs",
"test:unit": "node tests/unit/opencode-config.test.mjs && node tests/unit/changelog-release-notes.test.mjs && node tests/unit/analytics.test.mjs && node tests/unit/cpm.test.mjs && node tests/unit/baseline-compare.test.mjs && node tests/unit/workload.test.mjs && node tests/unit/cost-evm.test.mjs && node tests/unit/msproject.test.mjs && node tests/unit/auth-password.test.mjs && node tests/unit/editor-unsaved.test.mjs && node tests/unit/date-formatting-performance.test.mjs && node tests/unit/static-coverage-evidence.test.mjs && node tests/unit/dep-types.test.mjs && node tests/unit/weekly-report.test.mjs && node tests/unit/clearfolio.test.mjs && node tests/unit/clearfolio-adapter-mock-hmac.test.mjs && node tests/unit/orchestrator.test.mjs && node tests/unit/orchestrator-coverage.test.mjs && node tests/unit/orchestrator-attribution.test.mjs && node tests/unit/sprint-stats.test.mjs && node tests/unit/burndown.test.mjs && node tests/unit/pm-analysis.test.mjs && node tests/unit/cloud-sync-security.test.mjs && node tests/unit/attachment-status.test.mjs && node tests/unit/clearfolio-status-signal.test.mjs && node tests/unit/coverage-script-contract.test.mjs && node tests/unit/toast-accessibility.test.mjs",
"test:coverage": "c8 --all --include=app.js --include=cloud-sync.js --include=scripts/ci/static_coverage_evidence.mjs --include=server/attachment_status.mjs --include=server/app.mjs --include=server/auth.mjs --include=server/clearfolio.mjs --include=server/orchestrator.mjs --reporter=json --reporter=json-summary npm run test:coverage:cases",
"test:coverage:cases": "node tests/unit/coverage-script-contract.test.mjs && node tests/unit/attachment-status.test.mjs && node tests/unit/clearfolio-status-signal.test.mjs && node tests/unit/clearfolio-adapter-mock-hmac.test.mjs && node tests/unit/orchestrator.test.mjs && node tests/unit/orchestrator-coverage.test.mjs && node tests/unit/orchestrator-attribution.test.mjs && node tests/unit/msproject.test.mjs && node tests/unit/auth-password.test.mjs && node tests/unit/editor-unsaved.test.mjs && node tests/unit/static-coverage-evidence.test.mjs && npm run test:api",
"test:coverage:cases": "node tests/unit/coverage-script-contract.test.mjs && node tests/unit/attachment-status.test.mjs && node tests/unit/clearfolio-status-signal.test.mjs && node tests/unit/clearfolio-adapter-mock-hmac.test.mjs && node tests/unit/orchestrator.test.mjs && node tests/unit/orchestrator-coverage.test.mjs && node tests/unit/orchestrator-attribution.test.mjs && node tests/unit/msproject.test.mjs && node tests/unit/auth-password.test.mjs && node tests/unit/editor-unsaved.test.mjs && node tests/unit/date-formatting-performance.test.mjs && node tests/unit/static-coverage-evidence.test.mjs && npm run test:api",
"test:e2e": "playwright test",
"test:e2e:headed": "playwright test --headed",
"test:e2e:cloud": "playwright install chromium && playwright test tests/e2e/cloud.spec.js tests/e2e/toast-accessibility.spec.js",
Expand Down
41 changes: 41 additions & 0 deletions tests/unit/date-formatting-performance.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import assert from 'node:assert/strict';
import fs from 'node:fs';
import test from 'node:test';

const APP_PATH = new URL('../../app.js', import.meta.url);

function loadDateFormatters() {
const source = fs.readFileSync(APP_PATH, 'utf8');
const start = source.indexOf('function formatDateInput(date) {');
const end = source.indexOf('\nfunction formatPercent(value, digits) {', start);

assert.notEqual(start, -1, 'formatDateInput must remain present in app.js');
assert.notEqual(end, -1, 'date formatter block must remain bounded by formatPercent');

return new Function(
`${source.slice(start, end)}\nreturn { formatDateInput, formatLocalDateInput, formatCompactDate };`
)();
}

test('date formatters avoid padStart while preserving zero-padded output', () => {
const { formatDateInput, formatLocalDateInput, formatCompactDate } = loadDateFormatters();
const originalPadStart = String.prototype.padStart;
String.prototype.padStart = function forbiddenPadStart() {
throw new Error('date formatting regressed to String.prototype.padStart');
};

try {
assert.equal(formatDateInput(new Date(Date.UTC(2026, 0, 2, 15, 4, 5))), '2026-01-02');
assert.equal(formatDateInput(new Date(Date.UTC(2026, 10, 12, 15, 4, 5))), '2026-11-12');

const singleDigitLocal = new Date(2026, 0, 2, 12, 0, 0);
assert.equal(formatLocalDateInput(singleDigitLocal), '2026-01-02');
assert.equal(formatCompactDate(singleDigitLocal), '20260102');

const doubleDigitLocal = new Date(2026, 10, 12, 12, 0, 0);
assert.equal(formatLocalDateInput(doubleDigitLocal), '2026-11-12');
assert.equal(formatCompactDate(doubleDigitLocal), '20261112');
} finally {
String.prototype.padStart = originalPadStart;
}
});
Loading