feat(work): add ISO timestamps + auto-bump on staged work-doc changes
- New scripts/work/bump-updated-timestamps.mjs stamps the `updated:`
frontmatter field to the current ISO 8601 UTC timestamp on every
staged docs/work/**/*.md file. Idempotent; adds the field after
`created:` if missing.
- .husky/pre-commit invokes the bump script as step 2 (before
rebuild-state) so _state.json sees the fresh timestamp.
- Backfill all existing work docs (4 PRDs + 3 epics + 21 stories):
* created: promoted from \`YYYY-MM-DD\` -> ISO timestamp using
git log --diff-filter=A on each file (first-commit date for
stories that had no \`created:\` line, midnight UTC for PRDs
and epics that had date-only created).
* updated: added from \`git log -1 --format=%aI\` on each file
(last-commit timestamp); will be re-stamped to "now" by the
pre-commit hook on this commit.
Stories that had no \`created:\` line now get one.
This commit is contained in:
@@ -6,7 +6,10 @@
|
|||||||
# 1. lint-staged: format + lint staged files
|
# 1. lint-staged: format + lint staged files
|
||||||
pnpm exec lint-staged || exit 1
|
pnpm exec lint-staged || exit 1
|
||||||
|
|
||||||
# 2. If any docs/work/ markdown is staged, regenerate _state.json + re-stage it
|
# 2. Stamp the `updated:` frontmatter field on every staged docs/work/ md file.
|
||||||
|
node scripts/work/bump-updated-timestamps.mjs || exit 1
|
||||||
|
|
||||||
|
# 3. If any docs/work/ markdown is staged, regenerate _state.json + re-stage it
|
||||||
if git diff --cached --name-only | grep -qE '^docs/work/.*\.md$'; then
|
if git diff --cached --name-only | grep -qE '^docs/work/.*\.md$'; then
|
||||||
pnpm work rebuild-state
|
pnpm work rebuild-state
|
||||||
git add docs/work/_state.json
|
git add docs/work/_state.json
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: core-shared
|
feature: core-shared
|
||||||
depends-on: []
|
depends-on: []
|
||||||
blocks: [02-migrate-feature-binders, 03-update-generator-templates]
|
blocks: [02-migrate-feature-binders, 03-update-generator-templates]
|
||||||
|
created: 2026-05-13T19:17:10+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: auth, blog, media, marketing-pages, navigation
|
feature: auth, blog, media, marketing-pages, navigation
|
||||||
depends-on: [01-wire-use-case-helper]
|
depends-on: [01-wire-use-case-helper]
|
||||||
blocks: []
|
blocks: []
|
||||||
|
created: 2026-05-13T19:17:10+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: core-shared
|
feature: core-shared
|
||||||
depends-on: [01-wire-use-case-helper]
|
depends-on: [01-wire-use-case-helper]
|
||||||
blocks: []
|
blocks: []
|
||||||
|
created: 2026-05-13T19:17:10+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ title: Collapse binder duplication via wireUseCase helper
|
|||||||
type: epic
|
type: epic
|
||||||
status: done
|
status: done
|
||||||
features: [core-shared, auth, blog, media, marketing-pages, navigation]
|
features: [core-shared, auth, blog, media, marketing-pages, navigation]
|
||||||
created: 2026-05-13
|
created: 2026-05-13T00:00:00Z
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ blocks:
|
|||||||
04-major-bump-reevaluation,
|
04-major-bump-reevaluation,
|
||||||
05-trace-revalidation-workflow,
|
05-trace-revalidation-workflow,
|
||||||
]
|
]
|
||||||
|
created: 2026-05-14T18:59:12+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: tooling
|
feature: tooling
|
||||||
depends-on: [01-trace-schema-extensions]
|
depends-on: [01-trace-schema-extensions]
|
||||||
blocks: [08-reviewer-prompt-update]
|
blocks: [08-reviewer-prompt-update]
|
||||||
|
created: 2026-05-14T18:59:12+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: tooling
|
feature: tooling
|
||||||
depends-on: []
|
depends-on: []
|
||||||
blocks: [09-ci-security-guide-and-docs]
|
blocks: [09-ci-security-guide-and-docs]
|
||||||
|
created: 2026-05-14T18:59:12+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: scripts
|
feature: scripts
|
||||||
depends-on: [01-trace-schema-extensions]
|
depends-on: [01-trace-schema-extensions]
|
||||||
blocks: [05-trace-revalidation-workflow]
|
blocks: [05-trace-revalidation-workflow]
|
||||||
|
created: 2026-05-14T18:59:12+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: scripts
|
feature: scripts
|
||||||
depends-on: [01-trace-schema-extensions, 04-major-bump-reevaluation]
|
depends-on: [01-trace-schema-extensions, 04-major-bump-reevaluation]
|
||||||
blocks: [09-ci-security-guide-and-docs]
|
blocks: [09-ci-security-guide-and-docs]
|
||||||
|
created: 2026-05-14T18:59:12+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: tooling
|
feature: tooling
|
||||||
depends-on: []
|
depends-on: []
|
||||||
blocks: [08-reviewer-prompt-update]
|
blocks: [08-reviewer-prompt-update]
|
||||||
|
created: 2026-05-14T18:59:12+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: tooling
|
feature: tooling
|
||||||
depends-on: []
|
depends-on: []
|
||||||
blocks: [09-ci-security-guide-and-docs]
|
blocks: [09-ci-security-guide-and-docs]
|
||||||
|
created: 2026-05-14T18:59:12+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: tooling
|
feature: tooling
|
||||||
depends-on: [02-socket-integration, 06-codeql-and-audit-signatures]
|
depends-on: [02-socket-integration, 06-codeql-and-audit-signatures]
|
||||||
blocks: [09-ci-security-guide-and-docs]
|
blocks: [09-ci-security-guide-and-docs]
|
||||||
|
created: 2026-05-14T18:59:12+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ depends-on:
|
|||||||
08-reviewer-prompt-update,
|
08-reviewer-prompt-update,
|
||||||
]
|
]
|
||||||
blocks: []
|
blocks: []
|
||||||
|
created: 2026-05-14T18:59:12+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ title: CI security + supply-chain enforcement stack
|
|||||||
type: epic
|
type: epic
|
||||||
status: done
|
status: done
|
||||||
features: [scripts, tooling, docs]
|
features: [scripts, tooling, docs]
|
||||||
created: 2026-05-14
|
created: 2026-05-14T00:00:00Z
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ blocks:
|
|||||||
07-generator-pre-shipped-traces,
|
07-generator-pre-shipped-traces,
|
||||||
08-backfill-traces,
|
08-backfill-traces,
|
||||||
]
|
]
|
||||||
|
created: 2026-05-14T06:52:02+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: scripts
|
feature: scripts
|
||||||
depends-on: [01-trace-schema-foundation]
|
depends-on: [01-trace-schema-foundation]
|
||||||
blocks: [06-sandcastle-reviewer-prompt]
|
blocks: [06-sandcastle-reviewer-prompt]
|
||||||
|
created: 2026-05-14T06:52:02+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: tooling
|
feature: tooling
|
||||||
depends-on: []
|
depends-on: []
|
||||||
blocks: []
|
blocks: []
|
||||||
|
created: 2026-05-14T06:52:02+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: tooling
|
feature: tooling
|
||||||
depends-on: [01-trace-schema-foundation]
|
depends-on: [01-trace-schema-foundation]
|
||||||
blocks: [05-human-guide]
|
blocks: [05-human-guide]
|
||||||
|
created: 2026-05-14T06:52:02+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: docs
|
feature: docs
|
||||||
depends-on: [04-evaluate-library-skill]
|
depends-on: [04-evaluate-library-skill]
|
||||||
blocks: [09-claude-md-update]
|
blocks: [09-claude-md-update]
|
||||||
|
created: 2026-05-14T06:52:02+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: tooling
|
feature: tooling
|
||||||
depends-on: [02-pre-commit-check-script]
|
depends-on: [02-pre-commit-check-script]
|
||||||
blocks: []
|
blocks: []
|
||||||
|
created: 2026-05-14T06:52:02+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: tooling
|
feature: tooling
|
||||||
depends-on: [01-trace-schema-foundation]
|
depends-on: [01-trace-schema-foundation]
|
||||||
blocks: []
|
blocks: []
|
||||||
|
created: 2026-05-14T06:52:02+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: docs
|
feature: docs
|
||||||
depends-on: [01-trace-schema-foundation]
|
depends-on: [01-trace-schema-foundation]
|
||||||
blocks: []
|
blocks: []
|
||||||
|
created: 2026-05-14T06:52:02+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ status: done
|
|||||||
feature: docs
|
feature: docs
|
||||||
depends-on: [05-human-guide]
|
depends-on: [05-human-guide]
|
||||||
blocks: []
|
blocks: []
|
||||||
|
created: 2026-05-14T06:52:02+02:00
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ title: Library evaluation policy — skill, traces, enforcement stack
|
|||||||
type: epic
|
type: epic
|
||||||
status: done
|
status: done
|
||||||
features: [scripts, tooling, docs]
|
features: [scripts, tooling, docs]
|
||||||
created: 2026-05-14
|
created: 2026-05-14T00:00:00Z
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"updated_at": "2026-05-14T19:05:08.479Z",
|
"updated_at": "2026-05-14T19:10:35.823Z",
|
||||||
"epics": {
|
"epics": {
|
||||||
"2026-05-13-binder-wrap-helper": {
|
"2026-05-13-binder-wrap-helper": {
|
||||||
"status": "done",
|
"status": "done",
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ type: prd
|
|||||||
status: approved
|
status: approved
|
||||||
author: danijel
|
author: danijel
|
||||||
elicitation-session: improve-codebase-architecture-2026-05-13
|
elicitation-session: improve-codebase-architecture-2026-05-13
|
||||||
created: 2026-05-13
|
created: 2026-05-13T00:00:00Z
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
---
|
---
|
||||||
|
|
||||||
## Problem
|
## Problem
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ type: prd
|
|||||||
status: shipped
|
status: shipped
|
||||||
author: danijel
|
author: danijel
|
||||||
elicitation-session: brainstorm-2026-05-13
|
elicitation-session: brainstorm-2026-05-13
|
||||||
created: 2026-05-13
|
created: 2026-05-13T00:00:00Z
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
shipped: 2026-05-13
|
shipped: 2026-05-13
|
||||||
shipping-commits:
|
shipping-commits:
|
||||||
- 7eb783a (PRD)
|
- 7eb783a (PRD)
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ title: CI security + supply-chain enforcement stack
|
|||||||
type: prd
|
type: prd
|
||||||
status: approved
|
status: approved
|
||||||
author: danijel
|
author: danijel
|
||||||
created: 2026-05-14
|
created: 2026-05-14T00:00:00Z
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
adr: adr-023
|
adr: adr-023
|
||||||
builds-on: 2026-05-14-library-evaluation-policy
|
builds-on: 2026-05-14-library-evaluation-policy
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ title: Library evaluation policy — skill, traces, enforcement stack
|
|||||||
type: prd
|
type: prd
|
||||||
status: approved
|
status: approved
|
||||||
author: danijel
|
author: danijel
|
||||||
created: 2026-05-14
|
created: 2026-05-14T00:00:00Z
|
||||||
|
updated: 2026-05-14T19:10:35.370Z
|
||||||
adr: adr-022
|
adr: adr-022
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
78
scripts/work/bump-updated-timestamps.mjs
Normal file
78
scripts/work/bump-updated-timestamps.mjs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Stamp every staged `docs/work/**\/*.md` file's frontmatter `updated:` field
|
||||||
|
* to the current ISO 8601 timestamp. Runs from `.husky/pre-commit` before
|
||||||
|
* `pnpm work rebuild-state`, so `_state.json` sees the fresh value.
|
||||||
|
*
|
||||||
|
* Idempotent: re-running produces the same result. The script silently no-ops
|
||||||
|
* on files without frontmatter or without an `updated:` line to replace —
|
||||||
|
* adds the field after `created:` if missing.
|
||||||
|
*
|
||||||
|
* Only stamps files explicitly listed in the staged diff; never walks the
|
||||||
|
* tree. That way the timestamp tracks "the last commit that actually
|
||||||
|
* modified the file," not "the last commit period."
|
||||||
|
*/
|
||||||
|
import { execSync } from "node:child_process";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
|
||||||
|
const REPO_ROOT = execSync("git rev-parse --show-toplevel", {
|
||||||
|
encoding: "utf8",
|
||||||
|
}).trim();
|
||||||
|
|
||||||
|
function stagedWorkDocs() {
|
||||||
|
const out = execSync("git diff --cached --name-only --diff-filter=ACMR", {
|
||||||
|
cwd: REPO_ROOT,
|
||||||
|
encoding: "utf8",
|
||||||
|
});
|
||||||
|
return out
|
||||||
|
.split("\n")
|
||||||
|
.map((p) => p.trim())
|
||||||
|
.filter(
|
||||||
|
(p) =>
|
||||||
|
p.startsWith("docs/work/") &&
|
||||||
|
p.endsWith(".md") &&
|
||||||
|
!p.endsWith("README.md"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stampUpdated(content, isoNow) {
|
||||||
|
const fmMatch = content.match(/^(---\n)([\s\S]+?)(\n---)/);
|
||||||
|
if (!fmMatch) return content;
|
||||||
|
const [full, openDelim, body, closeDelim] = fmMatch;
|
||||||
|
|
||||||
|
let newBody;
|
||||||
|
if (/^updated:\s*/m.test(body)) {
|
||||||
|
newBody = body.replace(/^updated:\s*.*$/m, `updated: ${isoNow}`);
|
||||||
|
} else if (/^created:\s*/m.test(body)) {
|
||||||
|
// Insert `updated:` immediately after the `created:` line.
|
||||||
|
newBody = body.replace(/^(created:\s*.*)$/m, `$1\nupdated: ${isoNow}`);
|
||||||
|
} else {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
return content.replace(full, `${openDelim}${newBody}${closeDelim}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
const files = stagedWorkDocs();
|
||||||
|
if (files.length === 0) return;
|
||||||
|
const isoNow = new Date().toISOString();
|
||||||
|
let touched = 0;
|
||||||
|
for (const rel of files) {
|
||||||
|
const abs = path.join(REPO_ROOT, rel);
|
||||||
|
if (!fs.existsSync(abs)) continue;
|
||||||
|
const original = fs.readFileSync(abs, "utf8");
|
||||||
|
const next = stampUpdated(original, isoNow);
|
||||||
|
if (next === original) continue;
|
||||||
|
fs.writeFileSync(abs, next);
|
||||||
|
execSync(`git add ${JSON.stringify(rel)}`, { cwd: REPO_ROOT });
|
||||||
|
touched++;
|
||||||
|
}
|
||||||
|
if (touched > 0) {
|
||||||
|
console.log(
|
||||||
|
`bump-updated-timestamps: stamped ${touched} file(s) at ${isoNow}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
Reference in New Issue
Block a user