From ad39da3bba5dddfb414a028cc7623e84f961bb32 Mon Sep 17 00:00:00 2001 From: EHotwagner Date: Fri, 2 Oct 2026 16:23:12 +0200 Subject: [PATCH 1/3] Reproduce buffered infolog refusal and retain bounded cause counters --- docs/roadmaps/barc-01-useful-play.md | 18 ++++++ .../fixtures/complete-record-helper/README.md | 26 ++++++++ .../complete-record-helper/buffered_writer.py | 51 ++++++++++++++++ .../complete-record-helper/growing_log.py | 53 ++++++++++++++--- .../test_buffered_writer.py | 59 +++++++++++++++++++ .../test_growing_log.py | 29 ++++++++- .../tests/check-runtime-evidence.sh | 7 +++ 7 files changed, 235 insertions(+), 8 deletions(-) create mode 100644 tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/buffered_writer.py create mode 100644 tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/test_buffered_writer.py diff --git a/docs/roadmaps/barc-01-useful-play.md b/docs/roadmaps/barc-01-useful-play.md index 14b2218..5f188d8 100644 --- a/docs/roadmaps/barc-01-useful-play.md +++ b/docs/roadmaps/barc-01-useful-play.md @@ -164,3 +164,21 @@ engine/plugin custody and positive Replace acceptance remain open at native 0/6. It preserves frozen browser v1 types and the old rally patch/evidence. Stock source merge does not activate that custom engine, qualify local/generated input journeys or publish/install the product. + +### BARC-01.5f buffered-producer continuation + +- [ ] **BARC-01.5f-RP1 — Reproduce stock buffering and distinguish bounded refusal causes.** + The source candidate adds [ordinary libc buffered-writer controls](../../tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/test_buffered_writer.py) + against the actual held-FD adapter. Five public checks pass: growing partial + EOF exhausts 32 completed probes; a one-byte read control exhausts 128 calls + during the first probe; flush promotes the exact untrimmed sample; failed + consumption retains bounded counters with a digest receipt; destination + collision preserves original refusal and existing bytes. The two exhaustion + controls retain the same policy failure code while distinguishing their + mechanical cause. Real compiled-policy growth verification remains pending. + The [fixture contract](../../tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/README.md) + describes the separate observation/receipt retained by the actual adapter in + the attempt root. Typed F# authority, settlement behavior and runtime caps are + unchanged. RP1 source delivery does not qualify useful play (still 0/6) or + authorize native dispatch: RP2 complete-record contract qualification and RP3 + capacity evidence are both required before a joined successor and operation. diff --git a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/README.md b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/README.md index 3459763..172b40e 100644 --- a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/README.md +++ b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/README.md @@ -5,3 +5,29 @@ complete-record correspondence gate. The gate copies the Python files to a tempo mode-local directory and generates `source-manifest.json` from the checked-out commit and tree. It contains no game payload, credential, private packet, runtime grant, or accepted native observation. The fixture can only produce synthetic growing-log and policy inputs. + + +RP1 adds `buffered_writer.py`: public atlas message bodies verified against +Recoil `2639eedac7d1fd67d793ec93ebd27f014f336a14`, ordinary libc `fopen("w")`, +`setvbuf(NULL, _IOFBF, 8192)` and `fprintf("%s\n")`. The libc implementation +may choose a smaller effective buffer, exactly as stock FileSink permits. Tests +use acknowledged writes and held writer FDs, with no fabricated transcript. +`python3 -m unittest -v test_buffered_writer` runs the public mechanical controls +without .NET. The real compiled policy growth controls run in the coherent gate. + +On a failed `consume`, the actual adapter retains +`infolog-mechanical-.json` and its `.receipt.json` in the validated +attempt root, mode 0600, exclusive creation. The <=4096-byte observation contains +only closed categories, counters, byte lengths, sample hash and monotonic elapsed +microseconds; the receipt binds its filename, bytes/hash and source-set hash. +No raw log, path, process identity or exception text is included. A read-call cap +is per exact-read operation; aggregate calls across probes can exceed 128. +`sampleSha256`, complete-prefix/tail lengths describe the last fully checked +retained sample; requested/read-in-operation counts describe the current read. +`settlementBudgetMicroseconds` is the frozen relative budget, or null for direct +mechanical probes. This sidecar is separate mechanical evidence and never +acceptance authority. Failed publication preserves the original exception and +sets its retention flag false; absent/unjoined receipt is an evidence gap. +The existing typed F# failure diagnostic schema, settlement semantics and caps +remain unchanged. Source-only RP1 does not authorize another native attempt; +RP2 contract qualification and RP3 capacity evidence remain required. diff --git a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/buffered_writer.py b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/buffered_writer.py new file mode 100644 index 0000000..1188879 --- /dev/null +++ b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/buffered_writer.py @@ -0,0 +1,51 @@ +"""Public Recoil2639 FileSink-style libc full-buffered ordinary-file writer. +FileSink.cpp:123-130,214-223: fopen(w), setvbuf(_IOFBF,8192), fprintf newline. +No severity-triggered fflush, engine, content, or private inputs. +""" +import base64,ctypes,os,sys +ATLAS=(b'CTextureRenderAtlas::CreateAtlasTexture()[0] atlas=IconsAtlas_0 FBO::ready=1',b'CTextureRenderAtlas::CreateAtlasTexture()[1] atlas=IconsAtlas_0 atlasRendered=0') +ROOTS=(b'[DataDirLocater::Check] Using read-write data directory: /public/write/',b'[DataDirLocater::Check] Using read-only data directory: /public/data/',b'[DataDirLocater::Check] Isolation Mode!',b'[SpringApp::Init] Spring writeable configuration directory: /public/write/') +class BufferedWriter: + def __init__(self,path): + self.libc=ctypes.CDLL(None) + self.libc.fopen.argtypes=(ctypes.c_char_p,ctypes.c_char_p);self.libc.fopen.restype=ctypes.c_void_p + self.libc.setvbuf.argtypes=(ctypes.c_void_p,ctypes.c_void_p,ctypes.c_int,ctypes.c_size_t) + self.libc.fprintf.argtypes=(ctypes.c_void_p,ctypes.c_char_p) + self.libc.fflush.argtypes=(ctypes.c_void_p,);self.libc.fclose.argtypes=(ctypes.c_void_p,) + self.stream=self.libc.fopen(os.fsencode(path),b'w');assert self.stream + os.chmod(path,0o600) + assert self.libc.setvbuf(self.stream,None,0,8192)==0 # Linux _IOFBF + self.path=path;self.records=0 + def record(self,text): + assert b'\x00' not in text and b'\n' not in text + assert self.libc.fprintf(self.stream,b'%s\n',ctypes.c_char_p(text))>0 + self.records+=1 + def partial_eof(self): + previous=os.stat(self.path).st_size + for index in range(512): # <=64KiB public records per command + self.record(ATLAS[self.records%2]);size=os.stat(self.path).st_size + if size>previous: + with open(self.path,'rb') as reader:reader.seek(-1,2);last=reader.read(1) + if last!=b'\n':return size + previous=size + raise RuntimeError('no partial EOF in bounded public replay') + def close(self):self.libc.fclose(self.stream) +def main(): + os.umask(0o077);writer=BufferedWriter(sys.argv[1]) + try: + records=ROOTS if len(sys.argv)==2 else base64.b64decode(sys.argv[2]).splitlines() + for record in records:writer.record(record) + writer.partial_eof() + if len(sys.argv)>2:assert writer.libc.fflush(writer.stream)==0 + print('ready',flush=True) + for command in sys.stdin: + command=command.strip() + if command=='grow':writer.partial_eof() + elif command=='growflush': + writer.partial_eof();assert writer.libc.fflush(writer.stream)==0 + elif command=='flush':assert writer.libc.fflush(writer.stream)==0 + elif command=='close':break + else:raise RuntimeError('closed writer command') + print('done',flush=True) + finally:writer.close() +if __name__=='__main__':main() diff --git a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/growing_log.py b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/growing_log.py index 91defdf..db00900 100644 --- a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/growing_log.py +++ b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/growing_log.py @@ -1,7 +1,7 @@ """Held-FD adapter for one source-bound, growing Recoil infolog.""" import base64,hashlib,json,os,re,selectors,stat,subprocess,time from pathlib import Path -from private_io import Refused,SHA,canonical,components,hash_artifact,need,read_bytes +from private_io import Refused,SHA,atomic_bytes_new,atomic_new,canonical,components,hash_artifact,need,read_bytes from runtime_identity import mark_failure,proc_bytes,start_ticks MAX_LOG=4*1024*1024 MAX_POLICY_INPUT=6*1024*1024 @@ -57,7 +57,28 @@ def _closed_state(value,status,boundary,identity,revision,sample_bytes,sample_sh class GrowingLog: def __init__(self,path,process,fd,opened,writer): self.path=str(path);self.process=dict(process);self.fd=fd;self.device=opened.st_dev;self.inode=opened.st_ino - self.previous=b'';self.revision=0;self.state=None;self.revoked=False;self.writer=writer;self.closure_sha256=None;self.failure_checkpoint='policy-scope-join';self.last_policy_observation=None;self.settlement_transcript=[];self.settlement_effects=[] + self.previous=b'';self.revision=0;self.state=None;self.revoked=False;self.writer=writer;self.closure_sha256=None;self.failure_checkpoint='policy-scope-join';self.last_policy_observation=None;self.settlement_transcript=[];self.settlement_effects=[];self._reset_counters(None) + def _reset_counters(self,boundary): + self.counter_started=time.monotonic();self.counter_cause=None;self.counter_deadline=None + self.counters={'boundary':boundary,'probesBegun':0,'probesCompleted':0,'readOperations':0,'readCalls':0,'readCallsInOperation':0,'requestedReadBytes':0,'bytesReadInOperation':0,'evaluationsBegun':0,'evaluationsCompleted':0,'growthAfterEvaluation':0,'maximumObservedBytes':0,'sampleBytes':0,'completePrefixBytes':0,'tailBytes':0} + def _counter_observation(self,check): + elapsed=max(0,int((time.monotonic()-self.counter_started)*1000000)) + return {'schema':'fsbar.barc-infolog-mechanical-observation/v1',**self.counters,'elapsedMicroseconds':elapsed,'settlementBudgetMicroseconds':None if self.counter_deadline is None else max(0,int((self.counter_deadline-self.counter_started)*1000000)),'terminalCheck':check,'terminalCause':self.counter_cause or ('settlement-deadline' if check=='infolog-record-settlement-deadline' else 'other'),'sampleSha256':hashlib.sha256(self.previous).hexdigest(),'nativeAcceptance':False} + def _retain_counter_observation(self,error,config): + check=getattr(error,'_barc_failure_observation',{}).get('check',self.failure_checkpoint) + observation=self._counter_observation(check) + error._barc_infolog_mechanical_observation=observation + # Separate mechanical evidence: never alters the typed failure projection + # or acceptance. Missing publication is explicitly visible on the error. + try: + need(self.counters['boundary'] in BOUNDARIES,'closed counter boundary') + name='infolog-mechanical-'+self.counters['boundary']+'.json' + root=components(config['roots']['attemptRoot']) + encoded=(json.dumps(observation,separators=(',',':'),allow_nan=False)+'\n').encode() + atomic_bytes_new(str(root/name),encoded,4096) + atomic_new(str(root/(name+'.receipt.json')),{'schema':'fsbar.barc-infolog-mechanical-receipt/v1','file':name,'bytes':len(encoded),'sha256':hashlib.sha256(encoded).hexdigest(),'sourceSetSha256':_source_set(config),'nativeAcceptance':False}) + error._barc_infolog_mechanical_retained=True + except Exception:error._barc_infolog_mechanical_retained=False @classmethod def acquire(cls,path,process): check='infolog-path';fd=None @@ -117,12 +138,15 @@ def _deadline(deadline): raise mark_failure(Refused('growing log record settlement deadline'),'infolog-record-settlement-deadline','deadline',None) def _read_exact(self,length,deadline=None): chunks=[];offset=0;calls=0 + self.counters['readOperations']+=1;self.counters['readCallsInOperation']=0;self.counters['requestedReadBytes']=length;self.counters['bytesReadInOperation']=0 while offset=MAX_PREAD_CALLS: + self.counter_cause='exact-read-call-cap' raise mark_failure(Refused('growing log record exact-read exhausted'),'infolog-record-settlement-exhausted','refused',None) + self.counters['readCalls']+=1;self.counters['readCallsInOperation']+=1 block=os.pread(self.fd,min(65536,length-offset),offset);need(block,'growing log truncated');chunks.append(block);offset+=len(block) - calls+=1 + calls+=1;self.counters['bytesReadInOperation']=offset if deadline is not None:self._deadline(deadline) return b''.join(chunks) def _sample(self,deadline): @@ -147,6 +171,7 @@ def checkpoint(name): need((opened.st_dev,opened.st_ino)==(self.device,self.inode),'growing log descriptor identity changed') checkpoint('file-custody') need(stat.S_ISREG(named.st_mode) and named.st_uid==os.geteuid() and stat.S_IMODE(named.st_mode)==0o600 and named.st_nlink==1,'growing log custody') + self.counters['maximumObservedBytes']=max(self.counters['maximumObservedBytes'],opened.st_size) checkpoint('size-cap');need(opened.st_size<=MAX_LOG,'growing log bound') writer=self._writer(self.process,path,opened,deadline) if expected is not None: @@ -158,7 +183,7 @@ def _sample_impl(self,deadline): self._deadline(deadline) opened,_=self._custody(deadline=deadline) need(len(self.previous)<=opened.st_size,'growing log truncated') - length=opened.st_size;raw=self._read_exact(length,deadline) + length=opened.st_size;self.counters['maximumObservedBytes']=max(self.counters['maximumObservedBytes'],length);raw=self._read_exact(length,deadline) # This second retained-FD read closes the permanent overwrite window # after the first read. The custody check also reopens no authority: # any failure makes this object sticky-revoked in _sample. @@ -171,10 +196,14 @@ def _sample_impl(self,deadline): def _settle(self,deadline,probes): while probes0,'growing log policy deadline') self.failure_checkpoint='policy-transport';self.last_policy_observation=None + self.counters['evaluationsBegun']+=1 output=self._run_policy(policy['path'],closure['path'],closure['sha256'],encoded,policy_deadline) + self.counters['evaluationsCompleted']+=1 try:value=json.loads(output.decode('utf-8'),object_pairs_hook=_unique,parse_constant=lambda _:(_ for _ in ()).throw(Refused('nonfinite policy JSON'))) except (UnicodeError,json.JSONDecodeError) as error:raise Refused('invalid growing log policy result') from error self.failure_checkpoint='policy-result-join' @@ -345,7 +380,9 @@ def _consume_impl(self,boundary,config,deadline): hash_artifact(policy['path'],policy['sha256'],268435456) self._closure(closure['path'],closure['sha256'],policy_deadline) need(time.monotonic() Date: Fri, 2 Oct 2026 16:25:17 +0200 Subject: [PATCH 2/3] Keep retained sample lengths coherent before a new probe --- .../fixtures/complete-record-helper/growing_log.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/growing_log.py b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/growing_log.py index db00900..ac5379c 100644 --- a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/growing_log.py +++ b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/growing_log.py @@ -61,6 +61,8 @@ def __init__(self,path,process,fd,opened,writer): def _reset_counters(self,boundary): self.counter_started=time.monotonic();self.counter_cause=None;self.counter_deadline=None self.counters={'boundary':boundary,'probesBegun':0,'probesCompleted':0,'readOperations':0,'readCalls':0,'readCallsInOperation':0,'requestedReadBytes':0,'bytesReadInOperation':0,'evaluationsBegun':0,'evaluationsCompleted':0,'growthAfterEvaluation':0,'maximumObservedBytes':0,'sampleBytes':0,'completePrefixBytes':0,'tailBytes':0} + prefix=self.previous.rfind(b'\n')+1 + self.counters.update(sampleBytes=len(self.previous),completePrefixBytes=prefix,tailBytes=len(self.previous)-prefix) def _counter_observation(self,check): elapsed=max(0,int((time.monotonic()-self.counter_started)*1000000)) return {'schema':'fsbar.barc-infolog-mechanical-observation/v1',**self.counters,'elapsedMicroseconds':elapsed,'settlementBudgetMicroseconds':None if self.counter_deadline is None else max(0,int((self.counter_deadline-self.counter_started)*1000000)),'terminalCheck':check,'terminalCause':self.counter_cause or ('settlement-deadline' if check=='infolog-record-settlement-deadline' else 'other'),'sampleSha256':hashlib.sha256(self.previous).hexdigest(),'nativeAcceptance':False} From af75a9efb397430411c130c0c5090f472aa6bda9 Mon Sep 17 00:00:00 2001 From: EHotwagner Date: Fri, 2 Oct 2026 16:32:09 +0200 Subject: [PATCH 3/3] Record real policy buffered-writer growth qualification --- docs/roadmaps/barc-01-useful-play.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/roadmaps/barc-01-useful-play.md b/docs/roadmaps/barc-01-useful-play.md index 5f188d8..9057632 100644 --- a/docs/roadmaps/barc-01-useful-play.md +++ b/docs/roadmaps/barc-01-useful-play.md @@ -175,7 +175,11 @@ local/generated input journeys or publish/install the product. consumption retains bounded counters with a digest receipt; destination collision preserves original refusal and existing bytes. The two exhaustion controls retain the same policy failure code while distinguishing their - mechanical cause. Real compiled-policy growth verification remains pending. + mechanical cause. Two focused real compiled-policy checks pass against the + protected `4955ae7` artifact (4.572 seconds): both the existing writer and + the libc buffered writer reach exactly three completed evaluations and three + post-evaluation growth observations, then refuse at the unchanged cap. The + buffered control also retains the separate mechanical observation/receipt. The [fixture contract](../../tests/Broker.NativeProof/RuntimeEvidence/fixtures/complete-record-helper/README.md) describes the separate observation/receipt retained by the actual adapter in the attempt root. Typed F# authority, settlement behavior and runtime caps are