docs(sdlc): add ISO 29110 audit prep note; keep top-level sdlc notes out of seed and render

This commit is contained in:
Thanakorn
2026-10-02 08:05:10 +07:00
parent 4f1c2a0ad1
commit 2def1ef921
6 changed files with 75 additions and 9 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ while IFS= read -r -d '' source; do
destination="$STAGING_DIR/${relative%.md}.pdf"
echo "Rendering ${relative%.md}.pdf"
node "$TOOL_DIR/render-sdlc.mjs" "$source" "$destination"
done < <(find "$SOURCE_DIR" -type f -name '*.md' -print0 | sort -z)
done < <(find "$SOURCE_DIR" -mindepth 2 -type f -name '*.md' -print0 | sort -z)
# Every .pdf gets a Word copy beside it, reconstructed from the rendered page.
# The CI header bands need Playwright, so they are rendered here with node and
+4 -3
View File
@@ -18,12 +18,13 @@ const SCALE = 3; // the band is drawn at 3x so it stays crisp in print
const applyTemplate = (template, values) => template.replace(/{{(\w+)}}/g, (_, key) => values[key] ?? '');
const slug = (title) => title.replace(/[^\w-]+/g, '-').replace(/^-|-$/g, '').toLowerCase() || 'band';
async function markdownFiles(directory) {
// Work products sit in the process folders; top-level files in sdlc/ are notes.
async function markdownFiles(directory, depth = 0) {
const entries = await fs.readdir(directory, { withFileTypes: true });
const results = await Promise.all(entries.map(async (entry) => {
const target = path.join(directory, entry.name);
if (entry.isDirectory()) return markdownFiles(target);
return entry.isFile() && entry.name.endsWith('.md') ? [target] : [];
if (entry.isDirectory()) return markdownFiles(target, depth + 1);
return depth > 0 && entry.isFile() && entry.name.endsWith('.md') ? [target] : [];
}));
return results.flat();
}
+4 -3
View File
@@ -26,12 +26,13 @@ function compact(text) {
return text.normalize('NFC').toLocaleLowerCase().replace(/[^\p{L}\p{N}]/gu, '');
}
async function markdownFiles(directory) {
// Work products sit in the process folders; top-level files in sdlc/ are notes.
async function markdownFiles(directory, depth = 0) {
const entries = await fs.readdir(directory, { withFileTypes: true });
const results = await Promise.all(entries.map(async (entry) => {
const target = path.join(directory, entry.name);
if (entry.isDirectory()) return markdownFiles(target);
return entry.isFile() && entry.name.endsWith('.md') ? [target] : [];
if (entry.isDirectory()) return markdownFiles(target, depth + 1);
return depth > 0 && entry.isFile() && entry.name.endsWith('.md') ? [target] : [];
}));
return results.flat();
}
+3 -1
View File
@@ -74,7 +74,9 @@ async function main() {
const hindsight = hindsightErrors(docs, root);
if (hindsight.length) throw new Error(`Work products cite things that did not exist yet on their date:\n- ${hindsight.join('\n- ')}`);
await fs.rm(target, { recursive: true, force: true });
// Only the process folders are generated; files at the top of sdlc/ are
// working notes (e.g. the audit prep) and are neither seeded nor rendered.
for (const folder of FOLDERS) await fs.rm(path.join(target, folder), { recursive: true, force: true });
for (const folder of FOLDERS) await fs.mkdir(path.join(target, folder), { recursive: true });
for (const d of docs) {
await fs.writeFile(path.join(target, d.dir, `${d.name}.md`), d.md, 'utf8');
+1 -1
View File
@@ -9,7 +9,7 @@ PACKAGE_DIR="$(realpath -m "${1:-$ROOT_DIR/sdlc-delivery}")"
[[ -d "$PACKAGE_DIR" ]] || { echo "Delivery package not found: $PACKAGE_DIR" >&2; exit 2; }
expected="$(find "$SOURCE_DIR" -type f -name '*.md' | wc -l | tr -d ' ')"
expected="$(find "$SOURCE_DIR" -mindepth 2 -type f -name '*.md' | wc -l | tr -d ' ')"
produced="$(find "$PACKAGE_DIR" -type f -name '*.pdf' | wc -l | tr -d ' ')"
[[ "$expected" == "$produced" ]] || { echo "Expected $expected PDFs, found $produced." >&2; exit 1; }