@dogfood-lab/findings 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli.js CHANGED
@@ -45,7 +45,8 @@ import {
45
45
  performAction,
46
46
  performMerge,
47
47
  getReviewQueue,
48
- getEventsForFinding
48
+ getEventsForFinding,
49
+ EDITABLE_FIELDS
49
50
  } from './review/index.js';
50
51
  import {
51
52
  reviewArtifact,
@@ -291,7 +292,8 @@ Commands:
291
292
  accept <id> Accept a finding (--actor, --reason)
292
293
  reject <id> Reject a finding (--actor, --reason, --reject-reason)
293
294
  review <id> Move finding to reviewed (--actor)
294
- edit <id> Edit finding fields (--actor, --set field=value)
295
+ edit <id> Edit finding fields (--actor, --set field=value).
296
+ Editable fields: ${EDITABLE_FIELDS.join(', ')}.
295
297
  merge <ids...> Merge findings (--into <id>, --actor, --reason)
296
298
  reopen <id> Reopen a rejected/accepted finding (--actor, --reason)
297
299
  invalidate <id> Invalidate an accepted finding (--actor, --reason)
@@ -744,6 +746,7 @@ Structured output:
744
746
  const findingId = positional[0];
745
747
  if (!findingId) {
746
748
  console.error('Usage: dogfood findings edit <finding_id> --actor <name> --set field=value [--set field=value]');
749
+ console.error(`Editable fields: ${EDITABLE_FIELDS.join(', ')}`);
747
750
  process.exit(2);
748
751
  }
749
752
  // Parse --set flags
@@ -1323,6 +1326,20 @@ Structured output:
1323
1326
  }
1324
1327
 
1325
1328
  main().catch(err => {
1326
- console.error(err);
1329
+ // F-26179cb8 (Stage C humanization): render the repo-wide structured envelope
1330
+ // sibling bins use (report/cli.js emitError, report/init.js) instead of
1331
+ // dumping the raw Error/stack. The raw stack is a triage aid, not a default —
1332
+ // it stays behind DEBUG so a mis-rooted checkout or an un-caught throw gives
1333
+ // the operator `ERROR [<CODE>]:` + a next step, not a bare Node stack.
1334
+ const code = err && err.code ? err.code : 'UNEXPECTED';
1335
+ const message = err && err.message ? err.message : String(err);
1336
+ console.error(`ERROR [${code}]: ${message}`);
1337
+ console.error(
1338
+ ' Next: run from the testing-os repo root, or set FINDINGS_REPO_ROOT to it; ' +
1339
+ 'run `dogfood findings --help` for usage. Re-run with DEBUG=1 for the stack.'
1340
+ );
1341
+ if (process.env.DEBUG && err && err.stack) {
1342
+ console.error(err.stack);
1343
+ }
1327
1344
  process.exit(2);
1328
1345
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dogfood-lab/findings",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "type": "module",
5
5
  "description": "Finding contract spine for testing-os. Validates, reads, lists, and queries evidence-bound findings — the fourth contract alongside record, scenario, and policy.",
6
6
  "main": "index.js",
@@ -18,7 +18,7 @@
18
18
  "findings": "./cli.js"
19
19
  },
20
20
  "scripts": {
21
- "test": "node --test findings.test.js derive/derive.test.js derive/load-records-skip.test.js derive/d2b-008-collision-guard.test.js derive/d2b-002-write-schema-gate.test.js review/review.test.js review/event-log-loader.test.js review/h4-engine-auto-reject-reason.test.js review/featF-intel-001-review-artifacts.test.js review/featF-intel-001-cli.test.js synthesis/synthesis.test.js synthesis/loaders-skip.test.js synthesis/d2b-001-derive-skipped-signal.test.js synthesis/featF-intel-002-preserve-operator-status.test.js synthesis/featF-intel-003-apply-recommendation.test.js advise/advise.test.js lib/atomic-write.test.js lib/safe-yaml-load.test.js lib/d1b-002-findings-sleepsync.test.js"
21
+ "test": "node --test"
22
22
  },
23
23
  "files": [
24
24
  "index.js",
package/review/index.js CHANGED
@@ -3,4 +3,4 @@
3
3
  */
4
4
  export { isLawfulTransition, validateTransition, ACTION_TARGET_STATUS, REASON_REQUIRED } from './transitions.js';
5
5
  export { createEvent, appendEvent, getEventsForFinding, getAllEvents, getLogPath, generateEventId } from './event-log.js';
6
- export { performAction, performMerge, getReviewQueue } from './review-engine.js';
6
+ export { performAction, performMerge, getReviewQueue, EDITABLE_FIELDS } from './review-engine.js';
@@ -15,6 +15,29 @@ import { parseFinding, validateFinding } from '../validate.js';
15
15
  import { findById, loadFindings } from '../reader.js';
16
16
  import { atomicWriteFileSync } from '../lib/atomic-write.js';
17
17
 
18
+ /**
19
+ * The prose + classification fields an operator may safely target with
20
+ * `edit --set field=value`. This is the human-facing subset of the finding
21
+ * contract: free-text prose and the four classification enums. Identity,
22
+ * lineage, and evidence fields (finding_id, schema_version, source_record_ids,
23
+ * evidence, status, …) are excluded — they are set by the pipeline, not edited
24
+ * in place. The downstream write gate (dogfood-finding.schema.json's
25
+ * additionalProperties:false + enum checks) is the enforcement boundary; this
26
+ * list is what the CLI help renders so the documented set and the gate's
27
+ * intent share one source. Editing an unlisted field is still refused post-hoc
28
+ * by the schema gate — this constant narrows the help, not the enforcement.
29
+ */
30
+ export const EDITABLE_FIELDS = Object.freeze([
31
+ 'title',
32
+ 'summary',
33
+ 'doctrine_statement',
34
+ 'notes',
35
+ 'issue_kind',
36
+ 'root_cause_kind',
37
+ 'remediation_kind',
38
+ 'transfer_scope'
39
+ ]);
40
+
18
41
  /**
19
42
  * Perform a review action on a finding.
20
43
  *