@@ -164,8 +164,6 @@ int num_comp_logs;
164164 */
165165enum orchestrator_saturation {
166166 ORCH_SAT_RESULTS_FULL = 1u << 0 , /* MAX_RESULTS hit; drops new records */
167- ORCH_SAT_PROVENANCE_FULL =
168- 1u << 1 , /* MAX_PROVENANCE hit; drops later contributors */
169167 ORCH_SAT_COMPONENT_LINES_DROPPED =
170168 1u << 2 , /* alloc failure during verbose-line capture */
171169};
@@ -560,6 +558,30 @@ static enum kasld_confidence conf_from_wire(const char *s) {
560558 return CONF_UNKNOWN ;
561559}
562560
561+ /* Map a method: meta value to its bit in struct result.method_set (0 if the
562+ * value is empty or unrecognised). Mirrors the closed set in enum kasld_method.
563+ */
564+ static uint16_t method_bit (const char * s ) {
565+ int m = -1 ;
566+ if (!s || !* s )
567+ return 0 ;
568+ if (strcmp (s , "parsed" ) == 0 )
569+ m = KM_PARSED ;
570+ else if (strcmp (s , "derived" ) == 0 )
571+ m = KM_DERIVED ;
572+ else if (strcmp (s , "inferred" ) == 0 )
573+ m = KM_INFERRED ;
574+ else if (strcmp (s , "heuristic" ) == 0 )
575+ m = KM_HEURISTIC ;
576+ else if (strcmp (s , "timing" ) == 0 )
577+ m = KM_TIMING ;
578+ else if (strcmp (s , "brute" ) == 0 )
579+ m = KM_BRUTE ;
580+ else if (strcmp (s , "detection" ) == 0 )
581+ m = KM_DETECTION ;
582+ return m < 0 ? 0u : (uint16_t )(1u << m );
583+ }
584+
563585/* Power-of-two test, allowing v=0 to mean "no constraint" but the caller
564586 * gates on v != 0 separately. */
565587static int is_pow2 (unsigned long v ) { return v && !(v & (v - 1 )); }
@@ -879,11 +901,7 @@ static int capture_result(const char *line, const char *method,
879901 memcpy (r -> origins [0 ], origin , ol );
880902 r -> origins [0 ][ol ] = '\0' ;
881903 }
882- if (method && * method ) {
883- size_t ml = strnlen (method , METHOD_LEN - 1 );
884- memcpy (r -> methods [0 ], method , ml );
885- r -> methods [0 ][ml ] = '\0' ;
886- }
904+ r -> method_set = method_bit (method );
887905 r -> provenance_count = 1 ;
888906 return 1 ;
889907}
@@ -1710,22 +1728,14 @@ static int provenance_has(const struct result *r, const char *s) {
17101728 return 0 ;
17111729}
17121730
1713- static void provenance_add (struct result * r , const char * origin ,
1714- const char * method ) {
1731+ static void provenance_add (struct result * r , const char * origin ) {
17151732 if (origin && * origin && provenance_has (r , origin ))
17161733 return ;
1717- if (r -> provenance_count >= MAX_PROVENANCE ) {
1718- orchestrator_saturation |= ORCH_SAT_PROVENANCE_FULL ;
1719- static int warned ;
1720- if (!warned && !quiet ) {
1721- fprintf (stderr ,
1722- "warning: merged record provenance capped at MAX_PROVENANCE=%d; "
1723- "later contributors dropped\n" ,
1724- MAX_PROVENANCE );
1725- warned = 1 ;
1726- }
1734+ /* Distinct origins <= number of components <= MAX_PROVENANCE, so this guard
1735+ * never binds; it only keeps the write in-bounds if that invariant changes.
1736+ */
1737+ if (r -> provenance_count >= MAX_PROVENANCE )
17271738 return ;
1728- }
17291739 int slot = r -> provenance_count ++ ;
17301740 if (origin && * origin ) {
17311741 size_t ol = strnlen (origin , ORIGIN_LEN - 1 );
@@ -1734,13 +1744,6 @@ static void provenance_add(struct result *r, const char *origin,
17341744 } else {
17351745 r -> origins [slot ][0 ] = '\0' ;
17361746 }
1737- if (method && * method ) {
1738- size_t ml = strnlen (method , METHOD_LEN - 1 );
1739- memcpy (r -> methods [slot ], method , ml );
1740- r -> methods [slot ][ml ] = '\0' ;
1741- } else {
1742- r -> methods [slot ][0 ] = '\0' ;
1743- }
17441747}
17451748
17461749static void merge_into (struct result * a , const struct result * b ,
@@ -1782,8 +1785,9 @@ static void merge_into(struct result *a, const struct result *b,
17821785 }
17831786 if (conf_weight (b -> conf ) > conf_weight (a -> conf ))
17841787 a -> conf = b -> conf ;
1788+ a -> method_set |= b -> method_set ;
17851789 for (int i = 0 ; i < b -> provenance_count ; i ++ )
1786- provenance_add (a , b -> origins [i ], b -> methods [ i ] );
1790+ provenance_add (a , b -> origins [i ]);
17871791}
17881792
17891793static int merge_consistent (const struct result * a ) {
@@ -2454,9 +2458,9 @@ static void engine_report_saturation(const struct engine *e) {
24542458 ESTIMATE_MAX_CONFLICTS );
24552459}
24562460
2457- /* Sibling reporter for orchestrator-side caps (results[], merged-record
2458- * provenance, per-component verbose-line capture). Same diagnostic shape
2459- * as engine_report_saturation; surfaces under --verbose. */
2461+ /* Sibling reporter for orchestrator-side caps (results[], per-component
2462+ * verbose-line capture). Same diagnostic shape as engine_report_saturation;
2463+ * surfaces under --verbose. */
24602464static void orchestrator_report_saturation (void ) {
24612465 if (!orchestrator_saturation )
24622466 return ;
@@ -2465,12 +2469,6 @@ static void orchestrator_report_saturation(void) {
24652469 "[orchestrator] saturation: MAX_RESULTS (%d) reached; "
24662470 "further leak/scalar observations were dropped at capture\n" ,
24672471 MAX_RESULTS );
2468- if (orchestrator_saturation & ORCH_SAT_PROVENANCE_FULL )
2469- fprintf (stderr ,
2470- "[orchestrator] saturation: MAX_PROVENANCE (%d) reached on at "
2471- "least one merged record; additional contributors were not "
2472- "recorded (the record's resolved value is unaffected)\n" ,
2473- MAX_PROVENANCE );
24742472 if (orchestrator_saturation & ORCH_SAT_COMPONENT_LINES_DROPPED )
24752473 fprintf (stderr ,
24762474 "[orchestrator] saturation: allocation failure while capturing "
0 commit comments