[WIP] Add machine-readable PIR status sidecar for cross-cycle inheritance#2036
[WIP] Add machine-readable PIR status sidecar for cross-cycle inheritance#2036
Conversation
🏷️ Automatic Labeling SummaryThis PR has been automatically labeled based on the files changed and PR metadata. Applied Labels: size-xs Label Categories
For more information, see |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
…d guide update Agent-Logs-Url: https://github.com/Hack23/riksdagsmonitor/sessions/28d53555-ee00-4cde-80b9-c5570d33815c Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
…path parsing Agent-Logs-Url: https://github.com/Hack23/riksdagsmonitor/sessions/28d53555-ee00-4cde-80b9-c5570d33815c Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
There was a problem hiding this comment.
Pull request overview
Adds a machine-readable PIR status sidecar (pir-status.json) to support cross-cycle PIR inheritance, with a roll-forward script and CI analysis-gate enforcement.
Changes:
- Introduces
schemas/pir-status.schema.json(JSON Schema 2020-12) defining the PIR status sidecar contract. - Adds
scripts/roll-forward-pirs.tsto propagate PIRs across analysis cycles with confidence degradation for open items. - Updates analysis gate + methodology docs, and adds Vitest contract/integration tests covering schema, gate references, and roll-forward behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
tests/pir-status-contract.test.ts |
Contract + integration tests for schema validity, gate references, and roll-forward CLI behavior. |
scripts/roll-forward-pirs.ts |
New CLI tool to roll forward PIR sidecars between cycles and degrade confidence for open PIRs. |
schemas/pir-status.schema.json |
New schema defining required fields and PIR entry structure for pir-status.json. |
analysis/methodologies/ai-driven-analysis-guide.md |
Documents required pir-status.json generation and roll-forward usage. |
.github/prompts/05-analysis-gate.md |
Adds Check 10 to require and structurally validate pir-status.json in the analysis output directory. |
| - Add one more named actor (MP, minister, official) to every stakeholder and SWOT entry. | ||
| - Add one more dok_id or vote-record citation to every evidence column that has < 2 citations. | ||
| - **Tag every key finding to a PIR/EEI** from the catalog in `political-style-guide.md`. | ||
| - **Write `pir-status.json`** — every cycle must produce `$ANALYSIS_DIR/pir-status.json` conforming to `schemas/pir-status.schema.json` v1.0 (required fields: `schema_version`, `cycle`, `date`, `subfolder`, `pirs`, `generated_at`). Extract PIRs from `intelligence-assessment.md` and set each status to `open`. This file is the machine-readable PIR sidecar used for automated roll-forward (see `scripts/roll-forward-pirs.ts`) and CI gate enforcement (Check 10 in `05-analysis-gate.md`). |
| except Exception: | ||
| sys.exit(1) | ||
| " 2>/dev/null || { echo "❌ pir-status.json: 'pirs' field must be a JSON array"; FAIL=1; } | ||
| # each open PIR must have pir_id, statement, status, confidence |
| // Non-open PIRs are carried forward unchanged for history. | ||
| return { ...p, inherits_from: [p.pir_id] }; |
| return idx < CONFIDENCE_ORDER.length - 1 | ||
| ? (CONFIDENCE_ORDER[idx + 1] as Confidence) |
| /** Basic structural validation — not a full JSON Schema validator. */ | ||
| function validateSource(raw: unknown, filePath: string): PirStatusFile { | ||
| if (typeof raw !== 'object' || raw === null) { | ||
| throw new Error(`${filePath}: not a JSON object`); | ||
| } | ||
| const obj = raw as Record<string, unknown>; | ||
| for (const key of ['schema_version', 'cycle', 'date', 'pirs'] as const) { | ||
| if (!(key in obj)) throw new Error(`${filePath}: missing required field '${key}'`); | ||
| } | ||
| if (obj['schema_version'] !== '1.0') { | ||
| throw new Error(`${filePath}: unsupported schema_version '${String(obj['schema_version'])}'`); | ||
| } | ||
| if (!Array.isArray(obj['pirs'])) { | ||
| throw new Error(`${filePath}: 'pirs' must be an array`); | ||
| } |
| main(process.argv.slice(2)).catch((err: unknown) => { | ||
| console.error('Unexpected error:', err); | ||
| process.exit(1); | ||
| }); |
| "answer_summary": { | ||
| "type": "string", | ||
| "description": "Short (≤ 500 chars) summary of the evidence or event that answered this PIR. Populate only when status='answered'.", | ||
| "maxLength": 500 | ||
| }, |
| }, | ||
| "subfolder": { | ||
| "type": "string", | ||
| "description": "Relative subfolder path under `analysis/daily/YYYY-MM-DD/` — must equal the `cycle` value.", |
|
@copilot apply changes based on the comments in this thread and fix TypeScript & JavaScript Testing / Unit Tests (Vitest) (pull_request) |
- Schema: add if/then/else for answer_summary; soften subfolder description - roll-forward-pirs.ts: export helpers; isMainModule guard; degrade(-1) throws; preserve inherits_from for non-open PIRs; strict enum validation in validateSource; runMain takes injected IO for testability - Analysis gate (Check 10): iterate all PIRs (comment matches behavior), enforce subfolder===cycle and conditional answer_summary - Guide: clarify newly extracted PIRs default to open; rolled-forward preserve prior status - Tests: 69 direct unit tests via imports (was 35 via execSync); use os.tmpdir() to avoid armour false-positives. Coverage now 84.59% (≥80%) Agent-Logs-Url: https://github.com/Hack23/riksdagsmonitor/sessions/1f753652-b2a1-48e7-bc4e-89aeed758265 Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Addressed in 38f50c0. All 8 review threads resolved: schema now uses if/then/else for |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
There was a problem hiding this comment.
Pull request overview
Adds a machine-readable pir-status.json “sidecar” contract to enable PIR status roll-forward across analysis cycles, backed by a schema, a roll-forward CLI script, analysis-gate enforcement, and a dedicated test suite.
Changes:
- Introduces
schemas/pir-status.schema.json(v1.0) defining the sidecar structure and conditionalanswer_summary. - Adds
scripts/roll-forward-pirs.tsto roll forward PIRs between cycles (degrade confidence for open PIRs, preserve non-open PIRs). - Updates analysis gate + methodology guide and adds a comprehensive contract/unit test suite.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
schemas/pir-status.schema.json |
Defines the JSON Schema contract for pir-status.json. |
scripts/roll-forward-pirs.ts |
Implements roll-forward CLI + exported helpers for testing. |
.github/prompts/05-analysis-gate.md |
Enforces presence/shape invariants for pir-status.json in Check 10. |
analysis/methodologies/ai-driven-analysis-guide.md |
Documents the new required artifact and roll-forward workflow. |
tests/pir-status-contract.test.ts |
Adds contract + unit tests for schema, script helpers, and gate text. |
| else if (arg === '--date') args.date = argv[++i]; | ||
| else if (arg === '--cycle') args.cycle = argv[++i] as CycleType; | ||
| else if (arg === '--dry-run') args.dryRun = true; | ||
| else if (arg === '--max-lookback') args.maxLookback = parseInt(argv[++i] ?? '14', 10); |
| const relativeSourcePath = sourcePath.startsWith(repoRoot + path.sep) | ||
| ? sourcePath.slice(repoRoot.length + 1).replace(/\\/g, '/') | ||
| : sourcePath.replace(/\\/g, '/'); | ||
|
|
||
| return { | ||
| schema_version: '1.0', | ||
| cycle: targetCycle, | ||
| date: targetDate, | ||
| subfolder: targetCycle, | ||
| generated_at: now().toISOString(), | ||
| inherited_from: relativeSourcePath, | ||
| pirs, | ||
| }; |
| # Check 10 — PIR status sidecar (`pir-status.json`) | ||
| # A valid pir-status.json must be present after every analysis run so that | ||
| # open PIRs can be automatically rolled forward to the next cycle. | ||
| # Schema: schemas/pir-status.schema.json (v1.0) | ||
| # Roll-forward script: scripts/roll-forward-pirs.ts |
|
|
||
| it('runMain does not invoke exit when invoked with valid args', () => { | ||
| // Already covered by happy-path test, but assert the spy pattern is clean. | ||
| const exitSpy = vi.fn(); | ||
| const noopOut = { write: () => true } as unknown as NodeJS.WritableStream; | ||
| expect(typeof exitSpy).toBe('function'); | ||
| expect(typeof noopOut.write).toBe('function'); | ||
| }); |
| }, | ||
| "answer_summary": { | ||
| "type": "string", | ||
| "description": "Short (≤ 500 chars) summary of the evidence or event that answered this PIR. Populate only when status='answered'.", |
| export function validateSource(raw: unknown, filePath: string): PirStatusFile { | ||
| if (typeof raw !== 'object' || raw === null) { | ||
| throw new Error(`${filePath}: not a JSON object`); | ||
| } | ||
| const obj = raw as Record<string, unknown>; | ||
| for (const key of ['schema_version', 'cycle', 'date', 'pirs'] as const) { | ||
| if (!(key in obj)) throw new Error(`${filePath}: missing required field '${key}'`); | ||
| } | ||
| if (obj['schema_version'] !== '1.0') { | ||
| throw new Error( | ||
| `${filePath}: unsupported schema_version '${String(obj['schema_version'])}'`, | ||
| ); | ||
| } | ||
| if (!Array.isArray(obj['pirs'])) { | ||
| throw new Error(`${filePath}: 'pirs' must be an array`); | ||
| } |
|
@copilot apply changes based on the comments in this thread |
Agent-Logs-Url: https://github.com/Hack23/riksdagsmonitor/sessions/60e3718d-fdcf-4ef9-8d6b-eeccec428f9b Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
Agent-Logs-Url: https://github.com/Hack23/riksdagsmonitor/sessions/60e3718d-fdcf-4ef9-8d6b-eeccec428f9b Co-authored-by: pethers <1726836+pethers@users.noreply.github.com>
Addressed in e69f8cf and follow-up f239bb0. The second review thread is resolved: |
🔍 Lighthouse Performance Audit
📥 Download full Lighthouse report Budget Compliance: Performance budgets enforced via |
Adds a machine-readable
pir-status.jsonsidecar contract to support cross-cycle PIR inheritance, with a JSON Schema, roll-forward CLI, analysis-gate enforcement, and comprehensive Vitest coverage.Changes Made
schemas/pir-status.schema.jsonusing JSON Schema 2020-12, including conditionalanswer_summaryvalidation andminLength: 1.scripts/roll-forward-pirs.tsto roll forward PIRs across analysis cycles, degrade confidence for open PIRs, preserve non-open PIR inheritance history, validate source sidecars strictly, normalizeinherited_frompaths withpath.relative(), and validate--max-lookback..github/prompts/05-analysis-gate.mdwith PIR status sidecar enforcement as Check 9, includingsubfolder === cycle, PIR field validation, confidence/status validation, and conditionalanswer_summarychecks.analysis/methodologies/ai-driven-analysis-guide.mdto documentpir-status.jsoncreation, roll-forward behavior, and status preservation semantics.tests/pir-status-contract.test.tswith direct-import unit and contract tests covering schema, validation, roll-forward behavior, CLI argument handling, gate references, and regression cases.Testing