Compare commits

...
Author SHA1 Message Date
nala 45fd591c7f docs(irpc): record 5aaf1a56 delivery and separate remaining code from documentary questions 2026-10-26 11:07:26 +02:00
nala 5aaf1a56f9 feat(irpc): prepare exact values and documented M20 M22 field mappings
tests / ci (push) Canceled after 0s
2026-10-26 10:51:05 +02:00
nala 2116f66b2b docs(irpc): record 56475acb installation and remaining L6 scope 2026-10-26 10:33:32 +02:00
nala 56475acb2f feat(irpc): map short periods and foreign currency plans with explicit simulation evidence
tests / ci (push) Canceled after 0s
2026-10-26 09:55:25 +02:00
nala 0effdc9fcb docs(irpc): record e9fe1022 installation and partial L6 scope 2026-10-26 09:44:28 +02:00
nala e9fe102259 feat(irpc): demonstrate documented depreciation methods and prior quotas
tests / ci (push) Canceled after 0s
2026-10-26 09:24:06 +02:00
nala 44d0858cee docs(irpc): record 043dd35d installation and remaining L6 cases 2026-10-26 08:43:14 +02:00
nala 043dd35d8e feat(irpc): prepare scoped cost limits provisions and timing in QA
tests / ci (push) Canceled after 0s
2026-10-26 08:29:28 +02:00
nala f400e56a5b docs(irpc): record a2de7259 delivery and bounded L6 remainder 2026-10-25 22:39:35 +02:00
nala a2de725901 feat(irpc): prepare compatible L6 schedules and scoped form mappings in QA
tests / ci (push) Canceled after 0s
2026-10-25 22:29:06 +02:00
nala 82d0d05887 Record installed normal colecta and concrete L6 remainder separate from L7 L8 2026-10-25 22:11:55 +02:00
nala 2f684e5984 Calculate scoped normal IRPC colecta and preserve annual settlement boundary
tests / ci (push) Canceled after 0s
2026-10-25 21:58:59 +02:00
nala b8d45796dd Determine scoped IRPC taxable base from documented own loss balances 2026-10-25 21:46:59 +02:00
nala 5e02c23af8 Complete scoped IRPC taxable profit with explicit evidence states
tests / ci (push) Canceled after 0s
2026-10-25 21:33:51 +02:00
nala 664c88c8f7 Start scoped normal IRPC adjustments and record operational L5 installation 2026-10-25 21:22:42 +02:00
nala 7a11c4ef8f Specify AT interest and CER questions and label simulation assumptions
tests / ci (push) Canceled after 0s
2026-10-25 21:04:53 +02:00
nala acf8ec3cb5 Prepare documented interest calculations and separate MRFTA working cases 2026-10-25 20:52:21 +02:00
nala 5fa64bc0f4 Preserve exact original BM source bytes in the QA archive
tests / ci (push) Canceled after 0s
2026-10-25 20:19:53 +02:00
nala 85e3cd5c7b Prepare scoped MRFTA and documented compensatory interest with QA recovery 2026-10-25 20:19:08 +02:00
nala ce746d889d Implement scoped IRPC reliefs and PT-MZ royalties with QA recovery evidence
tests / ci (push) Canceled after 0s
2026-10-25 19:56:32 +02:00
nala 2b33a1c343 Identify IRPC income category and retention nature in Portuguese
tests / ci (push) Canceled after 0s
2026-10-25 19:20:44 +02:00
nala 4d6f828230 Group compatible IRPC withholding rates and reuse delivered FX selection 2026-10-25 19:14:46 +02:00
nala da0d8abb47 Start scoped IRPC L5 withholding workflow with document and payment reuse 2026-10-25 18:45:04 +02:00
nala 5c0cb25cea Preserve documented liberatory settlement when changing ISPC route
tests / ci (push) Canceled after 0s
2026-10-25 18:18:03 +02:00
nala 3dda7130ee Group ISPC occasional operations, excess acquisition treatment and 2026 formal preparation in QA 2026-10-25 18:12:34 +02:00
nala 6af7092e83 Reconcile installed L3 receipt and preserve current balance in compatible ISPC QA
tests / ci (push) Canceled after 0s
2026-10-25 17:15:52 +02:00
nala 49b448eb47 Prepare compatible ISPC quarterly QA on L3 baseline without experimental P001 changes 2026-10-25 17:11:58 +02:00
nala fa32a2b9e1 Align legacy message assertion with agreed P001 residual without fiscal changes
tests / ci (push) Canceled after 0s
2026-10-25 17:09:26 +02:00
nala 0f4df8a4d1 Prepare compatible L3 additional delivery with preserved residuals and accepted proofs
tests / ci (push) Canceled after 0s
2026-10-25 16:38:24 +02:00
nala b189d0fa43 Prepare exact beverage partitions, fiscal gap diagnostics and L3 form review in QA 2026-10-25 15:55:25 +02:00
nala dbeaf886ee Record installed L3 E delta and keep L3 and L1 L2 residuals open 2026-10-25 15:29:38 +02:00
nala 7ad187f9f0 Prepare demonstrated L3 E delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-25 15:25:44 +02:00
nala 4708662532 feat(iva): prepare beverage restitution QA and retain residual scope 2026-10-25 15:08:10 +02:00
nala 46944402da Record installed grouped L3 C D delta and preserved residuals 2026-10-25 14:53:45 +02:00
nala de36f02880 Prepare grouped L3 C D delivery after verified backup restore
tests / ci (push) Canceled after 0s
2026-10-25 14:50:04 +02:00
nala 9e2d90c880 Prepare L3 D refund lifecycle and grouped C D QA delivery with preserved credits 2026-10-25 14:47:03 +02:00
nala b7a745e64f Prepare L3 C substitutions with frozen predecessor and payment reconciliation in QA 2026-10-25 14:23:56 +02:00
nala 3aa851a467 Record installed L3 A/B delta and preserved residuals 2026-10-25 14:13:30 +02:00
nala 109cb0fe9e Prepare grouped L3 A/B delivery after verified backup restore
tests / ci (push) Canceled after 0s
2026-10-25 14:10:24 +02:00
nala f7b778cdce Implement scoped L3 A B credit carry and VAT closure with frozen L2 sources 2026-10-25 14:01:33 +02:00
nala 508aeb5205 Delimit L3 VAT closure increments using existing L1 L2 and cashflow mechanisms 2026-10-25 13:40:20 +02:00
nala acbd1f3315 Record installed L2 demonstrated scope and retain residual regularization work 2026-10-25 13:35:03 +02:00
nala 7a380b7690 Prepare grouped L2 D E delivery after authenticated backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-25 13:31:55 +02:00
nala dde20c3348 Implement scoped L2 E annual adjustments and asset control with grouped D E manifest 2026-10-25 13:22:17 +02:00
nala 2c2a2f2010 Implement L2 D allocation and provisional proportions with exact totals and frozen history 2026-10-25 13:00:59 +02:00
nala 855ab066c4 Record installed grouped L2 ABC and preserved L1 closure balance 2026-10-25 12:44:51 +02:00
nala 819ae791e9 Prepare grouped L2 ABC delivery after authenticated backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-25 12:41:42 +02:00
nala fc7e590d4e Prepare grouped L2 A B C with customs deduction exclusions and exact affected totals 2026-10-25 12:29:10 +02:00
nala 56c948ec45 Implement L2-A acquisition deduction rights with preserved history and affected totals 2026-10-25 12:12:29 +02:00
nala 940d69b82a Record limited L1 operational closure and executable L2 scope 2026-10-25 11:59:50 +02:00
nala 7febb6f7be Record installed P047 and explicitly partial P058 baggage delivery 2026-10-25 11:53:35 +02:00
nala ada9629bb6 Prepare grouped P047 delivery with explicitly partial P058 baggage
tests / ci (push) Canceled after 0s
2026-10-25 11:50:02 +02:00
nala 6e1dc4104c Implement P047 four remission families with scoped customs evidence and QA 2026-10-25 11:43:00 +02:00
nala 4f28fac5d0 Clarify L1 residual closure criteria and add partial returnee baggage QA 2026-10-25 11:24:02 +02:00
nala 9019f766f2 Record installed P104 and explicitly partial offer returnee scopes 2026-10-25 11:08:21 +02:00
nala e38aa74920 Authorize grouped installer after authenticated backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-25 11:04:59 +02:00
nala fab72d2e0c Prepare joint P104 delivery with explicit partial branch coverage 2026-10-25 11:02:30 +02:00
nala 7b6a95a718 Record P104 operational QA and partial offers returnee coverage 2026-10-25 10:57:42 +02:00
nala 9536eb710b Implement Tempo FX selection and offer request decision workflow in QA 2026-10-25 10:54:51 +02:00
nala 8b3ec2b04d docs(iva): receipt joint P046 P059 delivery with scoped RSA benefits 2026-10-25 10:26:31 +02:00
nala a665ee9c97 deploy(iva): deliver P046 P059 jointly with scoped miner benefits
tests / ci (push) Canceled after 0s
2026-10-25 10:22:39 +02:00
nala 2b130a66ec docs(iva): identify miner sources and record compatible P046 P059 QA 2026-10-25 10:16:33 +02:00
nala 4e550c3892 feat(iva): prepare documented P059 miner import paths in QA 2026-10-25 10:13:51 +02:00
nala 34bbcfa7e4 docs(iva): record P046 QA and concrete remaining source actions 2026-10-25 09:51:14 +02:00
nala 0807201517 feat(iva): prepare P046 objective import correspondence in QA 2026-10-25 09:48:47 +02:00
nala f059622562 docs(iva): receipt joint P129 P133 delivery with fiscal continuity 2026-10-25 09:34:10 +02:00
nala a48e974979 docs(iva): prepare joint travel event delivery preserving fiscal continuity
tests / ci (push) Canceled after 0s
2026-10-25 01:48:26 +02:00
nala 1a5f72209e docs(iva): record joint travel and special event QA with limitations 2026-10-25 01:45:12 +02:00
nala c309215d0f fix(iva): report only applicable special event facts preserving drafts 2026-10-25 01:43:06 +02:00
nala 7986d02405 feat(iva): add travel period margin and special travel suspensive events 2026-10-25 01:42:05 +02:00
nala 91c4063338 docs(iva): receipt joint P002 P121 P130 limited-scope delivery 2026-10-25 01:30:16 +02:00
nala df43aeb1e5 docs(iva): prepare joint foreign and limited digital delivery after restore
tests / ci (push) Canceled after 0s
2026-10-25 01:27:21 +02:00
nala de4b25bbd7 docs(iva): record digital QA and prepare grouped P002 delivery 2026-10-25 01:24:34 +02:00
nala 5f088e3411 feat(iva): classify digital goods and services with separate obligations 2026-10-25 01:23:14 +02:00
nala e4c490b323 docs: record P002 QA and delimit P104 currency finding 2026-10-25 01:15:52 +02:00
nala 86970cd507 Implement P002 reusing territoriality and events and clarify P104 legal cotejo 2026-10-25 01:13:46 +02:00
nala 2de67bebf9 docs(iva): receipt P131 P132 delivery keeping P104 conditional and pending 2026-10-25 01:07:32 +02:00
nala e8b5ae43ad docs(iva): prepare P131 P132 delivery with conditional P104 after isolated restore
tests / ci (push) Canceled after 0s
2026-10-25 01:04:54 +02:00
nala 0052cd42d2 docs(iva): record P131 P132 QA and delimit partial P104 currency coverage 2026-10-25 01:02:16 +02:00
nala 7e6e462e12 Implement P131 P132 event timing and conditional P104 draft in QA 2026-10-25 01:01:15 +02:00
nala 7a3ac43224 docs(iva): receipt P087 P127 delivery and remaining dependency groups 2026-10-25 00:52:54 +02:00
nala 92eaa93570 docs(iva): prepare joint P087 P127 delivery after isolated restore
tests / ci (push) Canceled after 0s
2026-10-25 00:50:30 +02:00
nala d84883b801 docs(iva): record P087 P127 QA and concrete actions for 16 pending IDs 2026-10-25 00:48:08 +02:00
nala 5999e35fcb Implement P087 binding lease and P127 business transfers in QA 2026-10-25 00:46:56 +02:00
nala 4cacef23dd docs(iva): receipt P123 P126 delivery with consignment and contrary proof explicit 2026-10-25 00:43:07 +02:00
nala ce9d649fbf docs(iva): prepare joint P123 P126 delivery after backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-25 00:40:41 +02:00
nala a5b1ae6657 docs(iva): record P123 P126 grouped QA and correct consignment designation 2026-10-25 00:37:34 +02:00
nala f640e19370 Implement P123 consignment and P126 rebuttable goods presumptions in QA 2026-10-25 00:36:56 +02:00
nala 4ef7be3d6f docs(iva): receipt grouped P092 P093 P125 delivery preserving margin eligibility 2026-10-25 00:33:14 +02:00
nala 019bcbad6c docs(iva): prepare joint P092 P093 P125 delivery after isolated restore
tests / ci (push) Canceled after 0s
2026-10-25 00:30:43 +02:00
nala 0ebb20c86a docs(iva): record grouped QA P092 P093 P125 and preserve 111 deliveries 2026-10-25 00:28:41 +02:00
nala b0818c0163 Implement P092 P093 P125 individual secondhand bases in QA 2026-10-25 00:27:37 +02:00
nala ec786f4ae2 docs(iva): receipt P088-P124 delivery with deduction history preserved 2026-10-25 00:19:44 +02:00
nala 6c12aabb3a docs(iva): prepare joint P088-P124 delivery after backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-25 00:17:11 +02:00
nala cd259623ae docs(iva): record P088-P124 QA with historical deduction separate from new deduction 2026-10-25 00:15:24 +02:00
nala 9b95e5e7a8 feat(iva): prepare goods allocation classification and current acquisition-cost bases in QA 2026-10-25 00:15:19 +02:00
nala 1b67fa85ff docs(iva): receipt joint P122-P128 delivery preserving P091 and prior closures 2026-10-25 00:10:37 +02:00
nala 63cc336787 docs(iva): prepare joint P122-P128 delivery after backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-25 00:08:02 +02:00
nala af7d250320 docs(iva): record P122-P128 QA preserving 107 delivered branches 2026-10-25 00:06:28 +02:00
nala 2b592ded66 feat(iva): prepare own-name goods and service chains together in QA 2026-10-25 00:06:24 +02:00
nala 5837f34a2c docs(iva): receipt joint P096-P099 delivery with deduction outside scope 2026-10-25 00:02:07 +02:00
nala 2fdca86367 docs(iva): prepare joint P096-P099 delivery after backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 23:59:51 +02:00
nala 833b4e5cef docs(iva): record four proportional bases in QA preserving 103 deliveries 2026-10-24 23:58:10 +02:00
nala 67a96085c8 feat(iva): prepare four proportional tax bases in one QA set 2026-10-24 23:58:06 +02:00
nala b0e01ef737 docs(iva): receipt joint G9A-G9J delivery preserving 93 closures 2026-10-24 23:53:30 +02:00
nala 2a7254406d docs(iva): prepare one G9A-G9J delivery after backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 23:49:58 +02:00
nala 4601bf64a0 docs(iva): record P111-P120 QA with separate territoriality and obligations 2026-10-24 23:48:12 +02:00
nala 6cffa1188f feat(iva): prepare P111-P120 listed services as one compatible QA set 2026-10-24 23:48:08 +02:00
nala 4853bc7284 docs(iva): receipt one joint G8B-G8F delivery preserving 88 closures 2026-10-24 23:43:03 +02:00
nala 03c26d6613 docs(iva): prepare one G8B-G8F delivery after backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 23:40:32 +02:00
nala 3f4e71c3f3 docs(iva): record five G8 branches in QA for one compatible delivery 2026-10-24 23:38:44 +02:00
nala ec33fb5be2 feat(iva): prepare five G8 service territoriality branches together in QA 2026-10-24 23:38:14 +02:00
nala aac3f46306 docs(iva): receipt G8A installation and adopt grouped future deliveries 2026-10-24 23:33:35 +02:00
nala 8f14f5dde2 docs(iva): prepare G8A delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 23:31:08 +02:00
nala fb7248661d docs(iva): record G8A P105 QA and preserve 87 delivered branches 2026-10-24 23:29:12 +02:00
nala 0682ef74e2 feat(iva): classify goods territoriality for L1 P105 in QA 2026-10-24 23:29:03 +02:00
nala 21ce03f65c docs(iva): record installed G7I P089 and distinct prior deduction scope 2026-10-24 23:23:49 +02:00
nala 6f1cf7b7a0 docs(iva): prepare G7I delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 23:21:33 +02:00
nala a4329bb4bf docs(iva): record G7I P089 QA and preserve 86 deliveries 2026-10-24 23:19:43 +02:00
nala 90b31c677f feat(iva): prepare P089 service normal values with distinct own conditions in QA 2026-10-24 23:19:00 +02:00
nala 33cc971a12 docs(iva): record installed G7H P103 and referenced correction scope 2026-10-24 23:15:02 +02:00
nala cd530b248b docs(iva): prepare G7H delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 23:12:48 +02:00
nala 2087134143 docs(iva): record G7H P103 QA and preserve 85 deliveries 2026-10-24 23:10:58 +02:00
nala 67b8b58149 feat(iva): prepare P103 price comparison and referenced correction in QA 2026-10-24 23:10:11 +02:00
nala adb849d4fc docs(iva): record installed G7G P102 and four exclusion scopes 2026-10-24 23:06:42 +02:00
nala 5d5f3b4148 docs(iva): prepare G7G delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 23:04:14 +02:00
nala 9c2b2c6560 docs(iva): record G7G P102 QA and preserve 84 deliveries 2026-10-24 23:00:49 +02:00
nala acc633bf08 feat(iva): prepare four P102 exclusions with own conditions in QA 2026-10-24 22:59:39 +02:00
nala a89f9eca8c docs(iva): record installed G7F P101 and single operation base 2026-10-24 22:55:06 +02:00
nala 7e5710ebbd docs(iva): prepare G7F delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 22:52:59 +02:00
nala 6f90fcb9d4 docs(iva): record G7F P101 QA and preserve 83 deliveries 2026-10-24 22:50:04 +02:00
nala e3caf55361 feat(iva): prepare P101 consideration composition without doublecounting in QA 2026-10-24 22:49:56 +02:00
nala 0bef805ede docs(iva): record installed G7E P100 and preserved valuation scope 2026-10-24 22:45:45 +02:00
nala 70b4a640ee docs(iva): prepare G7E delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 22:43:24 +02:00
nala 0460c85330 docs(iva): record G7E P100 QA and preserve 82 deliveries 2026-10-24 22:41:41 +02:00
nala 9f053ac9d3 feat(iva): prepare P100 noncash consideration bases in QA 2026-10-24 22:41:33 +02:00
nala 6234d34392 docs(iva): record installed G7D P095 and TC excluded once 2026-10-24 22:38:04 +02:00
nala 92a7418cb6 docs(iva): prepare G7D delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 22:35:57 +02:00
nala 76be72c38c docs(iva): record G7D P095 QA and preserve 81 deliveries 2026-10-24 22:34:04 +02:00
nala 3bcd98e78e feat(iva): prepare P095 regulated fuel base excluding TC in QA 2026-10-24 22:33:57 +02:00
nala 9600880169 docs(iva): record installed G7C P094 and preserved valuation scope 2026-10-24 22:29:08 +02:00
nala df7cb7fa47 docs(iva): prepare G7C delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 22:26:45 +02:00
nala 287f2f8321 docs(iva): record G7C P094 QA and preserve 80 deliveries 2026-10-24 22:23:42 +02:00
nala 4672789f2b feat(iva): prepare P094 act transfer valuation bases in QA 2026-10-24 22:23:10 +02:00
nala 15894f4b04 docs(iva): record installed G7B P091 and preserved commission directions 2026-10-24 22:15:55 +02:00
nala e62b7dfdc2 docs(iva): prepare G7B delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 22:13:42 +02:00
nala 9bd2e062f4 docs(iva): record G7B P091 QA and preserve 79 delivered branches 2026-10-24 22:04:25 +02:00
nala 948621a65c feat(iva): determine goods commission sale and purchase tax bases 2026-10-24 22:03:44 +02:00
nala 50463ca716 docs(iva): record installed G7A P090 with base VAT separation 2026-10-24 21:52:31 +02:00
nala 4193056bdd docs(iva): prepare G7A delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 21:50:21 +02:00
nala 20bfeb4f71 docs(iva): record G7A P090 QA and preserve 78 delivered branches 2026-10-24 21:47:38 +02:00
nala 1dda6ea258 feat(iva): determine public authority compensation tax bases 2026-10-24 21:46:47 +02:00
nala 0a80f1c457 docs(iva): record installed G6H P060 and preserved decision scope 2026-10-24 21:39:03 +02:00
nala eb9294ef42 docs(iva): prepare G6H delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 21:36:55 +02:00
nala 2359a88dba docs(iva): record G6H P060 QA and preserve 77 delivered branches 2026-10-24 21:29:32 +02:00
nala 69b6c49a60 feat(iva): classify UN development imports with proportional relief 2026-10-24 21:29:22 +02:00
nala 163e090ea5 docs(iva): record installed G6G P056 delivery and preserved authorization scope 2026-10-24 21:13:56 +02:00
nala 9b26217dec docs(iva): prepare G6G delivery after verified backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 21:11:50 +02:00
nala ebf5e53c3c docs(iva): record G6G P056 QA and preserve 76 delivered branches 2026-10-24 20:53:12 +02:00
nala 9783c54b2c feat(iva): classify authorized class K investment equipment imports 2026-10-24 20:52:32 +02:00
nala 0f9f7e3409 docs(iva): record installed G6F and partial P084 P085 delivery 2026-10-24 20:47:58 +02:00
nala 78c9f4a356 docs(iva): prepare G6F delivery after verified backup and restore
tests / ci (push) Canceled after 0s
2026-10-24 20:45:46 +02:00
nala 7996c35933 docs(iva): record G6F P050 QA and authorized partial offer coverage 2026-10-24 20:41:20 +02:00
nala 29e708ba2d fix(iva): exclude import-linked services from goods gift references 2026-10-24 20:39:54 +02:00
nala f9fb04f947 feat(iva): classify P050 services included in import taxable base 2026-10-24 20:39:23 +02:00
nala 77d1290258 docs(iva): record distinct offer paths and scoped conditional scenarios QA 2026-10-24 20:33:20 +02:00
nala 946fc08906 fix(iva): preserve exact and literal scope of offer decisions 2026-10-24 20:31:58 +02:00
nala 7ecf9ec79a feat(iva): distinguish offer requests emergency drafts and conditional scenarios 2026-10-24 20:30:54 +02:00
nala 536559d651 docs(iva): receipt for installed G6E P052 and partial draft preparation 2026-10-24 20:26:59 +02:00
nala c1314cdf90 docs(iva): prepare G6E delivery after fresh backup and isolated restore
tests / ci (push) Waiting to run
2026-10-24 20:23:46 +02:00
nala ff8848d32d docs(iva): record G6E QA and Model I1 enabling-diploma scope 2026-10-24 20:19:29 +02:00
nala 1565aa4ffb feat(iva): classify P052 onboard supply imports with statutory exclusions 2026-10-24 20:18:20 +02:00
nala 4e4bf6b859 docs(iva): record P084 P085 draft-only QA and joint source research 2026-10-24 20:11:22 +02:00
nala 5ec2f198a3 feat(iva): prepare distinct P084 P085 offer drafts without applying benefits 2026-10-24 20:10:28 +02:00
nala e32690799f docs(iva): receipt for installed joint P048 P080 delivery 2026-10-24 20:07:57 +02:00
nala 2d889a211b docs(iva): prepare joint P048 P080 Git delivery after verified restore
tests / ci (push) Canceled after 0s
2026-10-24 20:04:30 +02:00
nala 50fdd97916 docs(iva): record P080 QA and individual P084 P085 remaining work 2026-10-24 20:01:41 +02:00
nala 9842dcbb0e feat(iva): classify P080 special-regime imports and delimit P084/P085 2026-10-24 20:00:48 +02:00
nala e384418ecc docs(iva): record G6D P048 three treatments QA and preserved 72 closures 2026-10-24 19:55:26 +02:00
nala 0eb37ef59b feat(iva): classify P048 import customs regimes with full duty exemption 2026-10-24 19:54:06 +02:00
nala 2ed62165b7 docs(delivery): record G6C installed delta and reconciled 72 plus 60 balance 2026-10-24 19:48:13 +02:00
nala d46b794ab2 docs(delivery): prepare G6C with fresh backup and verified isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 19:45:57 +02:00
nala d65d3f5c4e docs(iva): record G6C P053 P054 four treatments QA and preserved 70 closures 2026-10-24 19:43:54 +02:00
nala 8e5565d5e0 feat(iva): classify eligible vessel and aircraft imports in scoped G6C 2026-10-24 19:42:37 +02:00
nala 72e56f7ae5 docs(delivery): record G6B installed delta and reconciled 70 plus 62 balance 2026-10-24 19:37:22 +02:00
nala 4cebd61765 docs(delivery): prepare G6B with fresh backup and verified isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 19:35:02 +02:00
nala 1efb32c244 docs(iva): record G6B P055 P057 QA and preserved 68 delivered branches 2026-10-24 19:32:07 +02:00
nala f75f36f0e3 feat(iva): classify artwork and fire brigade imports in scoped G6B 2026-10-24 19:29:00 +02:00
nala a23f1dcb6e docs(delivery): record G6A installed delta and reconciled 68 plus 64 balance 2026-10-24 19:24:39 +02:00
nala e3601c124d docs(delivery): prepare G6A with fresh backup and verified isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 19:22:06 +02:00
nala 615f78e79f docs(iva): record G6A P049 P051 QA and preserved 66 delivered branches 2026-10-24 19:20:09 +02:00
nala 965da26426 feat(iva): classify reimports and central bank gold imports in scoped G6A 2026-10-24 19:18:46 +02:00
nala e99ea1d013 docs(delivery): record G5B eliminated provision routing and installed delta 2026-10-24 19:10:47 +02:00
nala 6f056359df docs(delivery): prepare G5B with fresh backup and verified isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 19:08:39 +02:00
nala 0cd7e9fb62 docs(iva): record P086 rectification and demonstrated G5B acquisition continuity QA 2026-10-24 19:05:10 +02:00
nala 689a4c93c3 feat(iva): explain eliminated P086 exemption and preserve acquisition continuity 2026-10-24 19:03:00 +02:00
nala d3e9f3732c docs(delivery): record G5A installed delta and reconciled 65 plus 67 balance 2026-10-24 18:49:57 +02:00
nala 69f2e365bf chore(delivery): prepare G5A with fresh authenticated backup and restore
tests / ci (push) Waiting to run
2026-10-24 18:47:03 +02:00
nala 4e97cd05ea docs(iva): map accepted G4E treatments and record demonstrated G5A QA 2026-10-24 18:37:36 +02:00
nala 1f7fc13872 feat(iva): add G5A goods and connected services under special regimes 2026-10-24 18:36:01 +02:00
nala 0eb2c485cc docs(delivery): record G4E installed delta and reconciled 62 plus 70 balance 2026-10-24 18:28:22 +02:00
nala 2e21ca4500 chore(delivery): prepare G4E after fresh authenticated backup and restore
tests / ci (push) Canceled after 0s
2026-10-24 18:26:03 +02:00
nala fae8162c58 docs(iva): close G4E QA from Tempo manual visual confirmation 2026-10-24 18:23:30 +02:00
nala d03101bb69 docs(iva): record G4E QA evidence and pending directed visual check 2026-10-24 18:22:16 +02:00
nala 38faeac685 feat(iva): add G4E export buyer and beneficiary conditions in QA 2026-10-24 18:20:04 +02:00
nala 3be371c823 docs(delivery): record G4D installed delta and beverage follow-up in L2 L3 2026-10-24 18:09:53 +02:00
nala 686328a085 chore(delivery): prepare G4D with verified destination backup and restore
tests / ci (push) Canceled after 0s
2026-10-24 18:07:35 +02:00
nala 40a4ddcbde docs(iva): close G4D QA with Tempo directed visual confirmation 2026-10-24 18:06:14 +02:00
nala e50733ba1d docs(iva): record G4D coverage exclusions and pending visual proof 2026-10-24 18:05:20 +02:00
nala 8df721ac51 feat(iva): classify G4D onboard supplies with explicit beverage exceptions 2026-10-24 18:04:31 +02:00
nala 25cae1d98b docs(delivery): record G4C installed delta and preserved baseline 2026-10-24 17:59:25 +02:00
nala 679203d4b1 chore(delivery): prepare G4C after authenticated backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 17:56:23 +02:00
nala 2fccbc8ee8 docs(iva): close G4C QA with Tempo manual visual confirmation 2026-10-24 17:55:23 +02:00
nala 19b31d51c5 docs(iva): record G4C code/API coverage and pending directed visual proof 2026-10-24 17:54:36 +02:00
nala b1c8e0e343 feat(iva): add G4C linked export services with explicit operation reference 2026-10-24 17:53:35 +02:00
nala 117f2a70a8 docs(iva): record G4B homologation delivery and preserved balance 2026-10-24 17:42:50 +02:00
nala a153d0782f docs(iva): prepare G4B delivery with fresh authenticated backup and restore
tests / ci (push) Canceled after 0s
2026-10-24 17:40:34 +02:00
nala 0b0e002d15 docs(iva): record Tempo G4B visual completion and current saved result 2026-10-24 17:31:20 +02:00
nala b641887274 docs(iva): record G4B code QA and explicit browser access gate 2026-10-24 17:29:11 +02:00
nala f946364baa feat(iva): implement G4B eligible vessel aircraft and direct services 2026-10-24 17:27:32 +02:00
nala 3846be8fc6 docs(iva): record G4A homologation delivery and preserved balance 2026-10-24 17:21:31 +02:00
nala b898955603 docs(iva): prepare G4A delivery with fresh backup and restore
tests / ci (push) Canceled after 0s
2026-10-24 17:19:15 +02:00
nala 7b54efb0fc docs(iva): record Tempo G4A visual completion and preserved historical result 2026-10-24 17:16:23 +02:00
nala 7a58fa2435 docs(iva): record G4A code QA coverage and explicit visual remainder 2026-10-24 17:08:36 +02:00
nala 0f0d2e566f feat(iva): implement G4A direct international operations with scoped evidence 2026-10-24 17:07:26 +02:00
nala 82e010c44f docs(iva): record G3 homologation delivery and preserved balance 2026-10-24 17:03:13 +02:00
nala 6eefe4b332 docs(iva): prepare G3 delivery with fresh backup restore and compatible rollback
tests / ci (push) Canceled after 0s
2026-10-24 17:01:08 +02:00
nala 0dc2d64b20 docs(iva): record Tempo visual completion of G3 QA 2026-10-24 16:58:34 +02:00
nala bda6d1e3a0 docs(iva): record G3 cessation code QA and explicit visual verification remainder 2026-10-24 16:54:23 +02:00
nala ac948bd8b7 feat(iva): implement G3 temporary benefit cessation and explicit treatment continuity 2026-10-24 16:51:52 +02:00
nala 908c8afc54 docs(iva): make G2L manual visual evidence and technical corroboration explicit 2026-10-24 16:44:26 +02:00
nala 643ba6ed72 docs(iva): record G2K G2L homologation delivery and preserved balance 2026-10-24 16:41:57 +02:00
nala ccdecbd8d7 docs(iva): verify G2K G2L joint delivery backup and restore
tests / ci (push) Canceled after 0s
2026-10-24 16:39:06 +02:00
nala da798dd1d8 docs(iva): complete G2L QA with Tempo review and actual saved payload evidence 2026-10-24 16:36:58 +02:00
nala 0304612093 docs(iva): record partial Tempo review and clarify QA save recovery controls 2026-10-24 16:33:05 +02:00
nala d76078a81f docs(iva): accept Tempo manual verification route without claiming G2L closure 2026-10-24 16:24:02 +02:00
nala c4cc7d83e7 docs(iva): record G2L code QA and explicit pending visual access gate 2026-10-24 16:20:31 +02:00
nala 744682835a feat(iva): implement G2L Annex I and explicit continuity pending visual QA 2026-10-24 16:19:52 +02:00
nala 1fe742561f docs(iva): record G2K P008 QA candidate and preserved balance 2026-10-24 16:06:48 +02:00
nala 8882dc54d0 feat(iva): implement G2K pharmaceutical manufacturing inputs in QA 2026-10-24 16:05:55 +02:00
nala eb9e0dbc60 docs(iva): record G2I G2J homologation delivery and calendar resolution 2026-10-24 15:52:45 +02:00
nala e45a1394fa docs(iva): verify G2I G2J joint delivery backup and calendar evidence
tests / ci (push) Canceled after 0s
2026-10-24 15:49:08 +02:00
nala 72f4187d3b feat(iva): add fundraising group and correct production option calendar in QA 2026-10-24 15:47:02 +02:00
nala a5ac8ca1c9 docs(iva): record G2I QA candidate and explicit calendar limit 2026-10-24 15:31:29 +02:00
nala fe69a16eea feat(iva): add own-production exemptions and dated tax options in QA 2026-10-24 15:31:27 +02:00
nala 7696af6814 docs(iva): record G2G G2H homologation delivery and preserved balance 2026-10-24 15:15:49 +02:00
nala d4eae917ee docs(iva): verify G2G G2H joint delivery backup and compatibility
tests / ci (push) Canceled after 0s
2026-10-24 15:13:32 +02:00
nala b297058d11 docs(iva): record G2H QA candidate and one-branch coverage 2026-10-24 15:12:30 +02:00
nala 48146089cd feat(iva): add eighteen enumerated products within P026 in QA 2026-10-24 15:12:14 +02:00
nala 2440cb448a docs(iva): record G2G QA candidate and four-branch balance 2026-10-24 15:06:45 +02:00
nala 9dbfdd67ad feat(iva): add conditional public official and asset-sale operations in QA 2026-10-24 15:06:43 +02:00
nala b1928b61e5 docs(iva): clarify delivered G2F IDs and evidence paths 2026-10-24 15:03:42 +02:00
nala 541ea70484 docs(iva): record G2E G2F homologation delivery and preservation 2026-10-24 15:01:45 +02:00
nala 9a56d98242 docs(iva): verify G2E G2F destination backup and isolated restore
tests / ci (push) Canceled after 0s
2026-10-24 14:59:24 +02:00
nala 38b49bd5fa docs(iva): prepare G2E G2F joint delivery and authenticated preflight 2026-10-24 14:57:53 +02:00
nala 9b0f437073 docs(iva): record G2F candidate and seven QA branches 2026-10-24 14:57:23 +02:00
nala 8171c7992e feat(iva): add games stamped values and passenger transport in QA 2026-10-24 14:57:22 +02:00
nala 30760cab9b docs(iva): record G2E QA candidate and preserved balance 2026-10-24 14:53:24 +02:00
nala 33d18b9efc feat(iva): add conditional agropecuary operations in QA 2026-10-24 14:53:23 +02:00
nala 0aac0d1555 docs(iva): record G2C G2D homologation delivery and preservation 2026-10-24 14:49:27 +02:00
nala 3b788ec009 docs(iva): record G2C G2D backup and activation scope
tests / ci (push) Canceled after 0s
2026-10-24 14:46:36 +02:00
nala db4ff64e87 docs(iva): prepare verified G2C G2D joint Git delivery 2026-10-24 14:46:24 +02:00
nala c28e290b42 docs(iva): record G2D candidate and joint QA balance 2026-10-24 14:42:43 +02:00
nala 8d127799cd feat(iva): add author rights and eligible publications in QA 2026-10-24 14:42:38 +02:00
nala d32ad1e0a6 docs(iva): record G2C QA candidate and preserved delivery balance 2026-10-24 14:39:04 +02:00
nala 122f4f04b9 feat(iva): add conditional cultural and membership operations in QA 2026-10-24 14:38:55 +02:00
nala dacda11c07 Record joint L1 homologation delivery 490527b9 and verified preservation 2026-10-24 14:32:35 +02:00
nala 490527b92c Record joint L1 QA candidate, verified Git bundle and integration preview
tests / ci (push) Canceled after 0s
2026-10-24 14:22:15 +02:00
nala 4a35d63cd3 Complete G2B social QA and prepare joint L1 delivery with compatible rollback 2026-10-24 14:21:21 +02:00
nala 0e644b5524 Record G2A QA candidate and reconciled L1 closure counts 2026-10-24 14:04:45 +02:00
nala 675cf38f67 Implement G2A health exemptions in QA and reconcile L1 branch inventory 2026-10-24 14:04:18 +02:00
nala 89ab288334 Record L1 grouped QA candidate and verified final export evidence 2026-10-24 13:54:42 +02:00
nala 5030116ee5 Group L1 coverage and implement documented service exemptions in QA 2026-10-24 13:54:32 +02:00
nala 8719e916ea docs: record rational VAT QA candidate and open form dependency 2026-10-24 13:20:52 +02:00
nala 689e7cbe8b feat: preserve exact included VAT fractions and enumerate L1 remainder 2026-10-24 13:20:32 +02:00
nala d89912e579 docs: record IVA L1 QA candidate and explicit remaining scope 2026-10-24 13:00:26 +02:00
nala 544068e8cc feat: demonstrate scoped IVA operations L1 in QA 2026-10-24 12:59:37 +02:00
nala e8c39a1b54 docs: receipt for installed Modelo A acquisitions and totals 2026-10-24 12:19:34 +02:00
nala 1655f57e69 docs: register Modelo A acquisitions QA candidate and evidence
tests / ci (push) Canceled after 0s
2026-10-24 12:14:21 +02:00
nala d18ff0f049 feat: implement opportunity-scoped Modelo A acquisitions in QA 2026-10-24 12:13:57 +02:00
nala 355656b5c8 docs: receipt for installed simulator S1-S3 closure in homologation 2026-10-24 11:41:57 +02:00
nala cd10cccbf4 docs: close S3 monthly PDF review and mark simulator candidate ready for integration
tests / ci (push) Canceled after 0s
2026-10-24 11:37:09 +02:00
nala d044ef1efc docs: record S1 and S2 QA results and directed S3 file checks 2026-10-24 11:30:59 +02:00
nala 65b87819a0 fix: preserve cashflow currency and recover admitted monthly IVA executions in QA 2026-10-24 11:29:15 +02:00
nala be62783b98 docs: delimit simulator closure to two code gaps and monthly export proof 2026-10-24 11:16:42 +02:00
nala 98fc16a3fb docs: record installed stabilization reference and finite remaining scope 2026-10-24 11:10:51 +02:00
nala 276d833a4b test: consolidate stabilization reference and preserve accepted contour scope
tests / ci (push) Canceled after 0s
2026-10-24 11:08:35 +02:00
nala 5d45541a11 docs: receipt for installed shared map stabilization and accepted public contours 2026-10-24 10:51:31 +02:00
nala 066707ece6 fix: restore shared map access and publish accepted administrative boundary projection
tests / ci (push) Canceled after 0s
2026-10-24 10:47:13 +02:00
nala c1f4a71963 docs: record installed anchor integration and exact territorial recovery 2026-10-23 19:26:07 +02:00
nala cf2ddf21a1 fix: verify territorial recovery manifest with canonical Git line endings
tests / ci (push) Canceled after 0s
2026-10-23 19:20:25 +02:00
nala 3fd5128c62 fix: connect documentary anchors to investment preparation and recover accepted territories
tests / ci (push) Canceled after 0s
2026-10-23 19:17:15 +02:00
nala cdf8fcfba4 docs: record installed treatment scope and verified native PDF 2026-10-23 18:50:13 +02:00
nala 8036b9b071 docs: verify saved native PDF and release delivery condition
tests / ci (push) Canceled after 0s
2026-10-23 18:44:09 +02:00
nala 6985f82e9c docs: delimit anchor findings and pending native PDF delivery gate 2026-10-23 18:36:08 +02:00
nala 2856240cf4 fix: print selected requirements and translated opportunity stage states 2026-10-23 18:34:39 +02:00
nala 32144aa2f3 docs: record treatment scope QA and anchor search analysis boundary 2026-10-23 18:26:00 +02:00
nala 1afdfee8c0 fix: share selected opportunity across simulator stages and land shortcuts 2026-10-23 18:25:09 +02:00
nala bc84fbdb3e docs: delimit remaining transversal investment scope 2026-10-23 18:06:42 +02:00
nala b6a626c92d Record installed opportunity-consumer delta in homologation 2026-10-23 17:58:15 +02:00
nala 55136b446d Record directed QA proof for all four opportunity consumers
tests / ci (push) Canceled after 0s
2026-10-23 17:51:45 +02:00
nala 4a01e9e2b7 Scope parks and downstream investment requests to the treated opportunity 2026-10-23 17:49:22 +02:00
nala ad4160f040 Record second-opportunity context assessment and bounded consumer gaps 2026-10-23 17:18:55 +02:00
nala af9261809c Record installed complements delta and preserved acceptance 2026-10-23 17:14:04 +02:00
nala d8224ba84b Align public simulator entry check with integrated home layout
tests / ci (push) Canceled after 0s
2026-10-23 17:11:15 +02:00
nala 088f2c2cf4 Merge remote-tracking branch 'origin/main' into codex/investment-complements-20261023
tests / ci (push) Canceled after 0s
2026-10-23 16:35:03 +02:00
nala 603a88e1d3 Link documented investment complements to existing fiches and dossier context 2026-10-23 16:34:57 +02:00
paulomassigue 43cd0be7cb correcao de conflitos
tests / ci (push) Canceled after 0s
2026-10-23 16:03:34 +02:00
paulomassigue 89a9c3d994 mudanca o botao Tempo no hear fica Mais 2026-10-23 15:58:59 +02:00
nala 4098192a05 Record installed continuity corrections and destination delta checks 2026-10-23 15:48:52 +02:00
paulomassigue d242482042 home ajustado 2026-10-23 15:46:53 +02:00
nala 6b544548d3 Fix compressed draft saves provenance and Beira documentary continuity
tests / ci (push) Canceled after 0s
2026-10-23 15:41:37 +02:00
nala c3f7c3ad10 Record homologation product journey findings and publication status 2026-10-23 15:26:38 +02:00
nala 445aa7e69d Record consolidated adaptive portfolio installation receipt 2026-10-23 15:17:59 +02:00
nala 7c1f532134 Preserve inactive document history in adaptive reports
tests / ci (push) Canceled after 0s
2026-10-23 15:14:44 +02:00
nala 115c773162 Record QA continuity recovery after return reload and login
tests / ci (push) Canceled after 0s
2026-10-23 15:03:22 +02:00
paulomassigue ec4b2f2af2 organizacao da tela inicial 2026-10-23 14:51:34 +02:00
nala 3d877ec745 Preserve selected portfolio context through investment preparation 2026-10-23 14:35:50 +02:00
nala 6948ed62fc Consolidate adaptive preparation QA delivery and accepted evidence 2026-10-23 14:19:05 +02:00
nala 7d798579a6 Reconcile portfolio recovery evidence and integrated journey gap 2026-10-23 14:17:42 +02:00
nala 5bda74aedc Adapt land status to saved investment land need 2026-10-23 14:13:58 +02:00
nala f2150b1912 Reuse investment context as editable simulator summaries 2026-10-23 14:03:37 +02:00
nala 7ca94967f3 Adapt preparation presentation to declared applicability 2026-10-23 13:53:02 +02:00
nala e1f010f941 fix: preserve corridor filters and keep investment previews readable
tests / ci (push) Canceled after 0s
2026-10-23 13:30:10 +02:00
nala 0025309b98 feat: adapt investment territories to Tempo corridor configuration
tests / ci (push) Canceled after 0s
2026-10-23 13:24:58 +02:00
nala a0e80db4ec docs: confirm opportunity preparation continuity in homologation
tests / ci (push) Canceled after 0s
2026-10-23 12:31:36 +02:00
nala 7226287526 fix: keep opportunity preparation focused on the pending selection
tests / ci (push) Canceled after 0s
2026-10-23 12:29:26 +02:00
nala f1ac82ae4d docs: record clean investor entry verified in homologation
tests / ci (push) Canceled after 0s
2026-10-23 12:20:28 +02:00
nala 98474777f6 fix: remove internal metadata from investor dossier presentation
tests / ci (push) Canceled after 0s
2026-10-23 12:18:25 +02:00
nala 3848f29bea docs: record corridor catalogue verification in homologation
tests / ci (push) Canceled after 0s
2026-10-23 12:12:05 +02:00
nala 203492997e feat: explore the public opportunity catalogue by corridor
tests / ci (push) Canceled after 0s
2026-10-23 12:08:33 +02:00
nala 165c2f6171 fix: keep internal agribusiness delivery notes out of portal presentation
tests / ci (push) Canceled after 0s
2026-10-23 11:22:39 +02:00
nala 4ad1bf402b docs: record authenticated publication of 34 agribusiness opportunities
tests / ci (push) Canceled after 0s
2026-10-23 11:12:45 +02:00
nala e12ef6ad42 Record installed agribusiness workflow, preserved destination and pending real-account publication
tests / ci (push) Canceled after 0s
2026-10-23 11:00:30 +02:00
nala c641b267ac Publish agribusiness lot through scoped management and extend existing dossier for multiple opportunities
tests / ci (push) Canceled after 0s
2026-10-23 10:49:50 +02:00
paulomassigue e2b0fb4b2d melhorias de home 1 2026-10-23 10:36:34 +02:00
nala 7d08c2c664 Register 34 private agribusiness opportunities with promotional management and investor paths in QA 2026-10-23 10:15:41 +02:00
nala 761035aefb Record homologation agribusiness installation and preserved QA evidence
tests / ci (push) Canceled after 0s
2026-10-23 09:58:13 +02:00
nala 20a4099d10 Present 34 agribusiness opportunities in existing corridor sections
tests / ci (push) Canceled after 0s
2026-10-23 09:56:22 +02:00
nala e03de682ca Preserve completed features and restore approved portfolio visibility
tests / ci (push) Canceled after 0s
2026-10-23 09:19:25 +02:00
nala 37a8eb015a docs: record private legacy registration and authenticated editorial access
tests / ci (push) Canceled after 0s
2026-10-22 23:55:57 +02:00
nala 65eddf6bc7 merge: install reviewed private legacy editorial workflow
tests / ci (push) Canceled after 0s
2026-10-22 23:40:27 +02:00
nala fb4e7d8970 Complete private legacy article editing and previews in QA 2026-10-22 23:36:07 +02:00
nala bc93ccdb9e docs: reconcile all legacy articles and verify private QA batches 2026-10-22 23:10:21 +02:00
nala 7ccf62adec docs: record authenticated tender installation and final links
tests / ci (push) Canceled after 0s
2026-10-22 22:54:59 +02:00
nala f4d0970917 merge: install reviewed tender publishing in homologation
tests / ci (push) Canceled after 0s
2026-10-22 22:49:18 +02:00
nala e46f973159 docs: plan staged tender schema installation and activation 2026-10-22 22:44:42 +02:00
nala 1bcf34c0c0 feat: add QA tender and announcement publishing workflow 2026-10-22 22:41:28 +02:00
nala ef0c2acd36 docs: record authenticated homologation geometry restoration and access proof
tests / ci (push) Canceled after 0s
2026-10-22 22:04:32 +02:00
nala 30aed7cd12 Merge approved administrative access for geometry restoration
tests / ci (push) Canceled after 0s
2026-10-22 21:55:48 +02:00
nala 95d4cf44d7 fix: reuse approved administration for authenticated geometry import 2026-10-22 21:55:36 +02:00
nala 73c046e104 Merge territorial demarcation recovery reviewed for homologation
tests / ci (push) Canceled after 0s
2026-10-22 21:45:58 +02:00
nala 15d82611b6 fix: recover territorial demarcation QA and prepare retained geometry restoration 2026-10-22 21:43:54 +02:00
nala 8286d7504d fix: preserve approved editorial access independently of technical reservation
tests / ci (push) Canceled after 0s
2026-10-22 21:03:11 +02:00
nala aa2b3d05b0 fix: route authorised content staff through management access entry
tests / ci (push) Waiting to run
2026-10-22 21:00:05 +02:00
nala 97d51db60a feat: add unified team content management entry in QA
tests / ci (push) Canceled after 0s
2026-10-22 20:55:08 +02:00
Nelson_Matsinhe a1b553372e ajuste do tamanho da navbar
tests / ci (push) Canceled after 0s
2026-10-22 15:26:56 +02:00
nala f80d30f478 docs: record Tempo approval for catalogue selector integration
tests / ci (push) Canceled after 0s
2026-10-22 14:36:36 +02:00
nala 916819eb35 docs: record keyboard selector proof and mouse observation limit 2026-10-22 14:33:59 +02:00
nala 1d921c9d03 fix: keep public catalogue selectors independent of opportunity results 2026-10-22 14:28:40 +02:00
nala 7b1c35793c Fix Node navigation import and use Tempo commercial footer contact
tests / ci (push) Canceled after 0s
2026-10-22 13:54:20 +02:00
nala 1ec318561c docs: record authorised Inhambane preparation publication
tests / ci (push) Canceled after 0s
2026-10-22 13:47:50 +02:00
nala 9ac623a433 fix: preserve territorial search across investment catalogues 2026-10-22 12:52:52 +02:00
966 changed files with 128179 additions and 1088 deletions
+16
View File
@@ -0,0 +1,16 @@
.git
.idea
.agents
.codex
node_modules
vendor
public/build
storage/logs
storage/framework/cache
storage/framework/sessions
storage/framework/views
tests
Doc
docs
*.zip
.phpunit.result.cache
+3
View File
@@ -12,3 +12,6 @@ database/data/economic-references-lot-01.json text eol=crlf
CHANGELOG.md export-ignore
README.md export-ignore
.github/workflows/browser-tests.yml export-ignore
# Preserve the original archived BM HTML bytes and whitespace.
docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html -text -diff
+18
View File
@@ -1,5 +1,13 @@
# Instruções permanentes do projeto InvesteMoz
## Percurso adaptativo — decisão expressa da Tempo, 23/10/2026
Carteira/projectos âncora e percurso adaptativo têm diagnósticos distintos, mas fazem parte da mesma experiência e responsabilidade de correcção. Separar o diagnóstico não autoriza adiamento, desligamento do percurso ou perda de contexto entre corredor/localização, oportunidades, associações documentadas a âncoras/clusters, dossier e simulador. A reposição prioritária só se considera demonstrada com causa delimitada e disponibilidade recuperada, reutilizando o inventário e os recibos existentes; melhorias noutro ponto não a comprovam. Consultar os registos de reposição antes de voltar a declarar causa desconhecida ou registos desaparecidos.
Apresentar apenas o necessário ao investimento em preparação, com entrada por ideia, oportunidade, sector ou localização, reutilizando informação válida e autorizada da oportunidade, perfil, organização, dossier e fontes anteriores. As etapas são adaptáveis, não seis formulários obrigatórios. Não sobrescrever edições deliberadas; explicar divergências e impactos antes da confirmação. Conservar escolhas ao avançar, regressar, actualizar e autenticar-se. Seleccionar opções únicas e pedir apenas dados em falta ou desactualizados.
Ocultar campos e acções sem aplicação, conservando explicação breve e histórico; desconhecido não significa não aplicável. Na selecção múltipla, partilhar dados comuns sem perder os requisitos específicos de cada oportunidade. Consulta pública livre; autenticação no momento de manifestar interesse ou iniciar operação privada. Relatórios e exportações devem reflectir o contexto e as etapas efectivamente aplicáveis. O utilizador deve perceber onde está, o que falta e a próxima acção. Aperfeiçoar os componentes existentes por incrementos e registar cobertura na matriz existente; esta instrução não declara concluída a sua implementação transversal.
## Regras permanentes do InvesteMoz — decisão da Tempo, 12/10/2026
1. O portal InvesteMoz é propriedade da Tempo, Lda.
@@ -46,3 +54,13 @@ Referenciar estas orientações nos requisitos correspondentes da matriz existen
A legislação, os formulários e os procedimentos oficiais disponibilizados são fontes válidas para implementar os requisitos. As decisões e procedimentos da Tempo orientam a sua utilização no portal. Traduzir essas fontes em campos, regras, documentos, cálculos e percursos executáveis com rastreabilidade, sem exigir nova validação jurídica genérica ou criar aprovadores, restrições ou condições por interpretação do Codex.
Uma divergência concreta deve identificar os trechos, períodos e comportamento afectados; prosseguir com os restantes requisitos. Uma decisão de implementação em falta deve ser apresentada especificamente à Tempo, sem a substituir por regra inventada. Rever e remover bloqueios anteriores sem fundamento numa fonte aplicável ou decisão expressa da Tempo, preservando dados e histórico. A rastreabilidade explica a execução e não constitui uma autoridade adicional. Mantêm-se os limites autorizados de QA e das alterações no activo.
## Preservação do concluído — pedido expresso da Tempo, 23/10/2026
Antes de avançar com novas rondas de testes/validações, inventariar na matriz e no manual existentes as funcionalidades concluídas e as funcionalidades desaparecidas, e repor as perdas confirmadas. Preservar as aprovações, dados, originais, relações, versões, histórico e acessos já concluídos. Não transformar uma entrega anterior em funcionalidade nova nem exigir novamente a decisão organizacional já registada.
Comparar código, schema, dados, configuração e permissões entre o último estado demonstrado e o destino. Distinguir eliminação, perda de visibilidade, diferença de ambiente, pendência real e estado documental desactualizado; uma página vazia ou a falta de nova prova não apagam a aceitação anterior. Reutilizar as provas aceites e conferir apenas o delta da reposição. Cada entrega seguinte deve explicar qualquer redução do âmbito previamente disponível, em vez de a aceitar como consequência normal da implementação.
Transporte privado não equivale à revogação de uma divulgação anterior aprovada. Reconciliar a decisão anterior de forma delimitada e auditada, sem publicar automaticamente conteúdos novos, reviver exemplares arquivados ou sobrescrever edições posteriores. Mantêm-se backup/restauro, autenticação e os limites concretos de cada tarefa.
Escolha técnica de verificação: comparar dados protegidos por segurança por linha (RLS) com identidades e contexto de acesso equivalentes. Uma leitura da aplicação sem actor pode ocultar registos que o utilizador do backup consegue ler; confirmar essa diferença antes de declarar perda ou propor reposição. Esta orientação não altera permissões do portal nem autoriza contornar RLS numa operação da equipa.
File diff suppressed because one or more lines are too long
Binary file not shown.
+342
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -0,0 +1,70 @@
<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\Controller;
use App\Jobs\ScanDocumentForMalware;
use App\Services\SimulationFormDrafts;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class SimulationOfferDocumentController extends Controller
{
public function store(Request $request, string $id, SimulationFormDrafts $drafts)
{
abort_unless(Str::isUuid($id), 404);
$drafts->find($id, $request);
// Same private document infrastructure and technical file limit as investment attachments.
$request->validate(['file' => ['required', 'file', 'mimetypes:application/pdf,text/plain,image/png,image/jpeg', 'max:10240']]);
$file = $request->file('file');
$hash = hash_file('sha256', $file->getRealPath());
$existing = DB::table('documents')->where('source_system', 'simulation-fiscal-offer')->where('external_id', $id)->where('sha256', $hash)->whereNull('deleted_at')->first();
if ($existing) {
return response()->json(['data' => $this->metadata($id, $existing)], 200)->header('Cache-Control', 'private, no-store');
}
$documentId = (string) Str::uuid();
$key = $file->storeAs('simulation-offers/'.$id, $documentId, 'local');
abort_unless(is_string($key), 500);
try {
DB::table('documents')->insert(['id' => $documentId, 'source_system' => 'simulation-fiscal-offer', 'external_id' => $id,
'file_name' => basename($file->getClientOriginalName()), 'media_type' => $file->getMimeType(), 'storage_key' => $key,
'sha256' => $hash, 'size_bytes' => $file->getSize(), 'uploaded_by' => $request->user()->id,
'status' => 'quarantined', 'data_classification' => 'confidential']);
} catch (\Throwable $e) {
Storage::disk('local')->delete($key);
throw $e;
}
ScanDocumentForMalware::dispatch($documentId)->afterCommit();
return response()->json(['data' => $this->metadata($id, DB::table('documents')->where('id', $documentId)->first())], 201)->header('Cache-Control', 'private, no-store');
}
public function index(Request $request, string $id, SimulationFormDrafts $drafts)
{
abort_unless(Str::isUuid($id), 404);
$drafts->find($id, $request);
$documents = DB::table('documents')->where('source_system', 'simulation-fiscal-offer')->where('external_id', $id)->whereNull('deleted_at')->get();
return response()->json(['data' => $documents->map(fn ($doc) => $this->metadata($id, $doc))])->header('Cache-Control', 'private, no-store');
}
public function download(Request $request, string $id, string $document, SimulationFormDrafts $drafts)
{
abort_unless(Str::isUuid($id) && Str::isUuid($document), 404);
$drafts->find($id, $request);
$doc = DB::table('documents')->where('id', $document)->where('source_system', 'simulation-fiscal-offer')->where('external_id', $id)->whereNull('deleted_at')->first();
abort_unless($doc, 404);
abort_unless($doc->status === 'active' && $doc->malware_scan_status === 'clean' && hash_equals(trim($doc->sha256), (string) $doc->malware_scanned_sha256), 409, 'Anexo conservado; descarga disponível após análise antimalware concluída.');
$root = realpath(Storage::disk('local')->path('simulation-offers/'.$id));
$path = realpath(Storage::disk('local')->path($doc->storage_key));
abort_unless($root && $path && str_starts_with(strtolower($path), strtolower($root.DIRECTORY_SEPARATOR)) && is_file($path), 404);
abort_unless(hash_equals(trim($doc->sha256), hash_file('sha256', $path)), 409, 'Conteúdo do anexo diverge do hash registado.');
return response()->download($path, basename($doc->file_name), ['Cache-Control' => 'private, no-store', 'X-Content-Type-Options' => 'nosniff']);
}
private function metadata(string $id, object $doc): array
{
return ['id' => $doc->id, 'draftId' => $id, 'name' => $doc->file_name, 'sha256' => trim($doc->sha256),
'scan' => $doc->malware_scan_status, 'url' => '/api/v1/simulation-drafts/'.$id.'/offer-documents/'.$doc->id];
}
}
@@ -0,0 +1,73 @@
<?php
namespace App\Http\Controllers;
use App\Models\Opportunity;
use App\Services\CorridorAgribusinessOpportunities;
use App\Services\OpportunityManagement;
use App\Services\OpportunityPromotion;
use App\Services\PortalProfileAccess;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
final class CorridorAgribusinessController extends Controller
{
private function manifest(CorridorAgribusinessOpportunities $service): string
{
return hash('sha256', json_encode($service->entries(), JSON_THROW_ON_ERROR));
}
public function show(Request $request, CorridorAgribusinessOpportunities $service)
{
$access = app(PortalProfileAccess::class);
abort_unless($access->internalAssignment($request->user(), 'investment_project') || $access->has($request->user(), 'publisher'), 403);
$records = Opportunity::withTrashed()->whereIn('management_creation_key', array_column($service->entries(), 'key'))->get()->keyBy('management_creation_key');
foreach ($records as $record) abort_unless($access->canView($request->user(), $record), 403);
return Inertia::render('management/corridor-agribusiness', ['manifestHash' => $this->manifest($service),
'canRegister' => (bool) $access->internalAssignment($request->user(), 'investment_project'),
'entries' => array_map(function ($entry) use ($records) {
$r = $records->get($entry['key']);
return [...$entry, 'id' => $r?->id, 'status' => $r?->status, 'href' => $r ? '/oportunidades/'.$r->slug : null];
}, $service->entries())]);
}
public function register(Request $request, CorridorAgribusinessOpportunities $service)
{
$data = $request->validate(['manifest_hash' => 'required|string|size:64', 'confirm' => 'required|accepted']);
abort_unless(hash_equals($this->manifest($service), $data['manifest_hash']), 409, 'A fonte mudou; recupere a prévia.');
$access = app(PortalProfileAccess::class);
$grant = $access->internalAssignment($request->user(), 'investment_project');
abort_unless($grant && $access->mfa($request->user()), 403, 'Use a designação existente e MFA recente.');
return response()->json(['records' => $service->register($request->user(), $grant->organization_id)]);
}
public function preview(Request $request, CorridorAgribusinessOpportunities $service)
{
$previews = [];
foreach ($service->entries() as $entry) {
$record = Opportunity::where('management_creation_key', $entry['key'])->firstOrFail();
$input = data_get($record->workflow_context, 'promotional_summary.input');
abort_unless(is_array($input), 409, 'Complete a selecção pública na divulgação individual.');
$previews[] = ['id' => $record->id, ...app(OpportunityPromotion::class)->preview($request->user(), $record,
[...$input, 'source_date' => $input['source_date'] ?: null, 'action' => 'disclose', 'etag' => app(OpportunityManagement::class)->etag($record)])];
}
return response()->json(['previews' => $previews]);
}
public function disclose(Request $request, CorridorAgribusinessOpportunities $service)
{
$data = $request->validate(['confirm' => 'required|accepted', 'reason' => 'required|string|min:20|max:1000',
'previews' => 'required|array|size:34', 'previews.*.id' => 'required|integer|distinct',
'previews.*.token' => 'required|string|max:300000', 'previews.*.operation_key' => 'required|uuid|distinct']);
$expected = Opportunity::whereIn('management_creation_key', array_column($service->entries(), 'key'))->pluck('id')->sort()->values()->all();
$supplied = array_column($data['previews'], 'id'); sort($supplied);
abort_unless($expected === $supplied && count($expected) === 34, 409, 'A prévia deve identificar exactamente as 34 fichas deste lote.');
return response()->json(DB::transaction(function () use ($request, $data) {
$result = [];
foreach ($data['previews'] as $preview) $result[] = app(OpportunityPromotion::class)->confirm($request->user(), $preview['id'],
[...$preview, 'confirm' => true, 'reason' => $data['reason']]);
return ['records' => $result];
}));
}
}
@@ -81,31 +81,18 @@ class EditorialArticleController extends Controller
app(\App\Services\DocumentManagementAccess::class)->assertEditableResource(request()->user(), $id);
$r = DB::table('portal_resources')->find($id);
abort_unless($r, 404);
$content = $r->editorial_content ? json_decode($r->editorial_content, true) : null;
if ($content === null) {
$document = DB::table('documents')->find($r->document_id);
if ($document && $document->status === 'active' && $document->malware_scan_status === 'clean'
&& in_array($document->media_type, ['text/plain', 'application/json'], true)) {
$binary = app(VerifiedDocumentBinary::class)->respond($document);
$bytes = $binary instanceof \Symfony\Component\HttpFoundation\BinaryFileResponse
? file_get_contents($binary->getFile()->getPathname()) : $binary->getContent();
$original = json_decode($bytes, true);
if (is_array($original) && ($original['format'] ?? '') === 'investmoz-legacy-article-v1') {
$html = preg_replace('~</(?:p|div|li|h[1-6])>|<br\s*/?>~i', "\n\n", $original['content_html'] ?? '');
$content = ['body' => trim(html_entity_decode(strip_tags($html), ENT_QUOTES | ENT_HTML5, 'UTF-8')), 'image_resource_id' => null];
}
}
}
return Inertia::render('portal/article-editor', ['resource' => ['id' => $r->id, 'title' => $r->title, 'metadata_version' => $r->metadata_version],
'content' => $content, 'images' => $this->publicResources()->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp'])->get(['r.id', 'r.title']),
'revisions' => DB::table('portal_resource_revisions')->where('resource_id', $id)->orderByDesc('revision_no')->get(['revision_no', 'change_type', 'created_at'])]);
$reading = app(\App\Services\EditorialReading::class);
$original = $reading->original($r);
$content = $reading->content($r, $original);
return Inertia::render('portal/article-editor', ['resource' => ['id' => $r->id, 'title' => $r->title, 'metadata_version' => $r->metadata_version, 'published' => (bool) $r->published],
'content' => $content, 'source' => $original ? array_intersect_key($original, array_flip(['source_url', 'published_at', 'modified_at', 'legacy_id', 'image_source_url'])) : null, 'images' => $this->publicResources()->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp'])->get(['r.id', 'r.title']),
'revisions' => DB::table('portal_resource_revisions')->where('resource_id', $id)->orderByDesc('revision_no')->get(['revision_no', 'change_type', 'created_at'])])->toResponse(request())->header('Cache-Control', 'private, no-store');
}
public function save(Request $request, int $id)
{
$this->installed();
$data = $request->validate(['body' => ['required', 'string', 'max:100000'], 'image_resource_id' => ['nullable', 'integer'], 'metadata_version' => ['required', 'integer', 'min:1']]);
$data = $this->validateContent($request);
DB::transaction(function () use ($request, $id, $data) {
$r = DB::table('portal_resources')->where('id', $id)->lockForUpdate()->first();
abort_unless($r, 404);
@@ -118,7 +105,7 @@ class EditorialArticleController extends Controller
if ($body === '') {
throw ValidationException::withMessages(['body' => 'Escreva o corpo do artigo.']);
}
$content = ['format' => 1, 'body' => $body, 'image_resource_id' => $data['image_resource_id'] ?? null];
$content = $this->edition($r, $data);
$revision = (int) $r->metadata_version + 1;
DB::table('portal_resources')->where('id', $id)->update(['editorial_content' => json_encode($content, JSON_THROW_ON_ERROR), 'published' => false, 'approved_by' => null, 'metadata_version' => $revision, 'last_reviewed_by' => $request->user()->id, 'last_reviewed_at' => now(), 'updated_at' => now()]);
$resource = DB::table('portal_resources')->find($id);
@@ -130,16 +117,46 @@ class EditorialArticleController extends Controller
return redirect('/management/portal-services/resources/'.$id.'/article')->with('success', 'Artigo guardado como rascunho. Publique expressamente no acervo quando estiver pronto.');
}
public function show(int $id)
private function validateContent(Request $request): array
{
return $request->validate(['body' => ['required', 'string', 'max:100000'], 'image_resource_id' => ['nullable', 'integer'], 'image_mode' => ['nullable', 'in:original,selected,none'], 'metadata_version' => ['required', 'integer', 'min:1']]);
}
private function edition(object $resource, array $data): array
{
$reading = app(\App\Services\EditorialReading::class);
$original = $reading->original($resource);
$mode = $data['image_mode'] ?? (!empty($data['image_resource_id']) ? 'selected' : 'none');
if ($mode === 'selected') abort_unless(!empty($data['image_resource_id']) && $reading->publicResources()->where('r.id', $data['image_resource_id'])->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp'])->exists(), 422, 'Escolha uma imagem pública disponível na biblioteca.');
return ['format' => 1, 'body' => trim($data['body']), 'image_mode' => $mode, 'image_resource_id' => $mode === 'selected' ? (int)$data['image_resource_id'] : null,
'preserve_original_html' => $original && trim($data['body']) === $reading->plain($original['content_html'])];
}
public function preview(Request $request, int $id)
{
$this->installed();
$r = $this->publicResources()->where('r.id', $id)->first(['r.id', 'r.title', 'r.description', 'r.editorial_content', 'r.document_id', 'd.issuer']);
abort_unless($r && $r->editorial_content, 404);
$content = json_decode($r->editorial_content, true);
// Recheck the original bytes using the same binary gate as the library.
$binary = app(VerifiedDocumentBinary::class)->respond($this->publicResources()->where('r.id', $id)->first(['r.*', 'd.*']));
$image = ! empty($content['image_resource_id']) ? $this->publicResources()->where('r.id', $content['image_resource_id'])->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp'])->value('r.id') : null;
app(\App\Services\DocumentManagementAccess::class)->assertEditableResource($request->user(), $id);
$resource = DB::table('portal_resources')->find($id); abort_unless($resource, 404);
return Inertia::render('portal/article', ['article' => app(\App\Services\EditorialReading::class)->reading($resource, null, true)])
->toResponse($request)->header('Cache-Control', 'private, no-store')->header('X-Robots-Tag', 'noindex, nofollow');
}
return Inertia::render('portal/article', ['article' => ['id' => $id, 'title' => $r->title, 'description' => $r->description, 'author' => $r->issuer, 'body' => $content['body'], 'image_url' => $image ? '/documentos/'.$image.'/view' : null, 'original_url' => '/documentos/'.$id]]);
public function previewContent(Request $request, int $id)
{
$this->installed();
app(\App\Services\DocumentManagementAccess::class)->assertEditableResource($request->user(), $id);
$resource = DB::table('portal_resources')->find($id); abort_unless($resource, 404);
$data = $this->validateContent($request);
abort_unless((int)$resource->metadata_version === (int)$data['metadata_version'], 409, 'A revisão mudou; recupere antes de rever a prévia.');
return response()->json(['article' => app(\App\Services\EditorialReading::class)->reading($resource, $this->edition($resource, $data), true)])
->header('Cache-Control', 'private, no-store')->header('X-Robots-Tag', 'noindex, nofollow');
}
public function show(Request $request, int $id)
{
$this->installed();
$resource = app(\App\Services\EditorialReading::class)->publicResources()->where('r.id', $id)->first(['r.*']);
abort_unless($resource, 404);
return Inertia::render('portal/article', ['article' => app(\App\Services\EditorialReading::class)->reading($resource)])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
}
@@ -0,0 +1,27 @@
<?php
namespace App\Http\Controllers;
use App\Services\InvestmentComplements;
use Illuminate\Http\Request;
final class InvestmentComplementController extends Controller
{
public function index(Request $request, InvestmentComplements $service)
{
$data = $request->validate(['origin' => [\Illuminate\Validation\Rule::requiredIf(!$request->has('contexts')), 'nullable', 'string', 'max:100'], 'territory_id' => 'nullable|uuid',
'contexts' => 'sometimes|array|max:100', 'contexts.*' => 'array:origin,territory_id', 'contexts.*.origin' => 'required|string|max:100', 'contexts.*.territory_id' => 'nullable|uuid']);
$items = [];
$issues = [];
foreach ($data['contexts'] ?? [['origin' => $data['origin'], 'territory_id' => $data['territory_id'] ?? null]] as $context) {
try {
$items = [...$items, ...$service->options($context['origin'], $context['territory_id'] ?? null)];
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException|\Symfony\Component\HttpKernel\Exception\HttpException $e) {
$status = $e instanceof \Symfony\Component\HttpKernel\Exception\HttpException ? $e->getStatusCode() : 404;
if (!isset($data['contexts']) || $status !== 404) throw $e;
$issues[] = ['origin' => $context['origin'], 'message' => 'Uma referência escolhida deixou de estar disponível para consulta pública. A relação guardada conserva-se no dossier; os outros complementos continuam disponíveis.'];
}
}
return response()->json(isset($data['contexts']) ? ['items' => $items, 'issues' => $issues] : $items)->header('Cache-Control', 'private, no-store');
}
}
@@ -26,6 +26,7 @@ class InvestmentDiscoveryController extends Controller
}
return Inertia::render('investment/catalogue', ['filters' => $filters, 'catalogueUrl' => $request->routeIs('investment.education') ? '/educacao' : '/oportunidades', 'references' => $catalogue->references(false, $filters),
'corridorGroups' => ($filters['view'] ?? '') === 'corridors' ? app(\App\Services\OpportunityCorridorExplorer::class)->groups($filters) : [],
'territorySelection' => app(InvestmentGeography::class)->selection($filters),
'guides' => app(\App\Services\SectorInvestment::class)->guides(\App\Models\Sector::where('slug', $filters['sector'] ?? '')->where('is_active', true)->whereNotNull('published_at')->first()),
'results' => $catalogue->query($filters)->paginate(12)->withQueryString(),
@@ -88,7 +89,7 @@ class InvestmentDiscoveryController extends Controller
$data = $request->validate(['zone_id' => ['nullable', 'uuid'], 'from_dossier' => ['nullable', 'uuid']]);
$dossierOrigin = isset($data['from_dossier']) ? InvestmentPortfolioController::visible()->whereKey($data['from_dossier'])->firstOrFail() : null;
if ($dossierOrigin) {
$linked = false;
$linked = in_array($record->id, app(\App\Services\CorridorAgribusinessOpportunities::class)->portfolioOpportunityIds($dossierOrigin), true);
foreach (['projects' => 'project_id', 'clusters' => 'cluster_id', 'corridors' => 'corridor_id'] as $relation => $foreign) {
if ($dossierOrigin->$foreign && DB::table('opportunity_'.$relation)->where('opportunity_id', $record->id)->where($foreign, $dossierOrigin->$foreign)->exists()) {
$linked = true;
@@ -106,7 +107,7 @@ class InvestmentDiscoveryController extends Controller
$returnFilters = $request->query();
unset($returnFilters['zone_id'], $returnFilters['from_dossier']);
return Inertia::render('investment/detail', ['record' => $record, 'context' => $catalogue->context($record->id), 'zone_origin' => $origin,
return Inertia::render('investment/detail', ['complements' => app(\App\Services\InvestmentComplements::class)->options('opportunity:'.$record->id), 'record' => $record, 'context' => $catalogue->context($record->id), 'zone_origin' => $origin,
'guides' => app(\App\Services\SectorInvestment::class)->guides($record->sector),
'dossierOrigin' => $dossierOrigin ? ['id' => $dossierOrigin->id, 'title' => $dossierOrigin->title] : null,
'returnUrl' => $returnFilters === [] ? '/oportunidades' : '/oportunidades?'.http_build_query($returnFilters)]);
@@ -61,8 +61,15 @@ class InvestmentPortfolioController extends Controller
{
$management = $request->routeIs('management.portfolio*');
$filters = $request->validate(['q' => ['nullable', 'string', 'max:120'], 'kind' => ['nullable', 'in:corridor,cluster,project'],
'sector' => ['nullable', 'string', 'max:500'],
'province_id' => ['nullable', 'uuid'], 'district_id' => ['nullable', 'uuid'], 'admin_post_id' => ['nullable', 'uuid'], 'locality_id' => ['nullable', 'uuid']]);
$query = $management ? InvestmentDossier::query() : self::visible();
$sectorOptions = ($management ? InvestmentDossier::query() : self::visible())
->whereNotNull('content->sector')->get()->pluck('content.sector')
->filter(fn ($sector) => is_string($sector) && trim($sector) !== '')->unique()->sort()->values();
if (! empty($filters['sector'])) {
$query->where('content->sector', $filters['sector']);
}
if (! empty($filters['kind'])) {
$query->whereNotNull($filters['kind'].'_id');
}
@@ -76,7 +83,7 @@ class InvestmentPortfolioController extends Controller
}
return Inertia::render('portfolio/index', ['records' => $query->orderBy('title')->paginate(30)->withQueryString(),
'management' => $management, 'filters' => $filters, 'territorySelection' => $territorySelection]);
'management' => $management, 'filters' => $filters, 'sectors' => $sectorOptions, 'territorySelection' => $territorySelection]);
}
public function show(Request $request, string $id): Response
@@ -105,6 +112,7 @@ class InvestmentPortfolioController extends Controller
$opportunities = Opportunity::published()->where(function ($query) use ($record) {
$query->whereRaw('false');
$query->orWhereIn('id', app(\App\Services\CorridorAgribusinessOpportunities::class)->portfolioOpportunityIds($record));
foreach (['clusters' => 'cluster_id', 'corridors' => 'corridor_id', 'projects' => 'project_id'] as $relation => $foreign) {
if ($record->$foreign) {
$query->orWhereIn('id', DB::table('opportunity_'.$relation)->where($foreign, $record->$foreign)->select('opportunity_id'));
@@ -130,12 +138,19 @@ class InvestmentPortfolioController extends Controller
->orderByDesc('updated_at')->limit(10)->get(['id', 'version', 'updated_at'])
: collect();
return Inertia::render('portfolio/show', ['record' => $record, 'related' => $related, 'management' => $management, 'zones' => $zones,
return Inertia::render('portfolio/show', ['complements' => $management ? [] : app(\App\Services\InvestmentComplements::class)->options('portfolio:'.$record->id), 'record' => $record, 'related' => $related, 'management' => $management, 'zones' => $zones,
'anchorProject' => $anchorProject, 'existingSubmissions' => $existingSubmissions,
'geography' => app(InvestmentRelations::class)->dossier($record, $management),
'origin' => $origin ? ['id' => $origin->id, 'title' => $origin->title] : null, 'opportunities' => $opportunities, 'chains' => $chains]);
}
public function resumeInterest(Request $request, string $id): RedirectResponse
{
self::visible()->findOrFail($id);
$data = $request->validate(['catalogue_query' => ['nullable', 'string', 'max:4000']]);
return redirect('/carteira/'.$id.'?'.http_build_query([...$data, 'prepare_interest' => '1']));
}
public function save(Request $request, InvestmentDossier $dossier): RedirectResponse
{
$data = $request->validate(['version_no' => ['required', 'integer', 'min:1'], 'title' => ['required', 'string', 'max:255'], 'source' => ['required', 'string', 'max:2000'],
@@ -192,11 +192,13 @@ class InvestmentSubmissionController extends Controller
{
$required = $submitting ? 'required' : 'nullable';
$data = $request->validate(['version' => ['required', 'integer', 'min:1'],
'payload' => ['required', 'array:context_reuse,full_name,email,phone,country,residence_country_code,incorporation_country_code,organization_country_snapshot,declared_origin_country_code,organisation,representative_role,experience,investment_capacity,profile_id,sector,objective,participation_id,partnership_id,estimated_amount,currency,horizon,location,cluster_ids,corridor_ids,project_ids,contact_consent,other_details'],
'payload' => ['required', 'array:context_opportunity,context_opportunity_snapshot,context_reuse,full_name,email,phone,country,residence_country_code,incorporation_country_code,organization_country_snapshot,declared_origin_country_code,organisation,representative_role,experience,investment_capacity,profile_id,sector,objective,participation_id,partnership_id,estimated_amount,currency,horizon,location,cluster_ids,corridor_ids,project_ids,contact_consent,other_details'],
'payload.organization_country_snapshot' => ['sometimes', 'array', 'max:10'],
'payload.residence_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
'payload.incorporation_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
'payload.declared_origin_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()],
'payload.context_opportunity' => ['nullable', 'string', 'max:100'],
'payload.context_opportunity_snapshot' => ['nullable', 'string', 'max:200000'],
'payload.context_reuse' => ['nullable', 'string', 'max:10000'],
'payload.other_details' => ['nullable', 'string', 'max:5000'],
'payload.full_name' => [$required, 'string', ...($submitting ? ['min:3'] : []), 'max:150'], 'payload.email' => [$required, $submitting ? 'email:rfc' : 'string', 'max:150'],
@@ -247,6 +249,9 @@ class InvestmentSubmissionController extends Controller
}
}
$bound = DB::table('desk_cases')->where('submission_id', $request->route('id'))->where('user_id', $request->user()->id)->whereNotNull('journey_id')->first();
if ($bound) $data['payload'] = app(\App\Services\InvestmentConsumerScope::class)->bind($request->user(), $bound->id, $data['payload'], $submitting);
else unset($data['payload']['context_opportunity'], $data['payload']['context_opportunity_snapshot']);
return $data;
}
@@ -266,7 +271,7 @@ class InvestmentSubmissionController extends Controller
$version = DB::transaction(function () use ($request, $id, $data) {
$row = $this->owned($request, $id, true, true);
abort_unless($row->status === 'draft' && $row->version === (int) $data['version'], 409, 'Rascunho alterado. Recarregue antes de guardar.');
$row->update(['payload' => $this->preserveCountrySource($row, $data['payload']), 'version' => $row->version + 1]);
$row->update([...(isset($data['payload']['context_opportunity']) ? ['opportunity_id'=>(int)substr($data['payload']['context_opportunity'],12)] : []), 'payload' => $this->preserveCountrySource($row, $data['payload']), 'version' => $row->version + 1]);
InvestmentSpecificNeed::where('submission_id', $id)->delete();
foreach ($data['needs'] ?? [] as $need) {
InvestmentSpecificNeed::create([...$need, 'submission_id' => $id]);
@@ -310,7 +315,8 @@ class InvestmentSubmissionController extends Controller
return InterestRequest::findOrFail($row->interest_request_id)->reference;
}
abort_unless($row->version === (int) $data['version'], 409, 'Rascunho alterado. Recarregue.');
$opportunity = $row->opportunity_id ? Opportunity::published()->findOrFail($row->opportunity_id) : null;
$scopeKey = $data['payload']['context_opportunity'] ?? null;
$opportunity = $scopeKey ? Opportunity::published()->findOrFail(substr($scopeKey,12)) : ($row->opportunity_id ? Opportunity::published()->findOrFail($row->opportunity_id) : null);
if ($row->dossier_id) {
InvestmentPortfolioController::visible()->findOrFail($row->dossier_id);
}
@@ -331,12 +337,14 @@ class InvestmentSubmissionController extends Controller
'sector_interest' => $p['sector'], 'message' => $p['objective'], 'privacy_consent' => true, 'consented_at' => now(),
'status' => 'received', 'source_page' => '/investidor/manifestacoes/'.$id,
'metadata' => ['submission_id' => $id, 'portal_user_id' => $request->user()->id, 'dossier_id' => $row->dossier_id,
'context_opportunity' => $p['context_opportunity'] ?? null,
'context_opportunity_snapshot' => $p['context_opportunity_snapshot'] ?? null,
'declared_origin_country_code' => $p['declared_origin_country_code'] ?? null,
'residence_country_code' => $p['residence_country_code'] ?? null,
'incorporation_country_code' => $p['incorporation_country_code'] ?? null,
...(isset($p['organization_country_snapshot']) ? ['organization_country_snapshot' => $p['organization_country_snapshot']] : []),
...($zoneOrigin ? ['zone_origin' => (array) $zoneOrigin] : [])]]));
$row->update(['payload' => $p, 'version' => $row->version + 1, 'interest_request_id' => $interest->id, 'status' => 'submitted']);
$row->update(['opportunity_id'=>$opportunity?->id, 'payload' => $p, 'version' => $row->version + 1, 'interest_request_id' => $interest->id, 'status' => 'submitted']);
InvestmentSpecificNeed::where('submission_id', $id)->delete();
foreach ($data['needs'] ?? [] as $need) {
InvestmentSpecificNeed::create([...$need, 'submission_id' => $id]);
@@ -19,12 +19,21 @@ class InvestmentTerritoryController extends Controller
$data = $request->validate(['territory_id' => ['required', 'uuid']]);
$profile = $request->is('minhas-oportunidades/*');
$management = $request->is('management/*') || $profile;
$actor = $request->user();
$access = app(PortalProfileAccess::class);
// The general consumers use this same endpoint while authenticated.
// Reuse the read access already granted by the private cadastral routes.
$profileAccess = $actor && $actor->hasVerifiedEmail()
&& ($access->grants($actor) !== [] || $access->superuser($actor));
$internal = $profileAccess || ($actor?->hasVerifiedEmail() && $actor->can('manage-portal'));
if ($management) {
$access = app(PortalProfileAccess::class);
abort_unless($profile ? ($access->grants($request->user()) !== [] || $access->superuser($request->user())) : $request->user()?->can('manage-portal'), 403);
abort_unless($profile ? $profileAccess : $internal, 403);
}
return response()->json(app(TerritoryGeometry::class)->context($data['territory_id'], $management));
return response()->json([
...app(TerritoryGeometry::class)->context($data['territory_id'], $internal),
'geometry_scope' => $internal ? 'authorized_internal' : 'public',
])->header('Cache-Control', 'private, no-store');
}
private const TABLES = ['opportunities' => 'opportunities', 'projects' => 'projects', 'clusters' => 'economic_clusters', 'corridors' => 'development_corridors', 'zones' => 'investment_zones'];
@@ -11,6 +11,36 @@ use Inertia\Inertia;
final class InvestorContextController extends Controller
{
private function entryComplements(Request $request): array
{
$data = $request->validate(['complement_origin' => 'nullable|string|max:100', 'complement_code' => 'required_with:complement_origin|string|max:40',
'complement_target' => 'nullable|string|max:100', 'complement_territory' => 'nullable|uuid']);
if (empty($data['complement_origin'])) return [];
return app(\App\Services\InvestmentComplements::class)->resolve([['origin' => $data['complement_origin'], 'code' => $data['complement_code'],
'target' => $data['complement_target'] ?? null, 'territory_id' => $data['complement_territory'] ?? null]]);
}
private function entryChoices(Request $r, InvestorContext $context): array
{
$data = $r->validate(['source' => 'nullable|string|max:100', 'from_dossier' => 'nullable|uuid', 'opportunities' => 'sometimes|array|max:100', 'opportunities.*' => 'integer|distinct|min:1',
'province_id' => 'nullable|uuid', 'district_id' => 'nullable|uuid', 'admin_post_id' => 'nullable|uuid', 'locality_id' => 'nullable|uuid']);
$source = !empty($data['source']) ? $context->reference($data['source']) : null;
$ids = $data['opportunities'] ?? (($source['kind'] ?? '') === 'opportunity' ? [$source['id']] : []);
abort_if(!empty($data['from_dossier']) && !$ids, 422, 'Escolha a oportunidade associada à ficha da carteira.');
$path = app(InvestmentGeography::class)->selection($data);
$input = array_map(fn($id) => ['source' => 'opportunity:'.$id, ...($path ? ['territory' => 'territory:'.$path[array_key_last($path)]->id] : [])], $ids);
if (!empty($data['from_dossier'])) $input[0]['portfolio_origins'] = [$data['from_dossier']];
foreach ($this->entryComplements($r) as $complement) {
$keys = array_filter([$complement['origin']['key'], $complement['target']['key'] ?? null], fn($key) => str_starts_with($key, 'opportunity:'));
foreach ($keys as $key) {
if (in_array($key, array_column($input, 'source'), true)) continue;
$input[] = ['source' => $key, ...($complement['territory_id'] ? ['territory' => 'territory:'.$complement['territory_id']] : []),
...(str_starts_with($complement['origin']['key'], 'portfolio:') ? ['portfolio_origins' => [substr($complement['origin']['key'], 10)]] : [])];
}
}
return app(\App\Services\InvestmentOpportunityChoices::class)->resolve($input, [], true);
}
public function current(Request $r, InvestorContext $context)
{
return response()->json($context->current($r->user()));
@@ -23,7 +53,8 @@ final class InvestorContextController extends Controller
public function show(Request $r, string $id, InvestorContext $context)
{
return response()->json($context->view($r->user(), $id));
$data = $r->validate(['opportunity' => 'nullable|string|max:100']);
return response()->json($context->view($r->user(), $id, $data['opportunity'] ?? null));
}
public function options(Request $r, InvestorContext $context)
@@ -33,12 +64,56 @@ final class InvestorContextController extends Controller
return response()->json($context->options($d['q'] ?? ''));
}
public function corridorOptions(Request $r)
{
$data = $r->validate(['corridor' => ['nullable', \Illuminate\Validation\Rule::in(array_keys(config('investment_corridors')))], 'territory' => 'nullable|uuid']);
$service = app(\App\Services\InvestmentCorridorContext::class);
return response()->json(['corridors' => collect(config('investment_corridors'))->map(fn($entry,$key)=>['key'=>$key,'name'=>$entry['name'],'provinces'=>$service->provinces($key)])->values(),
'parks' => $service->parks($data['corridor'] ?? null, $data['territory'] ?? null)]);
}
public function saveDraft(Request $r, string $id, InvestorContext $context)
{
return response()->json($context->saveDraft($r->user(), $id, $r->all()));
}
public function edit(Request $r, string $id, InvestorContext $context)
{
$data = $context->view($r->user(), $id);
abort_unless($data['can_write'], 403);
return Inertia::render('investor-path/context', ['initial' => $data, 'options' => $context->options(), 'source' => $r->query('source') ? $context->reference($r->validate(['source' => 'required|string|max:100'])['source']) : null, 'territorySelection' => isset($data['context']['selection']['territory']) ? app(InvestmentGeography::class)->path($data['context']['selection']['territory']['id']) : []]);
$entries = $this->entryChoices($r, $context);
$choices = $entries ?: null;
$source = $r->query('source') ? $context->reference($r->validate(['source' => 'required|string|max:100'])['source']) : null;
if ($choices === null && ($source['kind'] ?? '') === 'opportunity') $choices = app(\App\Services\InvestmentOpportunityChoices::class)->resolve([['source' => $source['key']]]);
$explicitChoices=$choices;
$selectionKey=$r->validate(['selection_key'=>'nullable|uuid'])['selection_key']??null;
$entryKey=fn($c)=>$c['opportunity']['key'].($selectionKey?'@'.$selectionKey:'');
$entrySources=array_map($entryKey,$explicitChoices??[]);
if ($choices !== null) $choices = app(\App\Services\InvestmentOpportunityChoices::class)->mergeEntries($data['context']['opportunity_choices'] ?? [], $choices);
$draft = $context->draft($r->user(), $id);
if ($draft && isset($draft['opportunity_choices'])) {
$recovered = app(\App\Services\InvestmentOpportunityChoices::class)->resolve($draft['opportunity_choices'], $data['context']['opportunity_choices'] ?? [], true);
$new=array_filter($explicitChoices??[],fn($c)=>!in_array($entryKey($c),$draft['entry_sources']??[],true));
$choices = app(\App\Services\InvestmentOpportunityChoices::class)->mergeEntries($recovered, array_values($new));
}
$differences = [];
foreach ($explicitChoices ?? [] as $entry) {
$kept = collect($choices ?? [])->firstWhere('opportunity.key', $entry['opportunity']['key']);
if ($kept && ($kept['territory']['key'] ?? null) !== ($entry['territory']['key'] ?? null)) $differences[] = ['title'=>$entry['opportunity']['title'],'saved'=>$kept['territory']['title']??'Por definir','requested'=>$entry['territory']['title']??'Por definir'];
}
$complements = isset($draft['complements']) ? app(\App\Services\InvestmentComplements::class)->resolve($draft['complements'], $data['context']['complements'] ?? []) : ($data['context']['complements'] ?? []);
$entryTerritory = null;
if (($source['kind'] ?? null) === 'portfolio') {
$path = app(InvestmentGeography::class)->selection($r->validate(['province_id' => 'nullable|uuid', 'district_id' => 'nullable|uuid', 'admin_post_id' => 'nullable|uuid', 'locality_id' => 'nullable|uuid']));
if ($path) $entryTerritory = $context->reference('territory:'.$path[array_key_last($path)]->id);
}
foreach ($this->entryComplements($r) as $entry) {
$tag = 'complement:'.hash('sha256', $entry['key'].'@'.($selectionKey ?? ''));
$entrySources[] = $tag;
if (!in_array($tag, $draft['entry_sources'] ?? [], true)) $complements = collect([...$complements, $entry])->unique('key')->values()->all();
}
return Inertia::render('investor-path/context', ['entryTerritory' => $entryTerritory, 'entryComplements' => $complements, 'entryLocationDifferences'=>$differences,'entrySources'=>$entrySources,'draft' => $draft, 'requestedChoices' => $choices, 'initial' => $data, 'options' => $context->options(), 'source' => $source, 'territorySelection' => isset($data['context']['selection']['territory']) ? app(InvestmentGeography::class)->path($data['context']['selection']['territory']['id']) : ($entryTerritory ? app(InvestmentGeography::class)->path($entryTerritory['id']) : [])]);
}
public function preview(Request $r, string $id, InvestorContext $context)
@@ -55,8 +130,16 @@ final class InvestorContextController extends Controller
{
$d = $r->validate(['source' => 'nullable|string|max:100', 'step' => ['nullable', 'regex:/^S(0[1-9]|1[0-9])$/']]);
$ref = isset($d['source']) ? $context->reference($d['source']) : null;
$submissionId = $r->validate(['submission' => 'nullable|uuid'])['submission'] ?? null;
$entrySubmission = null;
if ($submissionId) {
$submission = \App\Models\InvestmentSubmission::where('id', $submissionId)->where('user_id', $r->user()->id)->where('status', 'draft')->firstOrFail();
abort_unless(($ref['kind'] ?? null) === 'portfolio' && $submission->dossier_id === $ref['id'], 422, 'Conserve a ficha de origem da manifestação.');
$entrySubmission = ['id' => $submission->id, 'version' => $submission->version];
}
return Inertia::render('investor-path/context-start', ['contexts' => $path->contexts($r->user()), 'source' => $ref, 'step' => $d['step'] ?? null]);
$choices = $this->entryChoices($r, $context);
return Inertia::render('investor-path/context-start', ['entrySubmission' => $entrySubmission, 'entryComplements' => $this->entryComplements($r), 'entryQuery' => $r->only(['complement_origin', 'complement_code', 'complement_target', 'complement_territory', 'from_dossier', 'province_id', 'district_id', 'admin_post_id', 'locality_id']), 'opportunityChoices' => $choices, 'contexts' => $path->contexts($r->user()), 'source' => $ref, 'step' => $d['step'] ?? null]);
}
public function installation(Request $r, InvestorContextInstallation $install)
@@ -88,7 +88,8 @@ class InvestorPathController extends Controller
public function show(Request $request, string $id, InvestorPath $path): JsonResponse|Response
{
$data = $path->view($request->user(), $id);
$choice = $request->validate(['opportunity' => 'nullable|string|max:100'])['opportunity'] ?? null;
$data = $path->view($request->user(), $id, $choice);
return $request->expectsJson() ? response()->json($data) : Inertia::render('investor-path/show', $data);
}
@@ -103,6 +103,7 @@ class OpportunityManagementController extends Controller
$records = $query->orderByDesc('id')->paginate(20)->withQueryString();
$records->getCollection()->each(function (Opportunity $r) use ($access, $service, $request) {
$r->setAttribute('can_edit', $access->canEdit($request->user(), $r));
$r->setAttribute('can_promote', app(\App\Services\OpportunityPromotion::class)->allowed($request->user(), $r));
$r->setAttribute('working_status', $access->state($r));
$r->setAttribute('publication', $r->publicationPresentation());
$r->setAttribute('draft_title', $service->values($r)['canonical']['official_title'] ?? $r->title);
@@ -130,6 +131,7 @@ class OpportunityManagementController extends Controller
'profileReauthenticationRequired' => $record && $record->owner_user_id !== null
? app(OpportunityProfileWorkflow::class)->reauthenticationRequired($request->user(), $record) : false,
'publicationState' => $record?->publicationPresentation(),
'promotionHref' => $record && app(\App\Services\OpportunityPromotion::class)->allowed($request->user(), $record) ? '/minhas-oportunidades/'.$record->id.'/divulgacao' : null,
'canonicalResponse' => $record?->owner_user_id !== null ? app(OpportunityCanonicalResponse::class)->read($request->user(), $record) : null,
'canEditDraft' => $record ? $access->canEdit($request->user(), $record) : false,
'workflowParticipants' => $record && $record->owner_user_id !== null ? app(OpportunityProfileWorkflow::class)->participants($request->user(), $record) : ['validators' => [], 'publishers' => []],
@@ -0,0 +1,26 @@
<?php
namespace App\Http\Controllers;
use App\Models\Opportunity;
use App\Services\OpportunityPromotion;
use Illuminate\Http\Request;
use Inertia\Inertia;
final class OpportunityPromotionController extends Controller
{
public function show(Request $request, int $id, OpportunityPromotion $service): \Inertia\Response
{
return Inertia::render('management/opportunity-promotion', $service->editor($request->user(), Opportunity::findOrFail($id)));
}
public function preview(Request $request, int $id, OpportunityPromotion $service): \Illuminate\Http\JsonResponse
{
return response()->json($service->preview($request->user(), Opportunity::findOrFail($id), $request->all()));
}
public function confirm(Request $request, int $id, OpportunityPromotion $service): \Illuminate\Http\JsonResponse
{
return response()->json($service->confirm($request->user(), $id, $request->all()));
}
}
@@ -9,6 +9,7 @@ use App\Services\CountryCatalogue;
use App\Services\IdempotencyConflict;
use App\Services\InterestSubmission;
use App\Services\LegacyContent;
use App\Services\PortalProfileAccess;
use App\Services\Malware\MalwareScanner;
use App\Services\VerifiedDocumentBinary;
use App\Services\VirtualDesk;
@@ -274,7 +275,7 @@ class PortalServicesController extends Controller
'resource' => $resource,
'backUrl' => $backUrl,
'downloadUrl' => route('services.download', ['id' => $id]),
'articleUrl' => Schema::hasColumn('portal_resources','editorial_content') && DB::table('portal_resources')->where('id',$id)->whereNotNull('editorial_content')->exists() ? '/artigos/'.$id : null,
'articleUrl' => $this->articleUrl($id),
]);
}
@@ -297,6 +298,7 @@ class PortalServicesController extends Controller
public function manage(Request $request, MalwareScanner $scanner): Response
{
$managementFilters = $request->validate(['q' => 'nullable|string|max:150', 'state' => 'nullable|in:draft,published,withdrawn', 'intent' => 'nullable|in:document,legislation']);
$access = app(\App\Services\DocumentManagementAccess::class);
if (! $access->full($request->user())) {
$documents = $access->documents($request->user())->where('status', '!=', 'deleted');
@@ -304,7 +306,7 @@ class PortalServicesController extends Controller
$health['signatures_at'] = $health['signatures_at']?->format(DATE_ATOM);
$editorial = $access->editorial($request->user());
$resources = $editorial ? $access->editorialResources($request->user())->orderByDesc('r.updated_at')
$resources = $editorial ? $this->filterManagedResources($access->editorialResources($request->user()), $managementFilters)->orderByDesc('r.updated_at')
->get(['r.*', 'd.file_name', 'd.media_type', 'd.size_bytes', 'd.issuer', 'd.status as file_status', 'd.data_classification', 'd.version_no as file_version', 'd.rights_status as file_rights_status', 'd.malware_scan_status', 'd.malware_failure_reason']) : collect();
$links = DB::table('portal_resource_links')->whereIn('resource_id', $resources->pluck('id'))->orderBy('id')->get()->groupBy('resource_id');
$revisions = DB::table('portal_resource_revisions')->whereIn('resource_id', $resources->pluck('id'))->orderByDesc('revision_no')->get(['resource_id', 'revision_no', 'change_type', 'actor_user_id', 'created_at'])->groupBy('resource_id');
@@ -313,6 +315,7 @@ class PortalServicesController extends Controller
$resource->revisions = $revisions->get($resource->id, collect())->values();
});
return Inertia::render('portal/manage', [
'managementFilters' => $managementFilters, 'associationOptions' => $this->contentAssociations($request),
'documentAccessOnly' => ! $editorial, 'editorialScopeOnly' => $editorial, 'resources' => $resources, 'partnerships' => [], 'territories' => [],
'requirementCatalogue' => [], 'requirementAssociationsEnabled' => false,
'disclosureAuthorization' => null, 'incompleteCount' => $resources->filter(fn ($r) => ! $r->description || ! $r->issuer || ! $r->source_url || $r->source_confirmation === 'unconfirmed' || $r->legal_status === 'unknown' || $r->rights_status === 'unconfirmed')->count(), 'possibleDuplicates' => $resources->whereNotNull('duplicate_of_resource_id')->count(),
@@ -331,7 +334,7 @@ class PortalServicesController extends Controller
->where('external_id', 'document-repository-disclosure-authorization-2026-10-06-v1')
->where('action', 'public_disclosure_authorized')->first(['external_id', 'occurred_at', 'after_data']);
$disclosureAuthorizationData = $disclosureAuthorization ? json_decode($disclosureAuthorization->after_data, true) : null;
$resources = DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->orderByDesc('r.updated_at')->limit(200)
$resources = $this->filterManagedResources(DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->whereNull('d.deleted_at'), $managementFilters)->orderByDesc('r.updated_at')->limit(200)
->get(['r.*', 'd.file_name', 'd.media_type', 'd.size_bytes', 'd.issuer', 'd.status as file_status', 'd.data_classification', 'd.version_no as file_version', 'd.rights_status as file_rights_status', 'd.malware_scan_status', 'd.malware_failure_reason']);
$links = DB::table('portal_resource_links')->whereIn('resource_id', $resources->pluck('id'))->orderBy('id')->get()->groupBy('resource_id');
$resources->each(fn ($resource) => $resource->links = $links->get($resource->id, collect())->values());
@@ -342,6 +345,7 @@ class PortalServicesController extends Controller
$malwareHealth['signatures_at'] = $malwareHealth['signatures_at']?->format(DATE_ATOM);
return Inertia::render('portal/manage', ['resources' => $resources,
'managementFilters' => $managementFilters, 'associationOptions' => $this->contentAssociations($request),
'requirementCatalogue' => $this->requirementEvidenceEnabled()
? collect(is_array($catalogue = config('document-requirements.catalogue', [])) ? $catalogue : [])->map(fn ($item, $key) => ['key' => $key, ...$item])->values()
: collect(),
@@ -367,6 +371,39 @@ class PortalServicesController extends Controller
'possibleDuplicates' => DB::table('portal_resources')->whereNotNull('duplicate_of_resource_id')->count()]);
}
private function filterManagedResources(Builder $query, array $filters): Builder
{
if (! empty($filters['q'])) {
$term = '%'.addcslashes($filters['q'], '%_\\').'%';
$query->where(fn ($q) => $q->where('r.title', 'ilike', $term)->orWhere('r.document_number', 'ilike', $term)->orWhere('d.issuer', 'ilike', $term)->orWhere('d.file_name', 'ilike', $term));
}
if (! empty($filters['state'])) {
$query->where('r.published', $filters['state'] === 'published');
if ($filters['state'] !== 'published') {
$method = $filters['state'] === 'withdrawn' ? 'whereExists' : 'whereNotExists';
$query->$method(fn ($q) => $q->selectRaw('1')->from('portal_resource_revisions as history')->whereColumn('history.resource_id', 'r.id')->whereIn('history.change_type', ['unpublished', 'withdrawn']));
}
}
return $query;
}
private function contentAssociations(Request $request): array
{
$access = app(\App\Services\DocumentManagementAccess::class);
$resources = $access->full($request->user()) ? DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->whereNull('d.deleted_at')
: ($access->editorial($request->user()) ? $access->editorialResources($request->user()) : null);
$documents = $resources ? $resources->orderBy('r.title')->get(['r.id as value', 'r.title as label', 'r.document_type']) : collect();
return [
'sector' => \App\Models\Sector::choices()->orderBy('name')->get(['id as value', 'name as label']),
'territory' => app(\App\Services\InvestmentGeography::class)->publicReferences()->orderBy('name')->get(['id as value', 'name as label']),
'opportunity' => app(PortalProfileAccess::class)->scope(\App\Models\Opportunity::query(), $request->user())->orderBy('title')->get(['id as value', 'title as label']),
'document' => $documents,
'procedure' => $documents->where('document_type', 'procedure')->values(),
'stage' => collect(config('virtual-desk.steps', []))->map(fn ($step, $key) => ['value' => $key, 'label' => $step['title']])->values(),
'activity' => app(\App\Services\EconomicReferenceCatalog::class)->activities()->map(fn ($row) => ['value' => $row->id, 'label' => $row->display_label])->values(),
];
}
public function upload(Request $request): RedirectResponse
{
$this->validateManagement($request, ['file' => ['required', 'file', 'mimetypes:application/pdf,text/plain,text/csv,image/jpeg,image/png,image/webp,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.text'.(app(LegacyContent::class)->available() ? ',application/json' : ''), 'max:10240'],
@@ -399,7 +436,7 @@ class PortalServicesController extends Controller
ScanDocumentForMalware::dispatch($id)->afterCommit();
return to_route('services.manage')->with('success', 'Documento recebido em armazenamento privado e quarentena. Não aparece na biblioteca pública até validação e publicação explícitas.');
return to_route('services.manage', array_filter(['intent' => in_array($request->input('intent'), ['document', 'legislation'], true) ? $request->input('intent') : null]))->with('uploaded_document_id', $id)->with('success', 'Documento recebido em armazenamento privado e quarentena. Não aparece na biblioteca pública até validação e publicação explícitas.');
}
public function resource(Request $request): RedirectResponse
@@ -663,7 +700,7 @@ class PortalServicesController extends Controller
'data_classification' => ['nullable', 'in:internal,public'],
'source_reference' => ['required', 'string', 'min:10', 'max:2000'],
'legislation' => ['required', 'boolean'], 'essential' => ['required', 'boolean'],
'associations' => ['nullable', 'array', 'max:40'], 'associations.*.target_type' => ['required', 'in:theme,module,activity,stage,procedure,entity,territory,document,investment_type,legal_source'.($this->requirementEvidenceEnabled() ? ',requirement' : '')],
'associations' => ['nullable', 'array', 'max:40'], 'associations.*.target_type' => ['required', 'in:theme,module,activity,stage,procedure,entity,territory,document,investment_type,legal_source,sector,opportunity'.($this->requirementEvidenceEnabled() ? ',requirement' : '')],
'associations.*.target_key' => ['required', 'string', 'max:180'],
'associations.*.review_status' => ['nullable', 'in:pending,confirmed'],
'associations.*.relationship' => ['required', 'in:applies_to,supports,version_of,translation_of,amends,repeals,implements,cites,related_to'],
@@ -829,4 +866,17 @@ SQL, [$id]);
return $ids ?: [$id];
}
private function articleUrl(int $id): ?string
{
if (!Schema::hasColumn('portal_resources', 'editorial_content')) return null;
$resource = DB::table('portal_resources')->find($id);
if (!$resource) return null;
if ($resource->editorial_content !== null) return '/artigos/'.$id;
try {
return app(\App\Services\EditorialReading::class)->original($resource) ? '/artigos/'.$resource->id : null;
} catch (\Symfony\Component\HttpKernel\Exception\HttpException) {
return null;
}
}
}
@@ -0,0 +1,138 @@
<?php
namespace App\Http\Controllers;
use App\Services\Procurement;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
class ProcurementController extends Controller
{
private const STATE_SQL = "CASE WHEN v.payload->>'procedural_state' IN ('cancelled','results') THEN v.payload->>'procedural_state' WHEN ((v.payload->>'deadline')::timestamp AT TIME ZONE (v.payload->>'timezone'))<=CURRENT_TIMESTAMP THEN 'deadline_ended' WHEN v.payload->>'extended'='true' THEN 'extended' ELSE 'open' END";
private function query(Procurement $service)
{
abort_unless($service->available(), 404);
return DB::table('portal_tenders as t')->join('portal_tender_versions as v', fn ($q) => $q->on('v.id', '=', 't.published_version_id')->on('v.tender_id', '=', 't.id'))->whereNotNull('v.published_at');
}
public function index(Request $request, Procurement $service)
{
$filters = $request->validate(['q' => 'nullable|string|max:150', 'entity' => 'nullable|uuid', 'sector' => 'nullable|integer', 'territory' => 'nullable|uuid', 'modality' => 'nullable|string|max:200', 'financier' => 'nullable|string|max:200', 'state' => 'nullable|in:open,extended,deadline_ended,cancelled,results', 'deadline_before' => 'nullable|date_format:Y-m-d', 'regime' => 'nullable|in:state,external,private,other']);
$filters = array_filter($filters, fn ($value) => $value !== null && $value !== '');
$query = $this->query($service);
if (! empty($filters['q'])) {
$query->where(fn ($q) => $q->whereRaw("v.payload->>'title' ILIKE ?", ['%'.$filters['q'].'%'])->orWhereRaw("v.payload->>'object' ILIKE ?", ['%'.$filters['q'].'%'])->orWhereRaw("v.payload->>'reference' ILIKE ?", ['%'.$filters['q'].'%']));
}
foreach (['entity' => 'organization_id', 'sector' => 'sector_id', 'modality' => 'modality', 'financier' => 'financier', 'regime' => 'regime'] as $filter => $field) {
if (! empty($filters[$filter])) {
$query->whereRaw('v.payload->>? = ?', [$field, (string) $filters[$filter]]);
}
}
if (! empty($filters['territory'])) {
$query->whereRaw("v.payload->>'territory_id' IN (WITH RECURSIVE scope(id,depth) AS (SELECT id,0 FROM geo_locations WHERE id=? AND deleted_at IS NULL UNION ALL SELECT c.id,s.depth+1 FROM geo_locations c JOIN scope s ON c.parent_id=s.id WHERE c.deleted_at IS NULL AND s.depth<4) SELECT id::text FROM scope)", [$filters['territory']]);
}
if (! empty($filters['state'])) {
$query->whereRaw(self::STATE_SQL.' = ?', [$filters['state']]);
}
if (! empty($filters['deadline_before'])) {
$query->whereRaw("left(v.payload->>'deadline',10)<=?", [$filters['deadline_before']]);
}
$rows = $query->select('t.id', 'v.id as vid')->orderByDesc('v.published_at')->paginate(20)->withQueryString();
$rows->through(fn ($r) => ['id' => $r->id, ...$this->summary($service, $r->vid)]);
$facets = $this->query($service)->get(['v.payload'])->map(fn ($r) => json_decode($r->payload, true));
$options = [];
foreach (['entity' => ['organization_id', 'organization_name'], 'sector' => ['sector_id', 'sector_name'], 'territory' => ['territory_id', 'territory_name'], 'modality' => ['modality', 'modality'], 'financier' => ['financier', 'financier']] as $name => [$value,$label]) {
$options[$name] = $facets->filter(fn ($p) => ! empty($p[$value]))->map(fn ($p) => ['id' => (string) $p[$value], 'name' => $p[$label]])->unique('id')->values();
}
return Inertia::render('procurement/index', ['items' => $rows, 'filters' => $filters, 'options' => $options, 'regimes' => config('procurement.regimes'), 'management' => $service->access($request->user())])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
private function summary(Procurement $service, string $vid): array
{
$v = $service->publishedVersion($vid);
return ['publication' => $v, 'state' => $service->state($v)];
}
public function show(Request $request, string $id, Procurement $service)
{
return $this->detail($request, $id, $service, false);
}
public function print(Request $request, string $id, Procurement $service)
{
return $this->detail($request, $id, $service, true);
}
private function detail(Request $request, string $id, Procurement $service, bool $print)
{
$row = $this->query($service)->where('t.id', $id)->firstOrFail(['t.id', 'v.id as vid']);
$filters = $request->only(['q', 'entity', 'sector', 'territory', 'modality', 'financier', 'state', 'deadline_before', 'regime', 'page']);
return Inertia::render('procurement/show', ['id' => $id, ...$this->summary($service, $row->vid), 'printMode' => $print, 'backUrl' => '/concursos'.($filters ? '?'.http_build_query($filters) : ''),
'history' => DB::table('portal_tender_versions')->where('tender_id', $id)->whereNotNull('published_at')->orderBy('version')->pluck('id')->map(fn ($vid) => $service->publishedVersion($vid)),
'watching' => $request->user() && DB::table('portal_tender_watches')->where('tender_id', $id)->where('user_id', $request->user()->id)->exists()])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
public function manage(Request $request, Procurement $service)
{
$service->guard($request->user());
return Inertia::render('procurement/manage', ['items' => DB::table('portal_tenders')->orderByDesc('updated_at')->get(['id', 'draft', 'version', 'published_version_id'])->map(fn ($r) => ['id' => $r->id, 'title' => json_decode($r->draft, true)['title'] ?? 'Rascunho sem título', 'version' => $r->version, 'published' => (bool) $r->published_version_id])])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
public function edit(Request $request, Procurement $service, ?string $id = null)
{
$service->guard($request->user());
$r = $id ? $service->record($id) : null;
return Inertia::render('procurement/edit', ['record' => $r ? ['id' => $id, 'version' => $r->version, 'draft' => json_decode($r->draft, true), 'published' => (bool) $r->published_version_id] : null,
'references' => $service->references($request->user()), 'history' => $id ? DB::table('portal_tender_versions')->where('tender_id', $id)->orderByDesc('version')->get(['version', 'act', 'reason', 'actor_id', 'published_at', 'created_at']) : []])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
public function save(Request $request, Procurement $service, ?string $id = null)
{
$id = $service->save($request->user(), $id, $request->all());
return redirect('/management/concursos/'.$id)->with('success', 'Rascunho guardado. A publicação anterior permanece intacta.');
}
public function preview(Request $request, string $id, Procurement $service)
{
return response()->json($service->preview($request->user(), $id, (string) $request->input('act')))->header('Cache-Control', 'private, no-store');
}
public function publish(Request $request, string $id, Procurement $service)
{
$service->publish($request->user(), $id, $request->all());
return redirect('/management/concursos/'.$id)->with('success', 'Acto publicado, com versão e auditoria. Nenhuma proposta recebida pelo portal.');
}
public function watch(Request $request, string $id, Procurement $service)
{
$row = $this->query($service)->where('t.id', $id)->firstOrFail(['v.id']);
DB::table('portal_tender_watches')->updateOrInsert(['tender_id' => $id, 'user_id' => $request->user()->id], ['seen_version_id' => $row->id, 'created_at' => now(), 'updated_at' => now()]);
return back()->with('success', 'Concurso guardado para acompanhamento. Isto não apresenta uma proposta.');
}
public function unwatch(Request $request, string $id, Procurement $service)
{
abort_unless($service->available(), 404);
DB::table('portal_tender_watches')->where('tender_id', $id)->where('user_id', $request->user()->id)->delete();
return back();
}
public function watched(Request $request, Procurement $service)
{
$rows = $this->query($service)->join('portal_tender_watches as w', 'w.tender_id', '=', 't.id')->where('w.user_id', $request->user()->id)->get(['t.id', 'v.id as vid', 'w.seen_version_id'])->map(fn ($r) => ['id' => $r->id, 'changed' => $r->seen_version_id !== $r->vid, ...$this->summary($service, $r->vid)]);
return Inertia::render('procurement/manage', ['watched' => true, 'items' => $rows])->toResponse($request)->header('Cache-Control', 'private, no-store');
}
}
@@ -11,8 +11,13 @@ class PublicGeographyController extends Controller
{
public function options(Request $request, InvestmentGeography $geography): JsonResponse
{
$data = $request->validate(['type' => ['required', 'in:province,district,admin_post,locality'], 'id' => ['nullable', 'uuid'], 'parent_id' => ['nullable', 'uuid'], 'q' => ['nullable', 'string', 'max:100'], 'page' => ['nullable', 'integer', 'min:1']]);
$data = $request->validate(['corridor' => ['nullable', \Illuminate\Validation\Rule::in(array_keys(config('investment_corridors')))], 'type' => ['required', 'in:province,district,admin_post,locality'], 'id' => ['nullable', 'uuid'], 'parent_id' => ['nullable', 'uuid'], 'q' => ['nullable', 'string', 'max:100'], 'page' => ['nullable', 'integer', 'min:1']]);
$query = $geography->publicReferences()->where('location_type', $data['type']);
if (!empty($data['corridor'])) {
$corridors = app(\App\Services\InvestmentCorridorContext::class);
if ($data['type'] === 'province') $query->whereIn('id', array_column($corridors->provinces($data['corridor']), 'id'));
elseif (!$corridors->compatible($data['corridor'], $data['parent_id'] ?? null)) abort(422, 'O território não pertence ao corredor escolhido.');
}
if (! empty($data['id'])) {
$query->where('id', $data['id']);
}
@@ -29,6 +34,6 @@ class PublicGeographyController extends Controller
->orWhereRaw('source_code ILIKE ?', [$term]));
}
return response()->json($query->orderBy('name')->orderBy('id')->paginate(100, ['id', 'name', 'parent_id', 'location_type', 'source_code']));
return response()->json($query->orderBy('name')->orderBy('id')->paginate(100, ['id', 'name', 'parent_id', 'location_type', 'source_code'])->withQueryString());
}
}
@@ -119,8 +119,8 @@ class VirtualDeskController extends Controller
public function createRequest(Request $request, string $id, VirtualDesk $desk): JsonResponse|RedirectResponse
{
$data = $request->validate(['service_version_id' => 'required|uuid', 'client_key' => 'required|uuid']);
$row = $desk->createRequest($request->user(), $id, $data['service_version_id'], $data['client_key']);
$data = $request->validate(['service_version_id' => 'required|uuid', 'client_key' => 'required|uuid', 'opportunity' => 'nullable|string|max:100']);
$row = $desk->createRequest($request->user(), $id, $data['service_version_id'], $data['client_key'], $data['opportunity'] ?? null);
return $request->expectsJson() ? response()->json(['id' => $row->id, 'version' => $row->version], 201) : redirect('/balcao-virtual/pedidos/'.$row->id);
}
@@ -14,7 +14,7 @@ class EnsureScopedEditorial
return $next($request);
}
abort_unless($access->editorial($actor), 403);
$allowed = in_array($request->route()->getName(), ['editorial.edit', 'editorial.save', 'services.resource', 'services.resource.update'], true)
$allowed = in_array($request->route()->getName(), ['editorial.edit', 'editorial.save', 'editorial.preview', 'editorial.preview-content', 'services.resource', 'services.resource.update'], true)
|| ($request->route()->getName() === 'services.moderate' && $request->route('type') === 'resources');
abort_unless($allowed, 403);
if ($request->route('id') !== null) {
@@ -14,12 +14,14 @@ final class EnsureScopedPortalAdministration
public function handle(Request $request, Closure $next): Response
{
$actor = $request->user();
abort_unless($actor, 403);
abort_unless($actor !== null, 403);
$scope = app(ScopedPortalAdministration::class);
$path = $request->path();
$interests = $request->is('management/interests', 'management/interests/*', 'api/v1/investment/admin/interests/*');
// Fiscal maintenance reuses authorised administration; unrelated gates remain unchanged.
$catalogue = $request->is('management/economic-references/lot-01', 'management/economic-references/lot-01/*',
$geometryRead = $request->isMethod('GET') && $path === 'management/territory-geometries';
$catalogue = $geometryRead || $request->is('management/territory-geometry-import', 'management/territory-geometry-import/*',
'management/economic-references/lot-01', 'management/economic-references/lot-01/*',
'management/education', 'management/education/*', 'management/investment/references', 'management/investment/references/*', 'api/v1/investment/admin/references', 'api/v1/investment/admin/references/*',
'management/investment/zones', 'management/investment/zones/*', 'api/v2/investment/admin/zones', 'api/v2/investment/admin/zones/*',
'management/balcao/atribuicoes', 'management/balcao/atribuicoes/*', 'management/balcao/servicos',
@@ -53,7 +53,7 @@ final class EnsureSimulationRecoveryCookie
}
}
return $response->withCookie(cookie(
$response->headers->setCookie(cookie(
self::NAME,
$forget ? '' : $token,
$minutes,
@@ -64,6 +64,7 @@ final class EnsureSimulationRecoveryCookie
false,
'lax',
));
return $response;
}
private function isExplicitDraftActivity(Request $request, Response $response): bool
@@ -51,8 +51,10 @@ class HandleInertiaRequests extends Middleware
return [
...parent::share($request),
'name' => config('app.name'),
'procurementEnabled' => app(\App\Services\Procurement::class)->available(),
'homologationReserved' => (bool) config('portal.homologation_only', false),
'profileAccess' => app(PortalProfileAccess::class)->navigation($request->user()),
'contentManagementHref' => app(\App\Services\ContentManagement::class)->access($request->user()) !== [] ? '/gestao-conteudos' : null,
'portalOperator' => config('portal.operator_name'),
'portalInstitutionalContactEmail' => filter_var(config('portal.institutional_contact_email'), FILTER_VALIDATE_EMAIL) ?: null,
'legacyContentEnabled' => app(LegacyContent::class)->available(),
@@ -68,7 +70,7 @@ class HandleInertiaRequests extends Middleware
'create' => ['label' => 'Nova oportunidade', 'href' => '/management/opportunities/create'],
'installationHref' => '/management/opportunity-management-install',
] : null,
'flash' => ['success' => fn () => $request->session()->get('success'), 'warning' => fn () => $request->session()->get('warning')],
'flash' => ['success' => fn () => $request->session()->get('success'), 'warning' => fn () => $request->session()->get('warning'), 'uploaded_document_id' => fn () => $request->session()->get('uploaded_document_id')],
'scopedAdministration' => $request->user() && app(\App\Services\ScopedPortalAdministration::class)->administrative($request->user()) ? [
['label'=>'Zonas e parques','href'=>'/management/investment/zones'],
['label'=>'Referências económicas','href'=>'/management/economic-references/lot-01'],
@@ -29,7 +29,9 @@ class ProtectProfileOpportunity
if ($record && ($record->owner_user_id !== null || str_starts_with($request->path(), 'minhas-oportunidades'))) {
abort_if($record->owner_user_id === null && str_starts_with($request->path(), 'minhas-oportunidades'), 403, 'Registo legado não convertido para a política v1.');
$access = app(PortalProfileAccess::class);
$access->authorize($request->user(), $request->isMethod('GET') || str_ends_with($request->path(), '/workflow') || str_ends_with($request->path(), '/preview') || $request->is('minhas-oportunidades/*/classification/review') ? 'view' : 'edit', $record);
// The promotional controller checks its own scoped disclosure capability,
// like workflow decisions; publication does not grant draft editing.
$access->authorize($request->user(), $request->isMethod('GET') || str_ends_with($request->path(), '/workflow') || str_ends_with($request->path(), '/preview') || $request->is('minhas-oportunidades/*/classification/review', 'minhas-oportunidades/*/divulgacao/previa', 'minhas-oportunidades/*/divulgacao/confirmar') ? 'view' : 'edit', $record);
abort_if($request->is('management/opportunity-origin/apply'), 403, 'O cadastro privado v1 não usa a classificação editorial dos exemplos legados.');
abort_if($request->isMethod('POST') && str_ends_with($request->path(), '/lifecycle') && ! str_contains($request->path(), '/resources/'), 403, 'Use o workflow com decisões segregadas; o perfil não concede exclusão.');
}
@@ -19,7 +19,9 @@ class StoreLandAssistanceCaseRequest extends FormRequest
{
$payload = $this->validated('payload');
return is_array($payload) ? $payload : [];
if (!is_array($payload)) return [];
if (!empty($payload['investor_path_case_id'])) return app(\App\Services\InvestmentConsumerScope::class)->bind($this->user(), $payload['investor_path_case_id'], $payload, $this->routeIs('land-assistance.support'));
return \Illuminate\Support\Arr::except($payload, ['context_opportunity', 'context_opportunity_snapshot']);
}
public function authorize(): bool
@@ -33,7 +35,9 @@ class StoreLandAssistanceCaseRequest extends FormRequest
return [
'version' => [$this->isMethod('post') && ! $this->routeIs('land-assistance.support') ? 'nullable' : 'required', 'integer', 'min:1'],
'context_revision' => ['nullable', 'integer', 'min:0'], 'context_reviewed' => ['nullable', 'boolean'],
'payload' => ['required', 'array:context_reuse,support_kind,request_description,project_reference,investor_path_case_id,applicant_category,full_name,contact_person,email,phone,preferred_contact,country,declared_origin_country_code,nationality,representative_name,representative_role,representation_basis,nuit,constitution_or_residency_note,area_status,parcels,purpose,activity,known_occupants,occupant_description,known_improvements,improvements_description,prior_right_status,prior_right_description,conflict_status,conflict_description,official_process,attachments_to_follow,exploration_plan,consultation,additional_information,truth_declaration,contact_consent'],
'payload' => ['required', 'array:context_opportunity,context_opportunity_snapshot,context_reuse,support_kind,request_description,project_reference,investor_path_case_id,applicant_category,full_name,contact_person,email,phone,preferred_contact,country,declared_origin_country_code,nationality,representative_name,representative_role,representation_basis,nuit,constitution_or_residency_note,area_status,parcels,purpose,activity,known_occupants,occupant_description,known_improvements,improvements_description,prior_right_status,prior_right_description,conflict_status,conflict_description,official_process,attachments_to_follow,exploration_plan,consultation,additional_information,truth_declaration,contact_consent'],
'payload.context_opportunity' => ['nullable', 'string', 'max:100'],
'payload.context_opportunity_snapshot' => ['nullable', 'string', 'max:200000'],
'payload.context_reuse' => ['nullable', 'string', 'max:10000'],
'payload.support_kind' => ['nullable', 'in:investment,home,family_exploitation,recognition,regularization,delimitation,change_of_use,transfer,existing_process,conflict_guidance,other'],
'payload.request_description' => ['nullable', 'string', 'max:4000'],
@@ -37,7 +37,7 @@ class StoreSimulationFormDraftRequest extends FormRequest
'contact_province', 'contact_district', 'preferred_channel',
];
$economic = [
'context_applicability_snapshot', 'investment_regime', 'context_reuse', 'compatible_fields_snapshot', 'published_iva_base', 'published_iva_currency', 'published_iva_date', 'published_iva_scope', 'monthly_iva_settings', 'monthly_iva_snapshot', 'journey_type', 'detail_level', 'business_plan_snapshot', 'financial_tools_snapshot', 'cashflow_snapshot', 'project_team_snapshot', 'project_execution_snapshot', 'purpose', 'manifestation_type', 'preferred_language', 'project_title', 'project_summary', 'project_problem', 'target_customers', 'value_proposition', 'market_assumption', 'market_source', 'project_milestones', 'selection_labels', 'project_type',
'context_opportunity', 'context_applicability_snapshot', 'investment_regime', 'context_reuse', 'compatible_fields_snapshot', 'published_iva_base', 'published_iva_currency', 'published_iva_date', 'published_iva_scope', 'monthly_iva_settings', 'monthly_iva_snapshot', 'modelo_a_snapshot', 'journey_type', 'detail_level', 'business_plan_snapshot', 'financial_tools_snapshot', 'cashflow_snapshot', 'project_team_snapshot', 'project_execution_snapshot', 'purpose', 'manifestation_type', 'preferred_language', 'project_title', 'project_summary', 'project_problem', 'target_customers', 'value_proposition', 'market_assumption', 'market_source', 'project_milestones', 'selection_labels', 'project_type',
'competitor_assumption', 'sales_channel_assumption', 'marketing_approach', 'location_rationale', 'project_risk_responses_snapshot', 'project_questionnaire_version',
'customer_validation_status', 'cost_estimate_status', 'location_assessment_status', 'funding_status', 'receivables_timing_status',
'project_type_other', 'sector_id', 'activity_id', 'products_services', 'maturity_stage', 'expected_start_date',
@@ -72,7 +72,8 @@ class StoreSimulationFormDraftRequest extends FormRequest
'economic_snapshot.business_plan_snapshot' => ['nullable', 'string', 'max:60000'],
'economic_snapshot.financial_tools_snapshot' => ['nullable', 'string', 'max:30000'],
'economic_snapshot.cashflow_snapshot' => ['nullable', 'string', 'max:20000'],
'economic_snapshot.context_applicability_snapshot' => ['nullable', 'string', 'max:20000'],
'economic_snapshot.context_applicability_snapshot' => ['nullable', 'string', 'max:1000000'],
'economic_snapshot.context_opportunity' => ['nullable', 'string', 'max:100'],
'economic_snapshot.investment_regime' => ['nullable', 'in:general,industrial_park,zee,zfi'],
'economic_snapshot.context_reuse' => ['nullable', 'string', 'max:10000'],
'economic_snapshot.compatible_fields_snapshot' => ['nullable', 'string', 'max:10000'],
@@ -82,6 +83,9 @@ class StoreSimulationFormDraftRequest extends FormRequest
'economic_snapshot.published_iva_scope' => ['nullable', 'string', 'in:yes,no'],
'economic_snapshot.monthly_iva_settings' => ['nullable', 'string', 'max:2000'],
'economic_snapshot.monthly_iva_snapshot' => ['nullable', 'string', 'max:60000'],
// Preserve accepted books and explicit history through the L3 refund increment.
// This is a bounded transport choice, not a business limit on fiscal records.
'economic_snapshot.modelo_a_snapshot' => ['nullable', 'string', 'json', 'max:6000000'],
'economic_snapshot.project_team_snapshot' => ['nullable', 'string', 'max:30000'],
'economic_snapshot.project_execution_snapshot' => ['nullable', 'string', 'max:30000'],
'economic_snapshot.project_risk_responses_snapshot' => ['nullable', 'string', 'max:30000'],
+9 -1
View File
@@ -31,6 +31,13 @@ class Opportunity extends Model
protected $appends = ['maturity_catalogue_version'];
public function toArray(): array
{
$data = parent::toArray();
if (isset($data['description'])) $data['description'] = \App\Services\OpportunityPublicText::description($this, $data['description']);
return $data;
}
public function getMaturityCatalogueVersionAttribute(): ?string
{
// Only published metadata is public; never expose the current private draft.
@@ -68,7 +75,8 @@ class Opportunity extends Model
$scope = $public ? 'public' : ($visible && $this->owner_user_id !== null ? 'restricted' : 'unpublished');
return ['scope' => $scope, 'public_catalog' => $public, 'label' => match ($scope) {
'public' => 'Publicada no catálogo público',
'public' => data_get($this->workflow_context, 'publication.purpose') === 'promotional_preparation'
? 'Resumo divulgado — Em preparação; não autoriza execução' : 'Publicada no catálogo público',
'restricted' => 'Disponibilizada com acesso restrito — perfis e organização autorizados',
default => 'Sem versão disponibilizada; aprovação interna é uma etapa distinta',
}];
@@ -0,0 +1,42 @@
<?php
namespace App\Services;
use RuntimeException;
/** Public read projection authorized by Tempo; source rows and originals stay private. */
class ApprovedAdministrativeBoundaries
{
public const HASH = '06ab905fcf9b19115c3521bf81de03f37873880f7765f229b9e1f79d99df7adc';
/** @var array<string,array<string,string>>|null */
private ?array $items = null;
/** @return array<string,array<string,string>> */
public function snapshots(): array
{
if ($this->items !== null) {
return $this->items;
}
$contents = file_get_contents(base_path('docs/investmoz/unification/approved-administrative-boundaries-20261024.json'));
if ($contents === false || ! hash_equals(self::HASH, hash('sha256', str_replace("\r\n", "\n", $contents)))) {
throw new RuntimeException('Approved administrative boundary manifest changed.');
}
$manifest = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);
if (count($manifest['items']) !== 408) {
throw new RuntimeException('Exact 408-boundary scope required.');
}
$this->items = array_column($manifest['items'], null, 'id');
return $this->items;
}
public function allows(string $id, string $territoryId, string $geometryHash, string $propertiesHash): bool
{
$item = $this->snapshots()[$id] ?? null;
return $item !== null && $item['territory_id'] === $territoryId
&& hash_equals($item['geometry_sha256'], $geometryHash)
&& hash_equals($item['properties_sha256'], $propertiesHash);
}
}
+106
View File
@@ -0,0 +1,106 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use RuntimeException;
/** Exact replay of the 28 accepted links into the transported project identities. */
final class ApprovedAnchorTerritories
{
public const HASH = 'd2893d0a638d630435aca1890f79a8094dc58eb65bbdd65a470bb685fa075190';
/** @return array{manifest_sha256:string,projects:list<array<string,mixed>>,links:list<array<string,mixed>>} */
public function plan(): array
{
$file = base_path('docs/investmoz/unification/approved-anchor-territories-20261023.json');
$contents = is_file($file) ? file_get_contents($file) : false;
if ($contents !== false) {
$contents = str_replace("\r\n", "\n", $contents);
}
if ($contents === false || ! hash_equals(self::HASH, hash('sha256', $contents))) {
throw new RuntimeException('Reviewed territorial manifest changed.');
}
$manifest = json_decode($contents, true, 512, JSON_THROW_ON_ERROR);
if (count($manifest['items']) !== 28) {
throw new RuntimeException('Exact 28-link scope required.');
}
$projects = [];
$links = [];
foreach ($manifest['items'] as $item) {
$project = DB::table('projects')->where('id', $item['project_id'])->whereNull('deleted_at')->first();
$dossier = DB::table('investment_dossiers')->where('id', $item['dossier_id'])->whereNull('deleted_at')->first();
if (! $project || $project->code !== $item['code'] || ! $dossier || $dossier->project_id !== $project->id
|| ! hash_equals($item['content_sha256'], hash('sha256', $dossier->content))
|| ! hash_equals($item['source_sha256'], hash('sha256', $dossier->source))) {
throw new RuntimeException('Project identity or documentary source changed: '.$item['code']);
}
$original = $item['original_relation'];
$geo = DB::table('geo_locations')->where('id', $original['geo_location_id'])->whereNull('deleted_at')->first();
foreach (['location_type', 'source_code', 'parent_id', 'data_classification'] as $field) {
if (! $geo || $item['territory'][$field] !== $geo->$field) {
throw new RuntimeException('Territory identity changed: '.$original['geo_location_id']);
}
}
$metadata = $projects[$project->id]['after_metadata'] ?? json_decode($project->metadata, true, 512, JSON_THROW_ON_ERROR);
$key = $geo->id.':'.$original['role'];
$evidence = $item['evidence'];
// Preserve the original dossier id in evidence and explicitly map the destination.
$evidence['transported_dossier_id'] = $dossier->id;
if (isset($metadata['documented_location_sources'][$key]) && $metadata['documented_location_sources'][$key] != $evidence) {
throw new RuntimeException('Existing territorial evidence differs; no overwrite: '.$item['code']);
}
$projects[$project->id] ??= ['id' => $project->id, 'code' => $project->code, 'before_version' => (int) $project->version_no, 'before_metadata' => json_decode($project->metadata, true, 512, JSON_THROW_ON_ERROR)];
$metadata['documented_location_sources'][$key] = $evidence;
$projects[$project->id]['after_metadata'] = $metadata;
$existing = DB::table('project_locations')->where('project_id', $project->id)->where('geo_location_id', $geo->id)->where('role', $original['role'])->first();
if ($existing && ($existing->deleted_at || $existing->data_classification !== 'public')) {
throw new RuntimeException('Archived or restricted territorial relation must not be revived.');
}
$identity = DB::table('project_locations')->where('id', $original['id'])->first();
if ($identity && (! $existing || $identity->id !== $existing->id)) {
throw new RuntimeException('Historical relation identity is already occupied.');
}
$links[] = ['code' => $item['code'], 'already_present' => (bool) $existing, 'row' => [...$original, 'project_id' => $project->id]];
}
return ['manifest_sha256' => self::HASH, 'projects' => array_values($projects), 'links' => $links];
}
/** Caller supplies an authenticated, backed-up transaction; no source publication changes.
* @param array{manifest_sha256:string,projects:list<array<string,mixed>>,links:list<array<string,mixed>>} $plan
* @return array<string,int>
*/
public function apply(array $plan): array
{
if (DB::transactionLevel() < 1 || $this->plan() !== $plan) {
throw new RuntimeException('Reviewed transaction and unchanged preview required.');
}
$inserted = 0;
$updated = 0;
foreach ($plan['projects'] as $project) {
if ($project['before_metadata'] == $project['after_metadata']) {
continue;
}
$count = DB::table('projects')->where('id', $project['id'])->where('version_no', $project['before_version'])->update([
'metadata' => json_encode($project['after_metadata'], JSON_THROW_ON_ERROR), 'version_no' => $project['before_version'] + 1, 'updated_at' => now(),
]);
if ($count !== 1) {
throw new RuntimeException('Concurrent project change.');
}
DB::table('audit_events')->insert(['source_system' => 'approved-anchor-territories-recovery-v1', 'external_id' => self::HASH.':'.$project['id'], 'entity_type' => 'projects', 'entity_id' => $project['id'], 'action' => 'accepted_territories_restored',
'data_classification' => 'public', 'before_data' => json_encode(['version_no' => $project['before_version'], 'metadata' => $project['before_metadata']], JSON_THROW_ON_ERROR),
'after_data' => json_encode(['version_no' => $project['before_version'] + 1, 'manifest_sha256' => self::HASH, 'metadata' => $project['after_metadata'], 'new_approval' => false], JSON_THROW_ON_ERROR)]);
$updated++;
}
foreach ($plan['links'] as $link) {
if ($link['already_present']) {
continue;
}
DB::table('project_locations')->insert($link['row']);
$inserted++;
}
return ['relations_restored' => $inserted, 'projects_updated' => $updated, 'new_dossiers' => 0, 'publication_changes' => 0];
}
}
+50
View File
@@ -0,0 +1,50 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Support\Facades\DB;
/** Navigation over existing authorisations; never grants a role or publishes content. */
final class ContentManagement
{
public function access(?User $actor): array
{
if (! $actor || ! $actor->hasVerifiedEmail()) return [];
$profiles = app(PortalProfileAccess::class);
$navigation = $profiles->navigation($actor);
$legacy = $profiles->legacyWriteAllowed($actor);
$documents = app(DocumentManagementAccess::class);
$editor = $documents->full($actor) || $documents->editorial($actor);
$upload = $editor || $documents->limited($actor);
$result = [];
if (app(Procurement::class)->available() && app(Procurement::class)->access($actor)) $result['procurement'] = ['index' => '/management/concursos', 'create' => '/management/concursos/novo'];
if ($legacy || ($navigation['mine'] ?? null) || ($navigation['review'] ?? null)) {
$result['opportunities'] = ['index' => $legacy ? '/management/opportunities' : '/minhas-oportunidades',
'create' => $legacy ? '/management/opportunities/create' : ($navigation['create'] ?? null), 'profileWorkflow' => ! $legacy];
}
if ($upload) $result['documents'] = ['index' => '/management/portal-services', 'edit' => $editor];
return $result;
}
public function view(User $actor): array
{
$access = $this->access($actor);
abort_unless($access !== [], 403);
$counts = [];
if (isset($access['opportunities'])) {
$counts['opportunities'] = app(PortalProfileAccess::class)->scope(Opportunity::query(), $actor)
->selectRaw("COALESCE(workflow_context->>'working_state',status) as state, count(*) as total")
->groupByRaw("COALESCE(workflow_context->>'working_state',status)")->pluck('total', 'state');
}
if (isset($access['documents'])) {
$documents = app(DocumentManagementAccess::class);
$query = $documents->full($actor) ? DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->whereNull('d.deleted_at')
: ($access['documents']['edit'] ? $documents->editorialResources($actor) : null);
$counts['documents'] = $query ? $query->select('r.published', DB::raw('count(*) as total'))->groupBy('r.published')->get()
->mapWithKeys(fn ($row) => [$row->published ? 'published' : 'unpublished' => (int) $row->total]) : [];
}
return ['access' => $access, 'counts' => $counts];
}
}
+83
View File
@@ -0,0 +1,83 @@
<?php
namespace App\Services;
use DOMDocument;
use DOMElement;
/** Supplement the six named agribusiness sections without changing corridor masters or source documents. */
final class CorridorAgribusiness
{
public function enrich(string $html, array $links = []): string
{
$data = json_decode(file_get_contents(__DIR__.'/../../database/data/corridor-investment-opportunities.json'), true, 512, JSON_THROW_ON_ERROR);
$doc = new DOMDocument;
$previous = libxml_use_internal_errors(true);
try {
$doc->loadHTML('<?xml encoding="UTF-8"><html><body>'.$html.'</body></html>', LIBXML_NONET);
$body = $doc->getElementsByTagName('body')->item(0);
if (! $body) {
return $html;
}
$changed = false;
foreach ($data['groups'] as $index => $group) {
$marker = 'agronegocio-oportunidades-'.($index + 1);
if ($doc->getElementById($marker)) {
continue;
}
foreach (iterator_to_array($body->childNodes) as $heading) {
if (! $heading instanceof DOMElement) {
continue;
}
$name = preg_replace('/^[a-f]\)\s*/u', '', trim($heading->textContent));
if ($name !== $group['name']) {
continue;
}
$chains = $heading->nextSibling;
while ($chains && ! $chains instanceof DOMElement) {
$chains = $chains->nextSibling;
}
// Insert only into the exact named section and its existing priority-chain paragraph.
if (! $chains || ! str_starts_with(trim($chains->textContent), 'Cadeias de valor prioritárias:')) {
continue;
}
$fragment = $doc->createDocumentFragment();
$label = $doc->createElement('p');
$strong = $doc->createElement('strong');
$strong->appendChild($doc->createTextNode('Oportunidades de investimento em agronegócio:'));
$label->appendChild($strong);
$fragment->appendChild($label);
$list = $doc->createElement('ul');
$list->setAttribute('id', $marker);
foreach ($group['opportunities'] as $itemIndex => $opportunity) {
$item = $doc->createElement('li');
$chain = $doc->createElement('strong');
$chain->appendChild($doc->createTextNode($opportunity['chain'].': '));
$item->appendChild($chain);
$item->appendChild($doc->createTextNode($opportunity['description']));
if (isset($links[$index][$itemIndex])) {
$item->appendChild($doc->createTextNode(' '));
$link = $doc->createElement('a');
$link->setAttribute('href', $links[$index][$itemIndex]);
$link->appendChild($doc->createTextNode('Conhecer a oportunidade e iniciar o roteiro'));
$item->appendChild($link);
}
$list->appendChild($item);
}
$fragment->appendChild($list);
$source = $doc->createElement('p');
$source->appendChild($doc->createTextNode('Fonte das oportunidades: '.$data['source']));
$fragment->appendChild($source);
$body->insertBefore($fragment, $chains->nextSibling);
$changed = true;
break;
}
}
return $changed ? implode('', array_map(fn ($node) => $doc->saveHTML($node), iterator_to_array($body->childNodes))) : $html;
} finally {
libxml_clear_errors();
libxml_use_internal_errors($previous);
}
}
}
@@ -0,0 +1,97 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
use App\Models\Sector;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Ramsey\Uuid\Uuid;
/** Source-defined opportunities; never infer a master corridor, site or promoter. */
final class CorridorAgribusinessOpportunities
{
public const SOURCE_HASH = '1473b06c48aa234e771660e3f2a51b9d2e4e1943bd52d878e0ae854ee6657055';
/** Documentary cross-reference only; keep the two source designations and master records intact. */
public function portfolioOpportunityIds(\App\Models\InvestmentDossier $dossier): array
{
if (!$dossier->corridor_id || data_get($dossier->content, 'code') !== 'COR-02') return [];
// COR-02 is Beira e Centro in investment-portfolio.json. The seven entries are explicitly
// grouped under Corredor da Beira in the accepted source, not selected by province/name search.
$keys = collect($this->entries())->where('corridor', 'Corredor da Beira')->pluck('key');
return Opportunity::published()->whereIn('management_creation_key', $keys)
->where('workflow_context->corridor_agribusiness->source_sha256', self::SOURCE_HASH)->pluck('id')->all();
}
public const LIMITATIONS = 'Promotor, implantação exacta, área, montante, financiamento, viabilidade e licenças não indicados nesta fonte. O corredor é um enquadramento documental; não identifica uma parcela nem confirma disponibilidade.';
public function entries(): array
{
$data = json_decode(file_get_contents(database_path('data/corridor-investment-opportunities.json')), true, 512, JSON_THROW_ON_ERROR);
if ($data['source_sha256'] !== self::SOURCE_HASH) throw new \RuntimeException('Fonte divergente; reconciliar antes de cadastrar.');
$sector = Sector::where('slug', 'agronegocio')->where('is_active', true)->whereNull('deleted_at')->firstOrFail();
$entries = [];
foreach ($data['groups'] as $g => $group) {
foreach ($group['opportunities'] as $i => $item) {
$key = (string) Uuid::uuid5(Uuid::NAMESPACE_URL, 'investmoz:agronegocio:'.self::SOURCE_HASH.':'.$g.':'.$i);
$title = Str::limit($item['chain'].' — '.$group['name'], 150, '…');
$description = $item['description']."\n\nEnquadramento documental: ".$group['name'].".\n\nFonte: ".$data['source'].'; SHA-256 '.self::SOURCE_HASH.".\n\n".self::LIMITATIONS;
$entries[] = ['key' => $key, 'group' => $g, 'index' => $i, 'corridor' => $group['name'], 'chain' => $item['chain'],
'source' => $data['source'], 'source_sha256' => self::SOURCE_HASH, 'title' => $title,
'summary' => $item['description'], 'description' => $description, 'sector_id' => $sector->id];
}
}
if (count($entries) !== 34) throw new \RuntimeException('O lote deve conter as 34 entradas da fonte.');
return $entries;
}
public function register(User $actor, string $organization): array
{
// The caller uses the ordinary profile creation route and its approved scope.
abort_unless(str_starts_with(request()->path(), 'minhas-oportunidades'), 422);
return DB::transaction(function () use ($actor, $organization) {
DB::select('SELECT pg_advisory_xact_lock(231026, 34)');
$result = [];
foreach ($this->entries() as $entry) {
$record = Opportunity::withTrashed()->where('management_creation_key', $entry['key'])->first();
if ($record) {
abort_unless(app(PortalProfileAccess::class)->canView($actor, $record), 403);
abort_unless(data_get($record->workflow_context, 'corridor_agribusiness.source_sha256') === self::SOURCE_HASH, 409);
// Recovery never overwrites editorial changes, withdrawal or archive.
$result[] = ['id' => $record->id, 'created' => false, 'key' => $entry['key']];
continue;
}
$record = app(OpportunityManagement::class)->save($actor, ['creation_key' => $entry['key'], 'organization_id' => $organization,
'opportunity_category' => 'investment_project', 'sector_id' => $entry['sector_id'],
'title' => $entry['title'], 'summary' => $entry['summary'], 'description' => $entry['description'],
'canonical' => ['opportunity_category' => 'investment_project', 'official_title' => $entry['title'],
'executive_summary' => $entry['summary'], 'demand_statement' => $entry['description'], 'sector_id' => $entry['sector_id']],
'reason' => 'Cadastro privado das 34 oportunidades de agronegócio solicitado pela Tempo em 23/10/2026; não constitui publicação nem aprovação de execução.']);
$context = $record->workflow_context ?? [];
$context['corridor_agribusiness'] = $entry;
$context['promotional_summary'] = ['input' => ['title' => $entry['title'], 'summary' => $entry['summary'],
'description' => $entry['description'], 'source_reference' => $entry['source'].'; SHA-256 '.self::SOURCE_HASH,
'limitations' => self::LIMITATIONS, 'edition' => '', 'source_date' => '', 'territory_ids' => [], 'sector_id' => $entry['sector_id']]];
$record->workflow_context = $context;
$record->maturity_label = 'Em preparação';
$record->save();
DB::table('audit_events')->insert(['source_system' => 'corridor-agribusiness-registration', 'entity_type' => 'opportunity',
'action' => 'private_source_registered', 'actor_user_id' => $actor->id, 'data_classification' => 'restricted',
'after_data' => json_encode(['record_id' => $record->id, 'source' => $entry, 'no_publication' => true, 'no_master_relation_inferred' => true], JSON_THROW_ON_ERROR)]);
$result[] = ['id' => $record->id, 'created' => true, 'key' => $entry['key']];
}
return $result;
});
}
public function articleLinks(): array
{
$records = Opportunity::published()->whereIn('management_creation_key', array_column($this->entries(), 'key'))->get()->keyBy('management_creation_key');
$links = [];
foreach ($this->entries() as $entry) {
if ($record = $records->get($entry['key'])) $links[$entry['group']][$entry['index']] = '/oportunidades/'.$record->slug;
}
return $links;
}
}
+8 -2
View File
@@ -26,8 +26,9 @@ class DocumentManagementAccess
/** Restore the approved editorial operation without a global management grant. */
public function editorial(User $actor): bool
{
return config('portal.homologation_only', false)
&& in_array(strtolower(trim($actor->email)), config('homologation_editorial.accounts', []), true)
// Tempo's named editorial designation does not depend on whether the
// site's technical reviewer reservation is enabled.
return in_array(strtolower(trim($actor->email)), config('homologation_editorial.accounts', []), true)
&& app(PortalProfileAccess::class)->superuser($actor)
&& ! app(PortalProfileAccess::class)->has($actor, 'auditor')
&& app(PortalProfileAccess::class)->mfa($actor);
@@ -49,6 +50,11 @@ class DocumentManagementAccess
->where('d.external_id', $item['external_id']);
});
}
foreach (json_decode(file_get_contents(config_path('legacy_editorial_resources.json')), true, 512, JSON_THROW_ON_ERROR) as $item) {
// These exact original bytes contain the legacy identity/source.
// Destination upload IDs differ; the approved file scope does not.
$query->orWhere('d.sha256', $item['sha256']);
}
});
}
+130
View File
@@ -0,0 +1,130 @@
<?php
namespace App\Services;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\UriResolver;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpKernel\Exception\HttpException;
/** Reads verified originals without writing a derived edition or changing publication. */
final class EditorialReading
{
public function publicResources()
{
return DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')
->where('r.published', true)->where('r.rights_status', 'authorized')->where('d.rights_status', 'authorized')
->where('d.status', 'active')->where('d.data_classification', 'public')->whereNull('d.deleted_at')
->where('d.malware_scan_status', 'clean')->whereColumn('d.sha256', 'd.malware_scanned_sha256');
}
public function original(object $resource): ?array
{
$document = DB::table('documents')->find($resource->document_id);
if (! $document || $document->status !== 'active' || $document->malware_scan_status !== 'clean' || ! in_array($document->media_type, ['text/plain', 'application/json'], true)) {
return null;
}
$binary = app(VerifiedDocumentBinary::class)->respond($document);
$bytes = $binary instanceof BinaryFileResponse ? file_get_contents($binary->getFile()->getPathname()) : $binary->getContent();
if (! is_string($bytes) || strlen($bytes) > 10485760) {
return null;
}
$original = json_decode($bytes, true);
return is_array($original) && ($original['format'] ?? '') === 'investmoz-legacy-article-v1' && is_string($original['content_html'] ?? null) ? $original : null;
}
public function plain(string $html): string
{
return trim(html_entity_decode(strip_tags(preg_replace('~</(?:p|div|li|h[1-6]|tr)>|<br\s*/?>~i', "\n\n", $html)), ENT_QUOTES | ENT_HTML5, 'UTF-8'));
}
public function content(object $resource, ?array $original): array
{
return $resource->editorial_content ? json_decode($resource->editorial_content, true, 512, JSON_THROW_ON_ERROR)
: ['body' => $this->plain($original['content_html'] ?? ''), 'image_resource_id' => null, 'image_mode' => 'original', 'preserve_original_html' => true];
}
private function sourceUrl(mixed $url, ?string $base = null): ?string
{
if (! is_string($url) || trim($url) === '') {
return null;
}
try {
$absolute = $base ? (string) UriResolver::resolve(new Uri($base), new Uri($url)) : $url;
return filter_var($absolute, FILTER_VALIDATE_URL) && in_array(strtolower((string) parse_url($absolute, PHP_URL_SCHEME)), ['http', 'https'], true) ? $absolute : null;
} catch (\InvalidArgumentException) {
return null;
}
}
public function reading(object $resource, ?array $override = null, bool $private = false): array
{
$original = $this->original($resource);
$content = $override ?? $this->content($resource, $original);
abort_unless(trim($content['body'] ?? '') !== '', 404, 'Este documento não contém um artigo legível.');
$document = DB::table('documents')->find($resource->document_id);
// The original is verified above; ordinary text adaptations retain the binary gate too.
app(VerifiedDocumentBinary::class)->respond($document);
$mode = $content['image_mode'] ?? (! empty($content['image_resource_id']) ? 'selected' : 'none');
$originalImageUrl = $this->sourceUrl($original['image_source_url'] ?? null, $original['source_url'] ?? null);
$expectedImageSha = $original['image_sha256'] ?? null;
if (! $expectedImageSha && $originalImageUrl === 'https://investemoz.tempo.co.mz/images/tempo-background.png') {
foreach (json_decode(file_get_contents(config_path('legacy_editorial_resources.json')), true, 512, JSON_THROW_ON_ERROR) as $accepted) {
if ($accepted['sha256'] === $document->sha256) {
$expectedImageSha = $accepted['original_image_sha256'] ?? null;
break;
}
}
}
$images = $this->publicResources()->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp']);
$image = null;
if ($mode === 'selected' && ! empty($content['image_resource_id'])) {
$image = (clone $images)->where('r.id', $content['image_resource_id'])->first(['r.id', 'r.title']);
}
if ($mode === 'original' && $original) {
$image = (clone $images)->where(function ($q) use ($expectedImageSha, $originalImageUrl) {
$q->whereRaw('1=0');
if ($expectedImageSha) {
$q->orWhere('d.sha256', $expectedImageSha);
} elseif ($originalImageUrl) {
$q->orWhere('r.source_url', $originalImageUrl)->orWhere('d.original_source', $originalImageUrl);
}
})->first(['r.id', 'r.title']);
}
if ($image) {
// A public flag alone never licenses missing or changed image bytes.
$binary = (clone $images)->where('r.id', $image->id)->first(['d.*']);
try {
app(VerifiedDocumentBinary::class)->respond($binary);
} catch (HttpException) {
$image = null;
}
}
$originalFormat = $original && ($content['preserve_original_html'] ?? false) && $content['body'] === $this->plain($original['content_html']);
$html = $originalFormat ? app(LegacyContent::class)->sanitize($original['content_html'], true) : null;
$imageReferences = [];
if ($original) {
preg_match_all('~<img\b[^>]*\bsrc\s*=\s*([\'"])(.*?)\1~is', $original['content_html'], $matches);
foreach ($matches[2] as $source) {
$url = $this->sourceUrl(html_entity_decode($source, ENT_QUOTES | ENT_HTML5, 'UTF-8'), $original['source_url'] ?? null);
if ($url) {
$imageReferences[] = $url;
}
}
}
return ['id' => $resource->id, 'title' => $resource->title, 'description' => $resource->description,
'author' => $document->issuer, 'body' => $content['body'], 'html' => $html,
'image_url' => $image ? '/documentos/'.$image->id.'/view' : null,
'image_notice' => $mode === 'selected' && ! $image ? 'A imagem escolhida está indisponível para divulgação; a selecção mantém-se na edição.' : ($mode === 'original' && ! $image && ! empty($original['image_source_url']) ? 'Imagem de origem referenciada, mas sem exemplar público verificado na biblioteca. A referência original mantém-se preservada.' : null),
'source_url' => $this->sourceUrl($original['source_url'] ?? $resource->source_url),
'published_at' => $original['published_at'] ?? null, 'modified_at' => $original['modified_at'] ?? null,
'legacy_id' => $original['legacy_id'] ?? null, 'image_source_url' => $originalImageUrl, 'image_expected_sha256' => $expectedImageSha, 'image_references' => array_values(array_unique($imageReferences)),
'metadata_version' => $resource->metadata_version, 'private_preview' => $private,
'original_url' => $private ? '/management/documents/'.$resource->document_id.'/download' : '/documentos/'.$resource->id,
];
}
}
+36 -20
View File
@@ -26,7 +26,7 @@ class InvestmentCatalogue
'cluster_id' => ['nullable', 'uuid'], 'corridor_id' => ['nullable', 'uuid'], 'project_id' => ['nullable', 'uuid'],
'geo_location_id' => ['nullable', 'uuid'], 'education' => ['nullable', 'boolean'],
'zee_id' => ['nullable', 'uuid'], 'zfi_id' => ['nullable', 'uuid'], 'park_id' => ['nullable', 'uuid'],
'dimension' => ['nullable', 'in:cluster,corridor,zee,zfi'], 'view' => ['nullable', 'in:grid,list,map,combined'],
'dimension' => ['nullable', 'in:cluster,corridor,zee,zfi'], 'view' => ['nullable', 'in:grid,list,map,combined,corridors'],
'maturity_level' => ['nullable', 'integer', 'between:1,8'], 'facets' => ['nullable', 'array', 'max:20'], 'facets.*' => ['integer', 'min:1'],
'min_amount' => ['nullable', 'numeric', 'min:0', 'max:999999999999'],
'max_amount' => ['nullable', 'numeric', 'min:0', 'max:999999999999', ...($request->filled('min_amount') ? ['gte:min_amount'] : [])],
@@ -231,16 +231,25 @@ class InvestmentCatalogue
} elseif (in_array($relation, ['clusters', 'corridors'], true)) {
$query->whereIn('id', $this->publicStructureIds($relation, $foreign));
} else {
$query->whereIn('id', InvestmentPortfolioController::visible()->whereNotNull($foreign)->pluck($foreign));
$query->whereIn('id', app(OpportunityClassification::class)->targets('project')->select('id'));
}
}
if (! $management && $path !== [] && $relation !== 'locations') {
$dossiers = InvestmentPortfolioController::visible();
app(InvestmentGeography::class)->constrainDossiersToTerritories($dossiers,
app(InvestmentGeography::class)->descendants($path[array_key_last($path)]->id));
$query->whereIn('id', $dossiers->whereNotNull($foreign)->select($foreign));
$territories = app(InvestmentGeography::class)->descendants($path[array_key_last($path)]->id);
$query->where(fn ($area) => $area->whereIn('primary_territory_id', $territories)
->orWhereIn('id', $dossiers->whereNotNull($foreign)->select($foreign)));
}
$result[$relation] = $query->orderBy('name')->get(['id', 'name']);
if (! $management && $relation !== 'locations') {
$dossiers = InvestmentPortfolioController::visible()->whereIn($foreign, $result[$relation]->pluck('id'))
->orderBy('id')->get(['id', $foreign])->unique($foreign)->keyBy($foreign);
$result[$relation]->each(function ($record) use ($dossiers): void {
$record->url = isset($dossiers[$record->id]) ? '/carteira/'.$dossiers[$record->id]->id : null;
});
}
}
$zones = app(InvestmentZones::class)->visible();
@@ -250,24 +259,15 @@ class InvestmentCatalogue
['province_id', 'district_id', 'admin_post_id', 'locality_id', 'province', 'district', 'geo_location_id']));
}
$result['zones'] = $zones->orderBy('name')->get(['id', 'name', 'category']);
if (! $management && ($path !== [] || ! empty($territoryFilters['sector']))) {
$scope = \Illuminate\Support\Arr::only($territoryFilters, ['sector','province_id','district_id','admin_post_id','locality_id','include_national']);
$available = ['chain' => [], 'activity' => []];
$this->query($scope)->reorder()->chunkById(200, function ($records) use (&$available) {
foreach ($records as $record) {
foreach (app(OpportunityClassification::class)->publicRows($record) as $row) {
if (isset($available[$row['target_type']])) $available[$row['target_type']][] = $row['target_id'];
}
foreach (['subsector_id','economic_activity_id'] as $key) {
$id = $record->workflow_context['publication']['taxonomy'][$key] ?? null;
if ($id) $available['activity'][] = $id;
}
}
}, 'opportunities.id', 'id');
foreach ($available as $kind => $ids) {
$result['classification']['targets'][$kind] = collect($result['classification']['targets'][$kind])->whereIn('id', $ids)->values();
}
if (! $management && $path !== []) {
// A chain's documented scope comes from its public cluster, never
// from the opportunities surviving the current search.
$ids = app(OpportunityClassification::class)->targets('chain')
->whereIn('cluster_id', $result['clusters']->pluck('id'))->pluck('id');
$result['classification']['targets']['chain'] = collect($result['classification']['targets']['chain'])->whereIn('id', $ids)->values();
}
// Activities are a public classification catalogue, not evidence of
// investment availability in a territory or sector.
return $result;
}
@@ -292,6 +292,10 @@ class InvestmentCatalogue
}
}
});
if (!empty($selected['corridor_id'])) {
$dossier = InvestmentPortfolioController::visible()->where('corridor_id', $selected['corridor_id'])->first();
if ($dossier) $ids['corridor_id'] = array_values(array_unique([...($ids['corridor_id'] ?? []), ...app(CorridorAgribusinessOpportunities::class)->portfolioOpportunityIds($dossier)]));
}
return $ids;
}
@@ -308,6 +312,18 @@ class InvestmentCatalogue
/** @return array<string,mixed> */
public function context(int $id, bool $management = false): array
{
$opportunity = Opportunity::findOrFail($id);
if (! $management && data_get($opportunity->workflow_context, 'publication.purpose') === OpportunityPromotion::PURPOSE) {
// Promotional disclosure includes only its explicit public coverage.
// Private profiles, source evidence and other dossier relations are not auto-published.
$public = ['profile' => null, 'facets' => collect(), 'zones' => collect(), 'classification' => [], 'source_evidence' => [],
'primary_territory_path' => app(InvestmentGeography::class)->path($opportunity->primary_territory_id, true),
'opportunity_locations' => app(InvestmentRelations::class)->opportunityLocations($id)];
foreach (self::RELATIONS as $relation => $_) $public[$relation] = collect();
$public['locations'] = DB::table('opportunity_locations as l')->join('geo_locations as g', 'g.id', '=', 'l.geo_location_id')
->where('l.opportunity_id', $id)->where('g.data_classification', 'public')->whereNull('g.deleted_at')->get(['g.id', 'g.name']);
return $public;
}
$result = ['profile' => DB::table('opportunity_profiles')->where('opportunity_id', $id)->first(),
'facets' => DB::table('opportunity_facets as f')->join('investment_reference_options as o', 'o.id', '=', 'f.option_id')
->where('f.opportunity_id', $id)->get(['o.id', 'o.group', 'o.label'])];
+157
View File
@@ -0,0 +1,157 @@
<?php
namespace App\Services;
use App\Http\Controllers\InvestmentPortfolioController;
use App\Models\Opportunity;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Str;
/** Resolve documented complements without creating opportunities or master relations. */
final class InvestmentComplements
{
private const TERMS = [
'irrigation' => ['Regadio', 'regadio|irrigação|irrigacao'],
'storage' => ['Silos e armazenagem', 'silos?|armazenagem|armazenamento'],
'cold' => ['Cadeia de frio', 'frio|refrigeração'],
'processing' => ['Processamento', 'processamento|transformação|moagem'],
'spinning' => ['Fiação', 'fiação|fiacao'],
'logistics' => ['Logística', 'logística|logistica|transporte'],
'certification' => ['Certificação', 'certificação|certificacao'],
'training' => ['Formação', 'formação|formacao'],
'finance' => ['Financiamento', 'financiamento|serviços financeiros'],
];
public function options(string $origin, ?string $territory = null): array
{
[$originKind, $originId] = array_pad(explode(':', $origin, 2), 2, '');
abort_unless(($originKind === 'portfolio' && Str::isUuid($originId)) || ($originKind === 'opportunity' && ctype_digit($originId)), 422, 'Origem complementar inválida.');
$principal = null;
$relationEvidence = [];
if (str_starts_with($origin, 'portfolio:')) {
$record = InvestmentPortfolioController::visible()->addSelect('version_no')->findOrFail(substr($origin, 10));
$text = trim(($record->content['focus'] ?? '')."\n".($record->content['gaps'] ?? '')."\n".($record->content['description'] ?? ''));
$reference = ['key' => $origin, 'title' => $record->title, 'href' => '/carteira/'.$record->id, 'version' => $record->version_no];
$ids = app(CorridorAgribusinessOpportunities::class)->portfolioOpportunityIds($record);
foreach (['projects' => 'project_id', 'clusters' => 'cluster_id', 'corridors' => 'corridor_id'] as $relation => $foreign) {
if ($record->$foreign) $ids = [...$ids, ...DB::table('opportunity_'.$relation)->where($foreign, $record->$foreign)->pluck('opportunity_id')->all()];
}
$basis = $record->source;
foreach (array_unique($ids) as $id) $relationEvidence[$id] = ['type' => 'portfolio', 'origin' => $origin, 'source' => $basis];
$serviceOrigins = [['dossier', $record->id]];
foreach (['project_id' => 'project', 'cluster_id' => 'cluster'] as $foreign => $type) {
if ($record->$foreign) $serviceOrigins[] = [$type, $record->$foreign];
}
} else {
$reference = app(InvestorContext::class)->reference($origin);
abort_unless($reference['kind'] === 'opportunity', 422);
$principal = Opportunity::published()->findOrFail($reference['id']);
$text = $principal->summary;
$basis = 'Resumo cadastrado da oportunidade '.$principal->reference;
$projects = DB::table('opportunity_projects')->where('opportunity_id', $principal->id)->pluck('project_id');
$links = DB::table('complementary_project_links')->whereIn('anchor_project_id', $projects)
->whereNull('deleted_at')->where('data_classification', 'public')->get(['id', 'anchor_project_id', 'complementary_project_id', 'relation_type', 'version_no']);
$targetProjects = DB::table('opportunity_projects')->whereIn('project_id', $links->pluck('complementary_project_id'))->get();
$ids = [$principal->id, ...$targetProjects->pluck('opportunity_id')->all()];
$relationEvidence[$principal->id] = ['type' => 'same_fiche', 'source' => $basis];
foreach ($targetProjects as $targetProject) $relationEvidence[$targetProject->opportunity_id] = ['type' => 'complementary_project',
'links' => $links->where('complementary_project_id', $targetProject->project_id)->values()->map(fn($link) => (array)$link)->all()];
foreach (Opportunity::published()->whereIn('id', $ids)->where('id', '!=', $principal->id)->get() as $linked) $text .= "\n".$linked->summary;
if (count($ids) > 1) $basis .= '; relações complementares públicas entre projectos';
$serviceOrigins = [['investment', (string) $principal->id]];
$classification = app(OpportunityClassification::class);
$principalChains = collect($classification->publicRows($principal))->where('target_type', 'chain')->filter(fn($r) => !empty($r['source_reference']));
$chains = $principalChains->pluck('target_id')->all();
if ($chains) {
Opportunity::published()->whereNot('id', $principal->id)->chunkById(100, function ($records) use (&$ids, &$relationEvidence, $chains, $principalChains, $classification) {
foreach ($records as $candidate) {
$related = collect($classification->publicRows($candidate))->where('target_type', 'chain')->filter(fn($r) => !empty($r['source_reference']));
$shared = array_intersect($chains, $related->pluck('target_id')->all());
if ($shared) {
$ids[] = $candidate->id;
$relationEvidence[$candidate->id] ??= ['type' => 'value_chain', 'principal' => $principalChains->whereIn('target_id', $shared)->values()->all(), 'target' => $related->whereIn('target_id', $shared)->values()->all()];
}
}
});
}
}
$territoryReference = $territory ? app(InvestorContext::class)->reference('territory:'.$territory) : null;
$candidates = Opportunity::published()->whereIn('id', array_unique($ids))->get();
$items = [];
foreach (self::TERMS as $code => [$label, $pattern]) {
if (!preg_match('/\b(?:'.$pattern.')\b/iu', $text, $match)) continue;
$offers = [];
foreach ($candidates as $candidate) {
// A common corridor alone does not prove the component. Keep the supporting excerpt.
if (!preg_match('/\b(?:'.$pattern.')\b/iu', $candidate->title."\n".$candidate->summary, $evidence)) continue;
// Mentioning a need for funding/training in a project's summary is not an offer.
if (in_array($code, ['certification', 'training', 'finance'], true) && !preg_match('/\b(?:'.$pattern.')\b/iu', $candidate->title)) continue;
if (in_array($code, ['certification', 'training', 'finance'], true) && preg_match('/\b(?:necessidade|pedido|procura)\b/iu', $candidate->title)) continue;
if ($territory && $candidate->primary_territory_id && !$this->compatible($territory, $candidate->primary_territory_id)) continue;
$offers[] = ['key' => 'opportunity:'.$candidate->id, 'title' => $candidate->title, 'href' => '/oportunidades/'.$candidate->slug,
'relationship' => $relationEvidence[$candidate->id] ?? null,
'version' => $candidate->management_version, 'evidence' => $evidence[0], 'location' => ($principal && $principal->id === $candidate->id ? 'Componente referido na própria ficha. ' : '').($candidate->primary_territory_id ? app(InvestorContext::class)->reference('territory:'.$candidate->primary_territory_id)['title'] : 'Implantação por definir')];
}
// Services are concrete published offerings explicitly associated with this source.
$services = [];
if (in_array($code, ['certification', 'training', 'finance'], true) && Schema::hasTable('partnership_origins') && Schema::hasTable('partnership_interests')) {
if ($serviceOrigins) {
$services = DB::table('portal_partnerships as p')->join('partnership_origins as o', 'o.partnership_id', '=', 'p.id')
->where(function ($q) use ($serviceOrigins) {
foreach ($serviceOrigins as [$type, $id]) $q->orWhere(fn($q) => $q->where('o.type', $type)->where('o.target_id', $id));
})->where('p.status', 'published')->where('p.kind', 'offering')
->where('p.partnership_type', $code === 'finance' ? 'finance' : 'training')
->when($code !== 'finance', fn($q) => $q->where(fn($q) => $q->where('p.title', 'ilike', '%'.$match[0].'%')->orWhereRaw("p.payload->>'summary' ILIKE ?", ['%'.$match[0].'%'])))->distinct()->get(['p.id', 'p.title'])
->filter(function ($p) use ($territory) {
if (!$territory) return true;
$locations = DB::table('partnership_locations')->where('partnership_id', $p->id)->pluck('geo_location_id');
return $locations->isEmpty() || $locations->contains(fn($id) => $this->compatible($territory, $id));
})->map(fn ($p) => ['key' => 'partnership:'.$p->id, 'title' => $p->title, 'href' => '/parcerias/'.$p->id, 'location' => 'Consultar âmbito na oferta'])->values()->all();
}
}
$excerpt = collect(explode("\n", $text))->first(fn($line) => preg_match('/\b(?:'.$pattern.')\b/iu', $line));
$items[] = ['code' => $code, 'title' => $label, 'origin' => $reference, 'territory_id' => $territory, 'territory' => $territoryReference,
'source' => $basis, 'excerpt' => $excerpt, 'source_sha256' => hash('sha256', $text), 'opportunities' => $offers, 'services' => $services];
}
return $items;
}
private function compatible(string $a, string $b): bool
{
if ($a === $b) return true;
$geo = app(InvestmentGeography::class);
return in_array($b, $geo->descendants($a), true) || in_array($a, $geo->descendants($b), true);
}
public function resolve(array $input, array $previous = []): array
{
$resolved = [];
foreach ($input as $choice) {
$target = $choice['target'] ?? null;
$old = collect($previous)->first(fn($r) => $r['origin']['key'] === $choice['origin'] && $r['code'] === $choice['code'] && ($r['target']['key'] ?? null) === $target && ($r['territory_id'] ?? null) === ($choice['territory_id'] ?? null));
try {
$item = collect($this->options($choice['origin'], $choice['territory_id'] ?? null))->firstWhere('code', $choice['code']);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
if (!$old) throw $e;
$item = null;
} catch (\Symfony\Component\HttpKernel\Exception\HttpException $e) {
if (!$old || $e->getStatusCode() !== 404) throw $e;
$item = null;
}
$offer = $target && $item ? collect([...$item['opportunities'], ...$item['services']])->firstWhere('key', $target) : null;
if ($old && (!$item || ($target && !$offer) || (!$target && ($item['opportunities'] || $item['services'])))) {
$resolved[$old['key']] = [...$old, 'availability' => 'review_required'];
continue;
}
abort_unless($item, 422, 'Complemento sem referência documentada neste investimento.');
abort_if($target && !$offer, 422, 'A oferta complementar deixou de estar disponível neste contexto.');
abort_if(!$target && ($item['opportunities'] || $item['services']), 422, 'Já existe uma oferta relacionada; seleccione a ficha correspondente.');
$key = hash('sha256', $choice['origin'].'|'.$choice['code'].'|'.($target ?? 'idea').'|'.($choice['territory_id'] ?? ''));
$resolved[$key] = ['key' => $key, 'origin' => $item['origin'], 'code' => $item['code'], 'title' => $item['title'],
'kind' => $target ? (str_starts_with($target, 'opportunity:') ? 'opportunity' : 'service') : 'need',
'target' => $offer, 'territory_id' => $item['territory_id'], 'territory' => $item['territory'], 'source' => $item['source'], 'excerpt' => $item['excerpt'], 'source_sha256' => $item['source_sha256']];
}
return array_values($resolved);
}
}
+85
View File
@@ -0,0 +1,85 @@
<?php
namespace App\Services;
use App\Models\User;
use Illuminate\Support\Arr;
/** An identified opportunity within the authorised dossier, never the account's last choice. */
final class InvestmentConsumerScope
{
public function key(array $context, ?string $key, bool $required = false): ?string
{
$choices = $context['opportunity_choices'] ?? [];
$key = $key ?: (count($choices) === 1 ? $choices[0]['opportunity']['key'] : null);
abort_if($key && !collect($choices)->contains('opportunity.key', $key), 422, 'Escolha uma oportunidade deste dossier.');
abort_if($required && count($choices) > 1 && !$key, 422, 'Escolha a oportunidade em tratamento.');
return $key;
}
public function facts(array $payload, array $context, ?string $key): array
{
$key = $this->key($context, $key);
$path = $payload['investor_path'] ?? [];
$defaults = ['land_needed' => 'unknown', 'external_funding' => 'unknown', 'viability' => 'unknown'];
// A dossier-wide dispensation cannot decide a distinct opportunity's needs.
if ($key && count($context['opportunity_choices'] ?? []) > 1) return [...$defaults, ...($path['opportunity_facts'][$key] ?? [])];
if ($key && isset($path['opportunity_facts'][$key])) return [...$defaults, ...$path['opportunity_facts'][$key]];
if (count($context['opportunity_choices'] ?? []) > 1) return $defaults;
return [...$defaults, ...($path['facts'] ?? [])];
}
public function context(array $context, ?string $key): array
{
$choices = $context['opportunity_choices'] ?? [];
if (!$choices) return $context;
$key = $key ?: (count($choices) === 1 ? $choices[0]['opportunity']['key'] : null);
$choice = $key ? collect($choices)->firstWhere('opportunity.key', $key) : null;
abort_if($key && !$choice, 422, 'Escolha uma oportunidade deste dossier.');
$specific = ['project_summary', 'sector_id', 'sector', 'province_id', 'district_id', 'admin_post_id', 'locality_id', 'province', 'district', 'location', 'special_zone_id', 'investment_regime'];
$context['fields'] = Arr::except($context['fields'], $specific);
$context['provenance'] = Arr::except($context['provenance'] ?? [], $specific);
$context['selection'] = Arr::except($context['selection'], ['opportunity', 'territory', 'park']);
if (!$choice) {
$context['opportunity_choices'] = [];
$context['requirements_assessment']['requirements'] = [];
return $context;
}
$context['selection']['opportunity'] = $choice['opportunity'];
$context['fields'] = [...$context['fields'], ...Arr::only($choice['opportunity']['fields'], $specific)];
foreach (Arr::only($choice['opportunity']['fields'], $specific) as $field => $value) $context['provenance'][$field] = Arr::only($choice['opportunity'], ['key','kind','id','title','version','sha256']);
unset($context['selection']['sector']);
if (!empty($context['fields']['sector_id'])) $context['selection']['sector'] = app(InvestorContext::class)->reference('sector:'.$context['fields']['sector_id']);
if ($choice['territory']) {
$context['selection']['territory'] = $choice['territory'];
$context['fields'] = [...Arr::except($context['fields'], array_keys(InvestmentGeography::FIELDS)), ...$choice['territory']['fields']];
foreach ($choice['territory']['fields'] as $field => $value) $context['provenance'][$field] = Arr::only($choice['territory'], ['key','kind','id','title','version','sha256']);
} else {
$context['fields'] = Arr::except($context['fields'], ['province_id', 'district_id', 'admin_post_id', 'locality_id', 'province', 'district', 'location']);
}
$park = $choice['park'] ?? null;
if ($park) $context['selection']['park'] = $park;
$context['fields']['special_zone_id'] = $park['id'] ?? '';
$context['fields']['investment_regime'] = $park['fields']['investment_regime'] ?? 'general';
$context['opportunity_choices'] = [$choice];
$context['requirements_assessment']['requirements'] = array_values(array_filter($context['requirements_assessment']['requirements'] ?? [], fn($r) => $r['opportunity_key'] === $key));
$context['consumer_opportunity'] = $choice;
$context['complements'] = array_values(array_filter($context['complements'] ?? [], fn($c) => ($c['origin']['key'] ?? null) === $key || ($c['target']['key'] ?? null) === $key || in_array(substr($c['origin']['key'] ?? '',10),array_column($choice['portfolio_origins'] ?? [],'id'),true)));
$context['dependency_hash'] = app(InvestorContext::class)->dependencyHash(['opportunity_choices'=>[$choice], 'fields'=>Arr::except($context['fields'],['project_title','project_summary']), 'complements'=>$context['complements']]);
return $context;
}
public function bind(User $actor, string $id, array $payload, bool $required = false): array
{
$case = app(VirtualDesk::class)->case($actor, $id, true);
$context = app(InvestorContext::class)->state($case);
$scoped = $this->context($context, $payload['context_opportunity'] ?? null);
$choice = $scoped['consumer_opportunity'] ?? null;
abort_if($required && count($context['opportunity_choices'] ?? []) > 1 && !$choice, 422, 'Escolha a oportunidade em tratamento antes de submeter.');
if (!$choice) return Arr::except($payload, ['context_opportunity', 'context_opportunity_snapshot']);
// Canonical server snapshot; client text cannot establish a different origin or territory.
$payload['context_opportunity'] = $choice['opportunity']['key'];
$payload['context_opportunity_snapshot'] = json_encode(['context_id' => $id, 'revision' => $context['revision'], 'choice' => $choice, 'requirements' => $scoped['requirements_assessment'] ?? null], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
return $payload;
}
}
@@ -0,0 +1,48 @@
<?php
namespace App\Services;
/** Preparation within the existing path; no licence, DUAT or fiscal benefit is granted. */
final class InvestmentContextRequirements
{
public const VERSION = 'context-requirements-20261023';
public function assess(array $context): array
{
$rows = [];
foreach ($context['opportunity_choices'] ?? [] as $choice) {
$activities = $choice['activities'] ?? [];
$key = $choice['opportunity']['key'];
$common = ['opportunity_key' => $key, 'opportunity_title' => $choice['opportunity']['title']];
$add = function ($code, $title, $state, $step, $authority, $documents, $basis, $url) use (&$rows, $common) {
$rows[] = [...$common, 'code' => $code, 'title' => $title, 'state' => $state, 'step' => $step,
'authority' => $authority, 'documents' => $documents, 'basis' => $basis, 'source_url' => $url,
'decision' => 'Preparação; enquadramento e acto concreto conservam confirmação na etapa correspondente.'];
};
$add('geography', 'Localização e geolocalização', $choice['territory'] ? 'selected' : 'missing', 'S09', 'Cadastro territorial e serviços de cadastro competentes',
['Referência administrativa confirmada', 'Planta/esboço e coordenadas quando disponíveis; não inventar polígonos'],
'Referência territorial escolhida no dossier; não comprova disponibilidade nem direito de uso.', '/investimentos');
$add('land', 'Acesso à terra e DUAT', 'conditional', 'S10', 'Serviços de cadastro e órgão competente para o pedido territorial concreto',
['Fundamento do uso: DUAT, arrendamento ou situação declarada', 'Planta/esboço do local; documentação do pedido correspondente'],
'Regulamento de Investimento, artigos 9(1)(c)–(d) e 14(1)(c)–(d). A preparação distingue DUAT e arrendamento; escolher território não atribui terra.', PrivateInvestmentPreparation::SOURCE.'#page=42');
$add('environment', 'Enquadramento ambiental', 'conditional', 'S08', 'Autoridade de Avaliação do Impacto Ambiental; competência central/provincial conforme categorização',
['Descrição da actividade, dimensão e localização', 'Instrumento ambiental definido pela categorização competente; acto e condições quando emitidos'],
'Decreto 54/2015: a natureza, dimensão e localização determinam o enquadramento; a categoria não é deduzida do corredor ou do sector.', 'https://sibmoz.gov.mz/legal-framework/');
$add('sector', 'Licenciamento sectorial', $activities ? 'declared' : 'missing', 'S08', 'BAU, IP e autoridade sectorial competente conforme a actividade',
['Actividades efectivas e modalidade', 'Requerimento e anexos da modalidade aplicável; acto quando emitido'],
'Identificar as actividades efectivas antes de seleccionar o procedimento. O nome Agronegócio não escolhe uma licença única.', 'https://www.bau.gov.mz/nossos-servicos/');
foreach (['processing' => ['Licenciamento industrial', 'Decreto 22/2014'], 'trade' => ['Licenciamento comercial', 'Decreto 34/2013']] as $activity => [$title, $basis]) {
if (in_array($activity, $activities, true)) $add($activity, $title, 'conditional', 'S08', 'BAU, IP / entidade licenciadora da modalidade',
['Caracterização do estabelecimento e actividade', 'Documentos e regime aplicáveis, incluindo simplificado ou mera comunicação quando preenchidas as suas condições'],
$basis.'; regimes 39/2017 e 27/2023 no catálogo oficial BAU. Dimensão e modalidade ainda devem ser especificadas; não se selecciona automaticamente o regime.', 'https://www.bau.gov.mz/legislacao/');
}
foreach (['water' => 'Uso de água', 'forestry' => 'Actividade florestal', 'animal' => 'Actividade pecuária', 'transport' => 'Transporte e logística'] as $activity => $title) {
if (in_array($activity, $activities, true)) $add($activity, $title, 'undetermined', 'S08', 'Autoridade sectorial competente a identificar para a modalidade declarada',
['Modalidade e dimensão da actividade', 'Fonte e documentação sectorial específica a associar ao dossier'],
'Actividade declarada; a referência do lote não contém o procedimento específico. Não se considera dispensada ou autorizada.', 'https://www.apiex.gov.mz/wp-content/uploads/2024/01/Mozambique-Business-Licensing-Guide.pdf');
}
}
return ['version' => self::VERSION, 'requirements' => $rows,
'fiscal_notice' => 'Localização, corredor, cluster ou projecto âncora não activam benefícios fiscais. O simulador mantém as condições, fonte, período e âmbito próprios; condições ausentes permanecem indeterminadas.'];
}
}
@@ -0,0 +1,59 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
use Illuminate\Support\Facades\DB;
final class InvestmentCorridorContext
{
public function key(Opportunity $record): ?string
{
$name = data_get($record->workflow_context, 'corridor_agribusiness.corridor');
foreach (config('investment_corridors') as $key => $entry) if ($entry['name'] === $name) return $key;
return null;
}
public function provinces(string $key): array
{
$entry = config('investment_corridors.'.$key);
abort_unless(is_array($entry), 422, 'Seleccione um corredor disponível.');
$records = app(InvestmentGeography::class)->publicReferences()->where('location_type', 'province')
->whereIn('source_code', $entry['provinces'])->get(['id', 'name', 'parent_id', 'location_type', 'source_code'])->all();
abort_unless(count($records) === count($entry['provinces']), 503, 'Não foi possível recuperar todas as províncias deste corredor. Tente novamente.');
return $records;
}
public function compatible(string $key, ?string $territory): bool
{
if (!$territory) return true;
$path = app(InvestmentGeography::class)->path($territory);
return $path !== [] && in_array($path[0]->id, array_column($this->provinces($key), 'id'), true);
}
/** Both membership in the selected area and documented public zone coverage are required. */
public function parks(?string $key, ?string $territory): array
{
if (!$key || !$territory) return [];
abort_unless($this->compatible($key, $territory), 422, 'A localização não pertence ao corredor escolhido.');
$selectedPath = array_column(app(InvestmentGeography::class)->path($territory), 'id');
$candidates = app(InvestmentZones::class)->visible()->whereIn('category', ['industrial_park', 'zee', 'zfi'])->orderBy('name')->get();
$result = [];
foreach ($candidates as $zone) {
$ids = DB::table('investment_zone_locations')->where('zone_id', $zone->id)->where('validation_status', 'validated')
->whereIn('scope_type', ['legal_scope', 'administrative', 'site'])
->where(fn($q)=>$q->whereNull('valid_from')->orWhereDate('valid_from','<=',today()))
->where(fn($q)=>$q->whereNull('valid_until')->orWhereDate('valid_until','>=',today()))->get(['geo_location_id','scope_type'])->all();
if ($zone->primary_territory_id) $ids[] = (object)['geo_location_id'=>$zone->primary_territory_id,'scope_type'=>'site'];
foreach ($ids as $link) {
$id=$link->geo_location_id;
if (!$this->compatible($key, $id)) continue;
$path = array_column(app(InvestmentGeography::class)->path($id), 'id');
if (in_array($territory, $path, true) || ($link->scope_type==='legal_scope' && in_array($id, $selectedPath, true))) {
$result[] = $zone->only(['id', 'name', 'category', 'version_no']); break;
}
}
}
return $result;
}
}
@@ -0,0 +1,93 @@
<?php
namespace App\Services;
use App\Http\Controllers\InvestmentPortfolioController;
use App\Models\Opportunity;
use Illuminate\Support\Facades\DB;
/** Multiple identified references in the existing encrypted investment context. */
final class InvestmentOpportunityChoices
{
public function portfolioOrigins(array $ids, int $opportunity): array
{
$origins = [];
foreach (array_unique($ids) as $id) {
$record = InvestmentPortfolioController::visible()->addSelect('version_no')->findOrFail($id);
$kind = null;
if (in_array($opportunity, app(CorridorAgribusinessOpportunities::class)->portfolioOpportunityIds($record), true)) $kind = 'corridor';
foreach (['projects' => 'project_id', 'clusters' => 'cluster_id', 'corridors' => 'corridor_id'] as $relation => $foreign) {
if ($record->$foreign && DB::table('opportunity_'.$relation)->where('opportunity_id', $opportunity)->where($foreign, $record->$foreign)->exists()) $kind = rtrim($relation, 's');
}
abort_unless($kind, 422, 'A associação escolhida não pertence a esta oportunidade.');
$origins[] = ['id' => $record->id, 'title' => $record->title, 'kind' => $kind, 'href' => '/carteira/'.$record->id,
'version' => $record->version_no, 'sha256' => hash('sha256', json_encode([$record->title, $record->source, $record->content], JSON_THROW_ON_ERROR))];
}
return $origins;
}
/** Add explicitly consulted associations without resetting saved geography or deliberate answers. */
public function mergeEntries(array $saved, array $entries): array
{
foreach ($entries as $entry) {
$index = array_search($entry['opportunity']['key'], array_column(array_column($saved, 'opportunity'), 'key'), true);
if ($index === false) { $saved[] = $entry; continue; }
$origins = collect([...($saved[$index]['portfolio_origins'] ?? []), ...($entry['portfolio_origins'] ?? [])])->unique('id')->values()->all();
if ($origins) $saved[$index]['portfolio_origins'] = $origins;
}
return $saved;
}
public function resolve(array $choices, array $previous = [], bool $pending = false): array
{
$result = [];
foreach ($choices as $choice) {
$ref = app(InvestorContext::class)->reference($choice['source']);
abort_unless($ref['kind'] === 'opportunity', 422, 'Seleccione uma ficha de oportunidade.');
$record = Opportunity::findOrFail($ref['id']);
$old = collect($previous)->first(fn ($row) => $row['opportunity']['key'] === $ref['key']);
$origins = $this->portfolioOrigins($choice['portfolio_origins'] ?? array_column($old['portfolio_origins'] ?? [], 'id'), (int) $record->id);
$corridors = app(InvestmentCorridorContext::class);
$corridor = $choice['corridor_key'] ?? $old['corridor_key'] ?? $corridors->key($record);
$provinces = $corridor ? $corridors->provinces($corridor) : [];
$documented = $record->primary_territory_id;
$territory = array_key_exists('territory', $choice) ? $choice['territory'] : ($documented ? 'territory:'.$documented : null);
if (!$territory && count($provinces) === 1) $territory = 'territory:'.$provinces[0]->id;
if ($corridor && $territory) abort_unless($corridors->compatible($corridor, substr($territory, 10)), 422, 'A localização não pertence ao corredor escolhido.');
$previousTerritory = $old['territory']['key'] ?? null;
$newAlternative = $documented && $territory !== 'territory:'.$documented
&& (! $old || ($old['documented_territory_id'] ?? null) !== $documented || $territory !== $previousTerritory);
$corridorChanged = $old && ($old['corridor_key'] ?? $corridors->key($record)) !== $corridor;
$incompatibleOld = $corridorChanged && $previousTerritory && !$corridors->compatible($corridor, substr($previousTerritory, 10));
if (!$pending && ($newAlternative || ($previousTerritory && $territory !== $previousTerritory && !$incompatibleOld))) {
abort_unless(! empty($choice['confirm_location_change']) && mb_strlen(trim($choice['location_reason'] ?? '')) >= 20,
422, 'Uma localização documentada ou já confirmada só muda por escolha explícita, com confirmação e motivo.');
}
$location = $territory ? app(InvestorContext::class)->reference($territory) : null;
abort_unless($location === null || $location['kind'] === 'territory', 422);
$parkKey = array_key_exists('park', $choice) ? $choice['park'] : ($old['park']['key'] ?? null);
$park = $parkKey ? app(InvestorContext::class)->reference($parkKey) : null;
if ($park) {
$eligible = $corridor ? array_column($corridors->parks($corridor, $location['id'] ?? null), 'id') : [];
if (!in_array($park['id'], $eligible, true)) {
abort_if(!empty($choice['park']), 422, 'A zona ou parque não é compatível com a localização desta oportunidade.');
$park = null;
}
abort_unless(!$park || $park['kind'] === 'park', 422);
}
$result[] = ['opportunity' => $ref, 'territory' => $location, ...($origins ? ['portfolio_origins' => $origins] : []),
'park' => $park,
'corridor_key' => $corridor, 'corridor_name' => $corridor ? config('investment_corridors.'.$corridor.'.name') : null,
'allowed_provinces' => array_map(fn($p)=>(array)$p, $provinces),
'territory_path' => $location ? array_map(fn ($node) => \Illuminate\Support\Arr::only((array) $node, ['id', 'name', 'parent_id', 'location_type']), app(InvestmentGeography::class)->path($location['id'], true)) : [],
'activities' => $choice['activities'] ?? ($old['activities'] ?? []),
'documented_territory_id' => $documented, 'location_reason' => $choice['location_reason'] ?? '',
'location_state' => $location ? ($documented && $territory === 'territory:'.$documented ? 'documented' : 'investor_selected') : 'undetermined',
'location_changed_explicitly' => $old && $territory === $previousTerritory ? (bool) ($old['location_changed_explicitly'] ?? false) : (bool) ($choice['confirm_location_change'] ?? false),
'coverage' => data_get($record->workflow_context, 'corridor_agribusiness.corridor'),
'source' => data_get($record->workflow_context, 'corridor_agribusiness.source'),
'source_sha256' => data_get($record->workflow_context, 'corridor_agribusiness.source_sha256')];
}
return $result;
}
}
+200 -14
View File
@@ -27,6 +27,67 @@ final class InvestorContext
public function __construct(private readonly VirtualDesk $desk) {}
public function draft(User $actor, string $id): ?array
{
$case = $this->desk->case($actor, $id, true);
$draft = $this->desk->decode($case->payload)['investor_path']['context_drafts'][(string)$actor->id] ?? null;
return $draft ? [...$draft, 'needs_review' => (int)$draft['version'] !== (int)$case->version] : null;
}
public function saveDraft(User $actor, string $id, array $input): array
{
$case=$this->desk->case($actor,$id,true);
abort_if($case->closed_at,409);
$sequence = (int)($input['draft_sequence'] ?? 0);
$entrySources=Validator::make($input,['entry_sources'=>'sometimes|array|max:200','entry_sources.*'=>'string|max:100'])->validate()['entry_sources']??[];
unset($input['draft_sequence'],$input['entry_sources']);
abort_unless($sequence > 0, 422);
$data = $this->input($input);
if (isset($data['complements'])) app(InvestmentComplements::class)->resolve($data['complements'], $this->state($case)['complements'] ?? []);
foreach ($data['selection'] as $slot=>$key) {
if (!$key) continue;
$ref=$this->reference($key);
abort_unless(in_array($ref['kind'],$slot==='opportunity'?['opportunity','business']:[$slot],true),422,'Referência incompatível com a escolha.');
}
foreach ($data['opportunity_choices'] ?? [] as $choice) {
$ref = $this->reference($choice['source']);
abort_unless($ref['kind'] === 'opportunity', 422);
$record = Opportunity::findOrFail($ref['id']);
app(InvestmentOpportunityChoices::class)->portfolioOrigins($choice['portfolio_origins'] ?? [], (int) $record->id);
$key = $choice['corridor_key'] ?? app(InvestmentCorridorContext::class)->key($record);
if (!empty($choice['territory'])) {
$location = $this->reference($choice['territory']);
abort_unless($location['kind'] === 'territory', 422);
if ($key) abort_unless(app(InvestmentCorridorContext::class)->compatible($key, $location['id']), 422, 'A localização não pertence ao corredor escolhido.');
}
}
if (isset($data['opportunity_choices'])) app(InvestmentOpportunityChoices::class)->resolve($data['opportunity_choices'], $this->state($case)['opportunity_choices'] ?? [], true);
if (!empty($data['selection']['park'])) {
$first=$data['opportunity_choices'][0] ?? null;
$source=$first['source'] ?? $data['selection']['opportunity'] ?? null;
if ($source && str_starts_with($source,'opportunity:')) {
$key=$first['corridor_key'] ?? app(InvestmentCorridorContext::class)->key(Opportunity::findOrFail(substr($source,12)));
if ($key) {
$territory=$first['territory'] ?? $data['selection']['territory'] ?? null;
$ids=app(InvestmentCorridorContext::class)->provinces($key);
$territory=$territory ? substr($territory,10) : (count($ids)===1?$ids[0]->id:null);
$park=$this->reference($data['selection']['park']);
abort_unless($park['kind']==='park' && in_array($park['id'],array_column(app(InvestmentCorridorContext::class)->parks($key,$territory),'id'),true),422,'A zona ou parque não tem enquadramento compatível documentado nesta localização.');
}
}
}
return DB::transaction(function () use ($actor, $id, $data, $sequence, $entrySources) {
$case = $this->desk->case($actor, $id, true, true);
abort_if($case->closed_at || (int)$case->version !== (int)$data['version'], 409, 'O dossier mudou. Recupere os dados antes de continuar.');
$payload = $this->desk->decode($case->payload);
$previous = $payload['investor_path']['context_drafts'][(string)$actor->id] ?? [];
abort_if(($previous['draft_sequence'] ?? 0) > $sequence, 409, 'Existe um rascunho mais recente. Recupere o dossier antes de continuar.');
$payload['investor_path']['context_drafts'][(string)$actor->id] = [...$data, 'draft_sequence' => $sequence, 'entry_sources'=>array_values(array_unique([...($previous['entry_sources']??[]),...$entrySources]))];
DB::table('desk_cases')->where('id', $id)->update(['payload' => $this->desk->encode($payload)]);
return ['saved' => true];
});
}
public function installed(): bool
{
return Schema::hasTable('investor_navigation_preferences');
@@ -51,6 +112,7 @@ final class InvestorContext
}
}
}
if (!empty($context['opportunity_choices']) && !array_key_exists('park', $context['opportunity_choices'][0])) $context['opportunity_choices'][0]['park'] = $context['selection']['park'] ?? null;
$zone = $context['selection']['park'] ?? null;
$context['fields']['investment_regime'] = $zone['fields']['investment_regime'] ?? 'general';
$context['fields']['special_zone_id'] = $zone['id'] ?? '';
@@ -60,6 +122,8 @@ final class InvestorContext
public function dependencyHash(array $selection): string
{
unset($selection['portfolio'], $selection['selection']['portfolio']);
if (isset($selection['opportunity_choices'])) $selection['opportunity_choices'] = array_map(fn($choice)=>Arr::except($choice,['portfolio_origins']),$selection['opportunity_choices']);
return hash('sha256', json_encode(Arr::sortRecursive($selection), JSON_THROW_ON_ERROR));
}
@@ -105,6 +169,18 @@ final class InvestorContext
if ($o->primary_territory_id) {
$fields = [...$fields, ...$this->territoryFields($o->primary_territory_id)];
}
} elseif ($kind === 'portfolio') {
abort_unless(Str::isUuid($id), 422);
$dossier = \App\Http\Controllers\InvestmentPortfolioController::visible()->findOrFail($id);
$title = $dossier->title;
$href = '/carteira/'.$id;
// Documentary coverage is not the investor's chosen implantation.
$version = DB::table('investment_dossiers')->where('id', $id)->value('version_no');
$fields = ['project_title' => $title, 'project_summary' => $dossier->content['description'] ?? $dossier->content['focus'] ?? ''];
$state = 'documented_origin';
$zoneAnalysis = ['source' => $dossier->source, 'documented_sector' => $dossier->content['sector'] ?? null,
'documented_location' => $dossier->content['location'] ?? $dossier->content['region'] ?? null,
'geography' => app(InvestmentRelations::class)->dossier($dossier), 'available_opportunity' => false];
} elseif ($kind === 'business') {
abort_unless(config('existing-business.enabled') && Str::isUuid($id), 404);
$o = ExistingBusiness::published()->with('sector')->findOrFail($id);
@@ -268,7 +344,7 @@ final class InvestorContext
private function input(array $input): array
{
abort_if(array_diff(array_keys($input), ['version', 'selection', 'declarations', 'replace_fields', 'preview_hash', 'operation_key', 'confirm', 'document_links', '_token']), 422, 'Campo de controlo desconhecido.');
abort_if(array_diff(array_keys($input), ['complements', 'opportunity_choices', 'version', 'selection', 'declarations', 'replace_fields', 'preview_hash', 'operation_key', 'confirm', 'document_links', '_token']), 422, 'Campo de controlo desconhecido.');
abort_if(! app(PrivateInvestmentPreparation::class)->available() && (! empty($input['document_links']) || array_intersect(array_keys(is_array($input['declarations'] ?? null) ? $input['declarations'] : []), PrivateInvestmentPreparation::FIELDS)), 409, 'Esta preparação ainda não está disponível neste ambiente. As respostas foram preservadas.');
@@ -280,7 +356,18 @@ final class InvestorContext
$inputRules['declarations.'.$question['key']] = isset($question['options']) ? ['nullable', Rule::in(array_keys($question['options']))] : ['nullable', 'regex:/^\d+(?:\.\d+)?$/D', 'numeric', 'min:0', 'max:999999999999999999'];
}
return Validator::make($input, [...$inputRules, 'version' => 'required|integer|min:1', 'selection' => 'present|array:opportunity,sector,territory,park',
return Validator::make($input, [...$inputRules,
'complements' => 'sometimes|array|max:100', 'complements.*' => 'array:origin,code,target,territory_id',
'complements.*.origin' => 'required|string|max:100', 'complements.*.code' => 'required|string|max:40',
'complements.*.target' => 'nullable|string|max:100', 'complements.*.territory_id' => 'nullable|uuid',
'opportunity_choices' => 'sometimes|array|max:100', 'opportunity_choices.*' => 'array:source,territory,location_reason,confirm_location_change,activities,corridor_key,portfolio_origins,park',
'opportunity_choices.*.portfolio_origins' => 'sometimes|array|max:100', 'opportunity_choices.*.portfolio_origins.*' => 'uuid',
'opportunity_choices.*.corridor_key' => ['sometimes', 'nullable', Rule::in(array_keys(config('investment_corridors')))],
'opportunity_choices.*.activities' => 'sometimes|array', 'opportunity_choices.*.activities.*' => 'string|distinct|in:production,processing,trade,transport,water,forestry,animal',
'opportunity_choices.*.park' => 'sometimes|nullable|string|max:100',
'opportunity_choices.*.source' => 'required|string|distinct|max:100', 'opportunity_choices.*.territory' => 'nullable|string|max:100',
'opportunity_choices.*.location_reason' => 'nullable|string|max:2000', 'opportunity_choices.*.confirm_location_change' => 'sometimes|boolean',
'version' => 'required|integer|min:1', 'selection' => 'present|array:portfolio,opportunity,sector,territory,park',
'selection.*' => 'nullable|string|max:100', 'declarations' => 'nullable|array:project_title,project_summary,currency,expected_start_date,investor_origin,person_type,entity_stage,tax_residency_country,fiscal_residency_country,project_type,maturity_stage,'.implode(',', PrivateInvestmentPreparation::FIELDS), 'declarations.project_title' => 'nullable|string|max:200', 'declarations.project_summary' => 'nullable|string|max:5000',
'declarations.currency' => 'nullable|regex:/^[A-Z]{3}$/', 'declarations.expected_start_date' => 'nullable|date_format:Y-m-d', 'declarations.investor_origin' => 'nullable|in:national,foreign,mixed', 'declarations.person_type' => 'nullable|in:singular,collective,sole_trader,consortium', 'declarations.entity_stage' => 'nullable|in:existing,being_formed', 'declarations.tax_residency_country' => ['nullable', 'string', app(CountryCatalogue::class)->rule()], 'declarations.fiscal_residency_country' => ['nullable', 'string', app(CountryCatalogue::class)->rule()], 'declarations.project_type' => 'nullable|string|max:100', 'declarations.maturity_stage' => 'nullable|string|max:100',
'replace_fields' => 'nullable|array', 'replace_fields.*' => 'string|in:'.implode(',', self::FIELDS)])->validate();
@@ -294,6 +381,7 @@ final class InvestorContext
abort_unless((int) $case->version === $data['version'], 409, 'O dossier mudou; recupere a versão atual.');
app(InvestorPath::class)->view($actor, $id);
$old = $this->state($case);
$complements = array_key_exists('complements', $data) ? app(InvestmentComplements::class)->resolve($data['complements'], $old['complements'] ?? []) : ($old['complements'] ?? []);
$links = $old['preparation_documents'] ?? [];
foreach ($data['document_links'] ?? [] as $key => $document) {
if ($document) {
@@ -303,7 +391,31 @@ final class InvestorContext
unset($links[$key]);
}
}
$choices = $old['opportunity_choices'] ?? [];
if (! array_key_exists('opportunity_choices', $data) && array_key_exists('territory', $data['selection'])) {
$source = $data['selection']['opportunity'] ?? ($old['selection']['opportunity']['key'] ?? null);
if ($source && str_starts_with($source, 'opportunity:')) {
$documented = Opportunity::findOrFail(substr($source, 12))->primary_territory_id;
abort_if($documented && $data['selection']['territory'] !== 'territory:'.$documented, 422,
'Confirme a alternativa territorial por ficha e indique o motivo; a localização documentada foi preservada.');
}
}
if (array_key_exists('opportunity_choices', $data)) {
$choices = app(InvestmentOpportunityChoices::class)->resolve($data['opportunity_choices'], $choices);
$data['selection']['opportunity'] = $choices[0]['opportunity']['key'] ?? null;
// Shared fields concern the first identified opportunity; other sites remain separate.
$data['selection']['territory'] = $choices[0]['territory']['key'] ?? null;
if (array_key_exists('park', $data['opportunity_choices'][0] ?? [])) $data['selection']['park'] = $choices[0]['park']['key'] ?? null;
} elseif (array_key_exists('opportunity', $data['selection']) && $choices !== []) {
abort(422, 'Actualize a selecção identificada de oportunidades; não substitua silenciosamente o conjunto por uma ficha.');
}
$selection = $old['selection'];
foreach ($complements as $complement) {
if (($complement['availability'] ?? '') === 'review_required') continue;
foreach ([$complement['origin']['key'], $complement['target']['key'] ?? ''] as $key) {
if (str_starts_with($key, 'opportunity:')) abort_unless(in_array($key, array_column(array_column($choices, 'opportunity'), 'key'), true), 422, 'Conserve a oportunidade escolhida ou retire explicitamente a sua relação complementar.');
}
}
foreach ($data['selection'] as $slot => $key) {
if ($key === null || $key === '') {
unset($selection[$slot]);
@@ -315,6 +427,16 @@ final class InvestorContext
abort_unless(in_array($ref['kind'], $expected, true), 422, 'Referência incompatível com a dimensão.');
$selection[$slot] = $ref;
}
$corridor = $choices[0]['corridor_key'] ?? (isset($selection['opportunity']) && $selection['opportunity']['kind'] === 'opportunity'
? app(InvestmentCorridorContext::class)->key(Opportunity::findOrFail($selection['opportunity']['id'])) : null);
if ($corridor && isset($selection['territory'])) abort_unless(app(InvestmentCorridorContext::class)->compatible($corridor, $selection['territory']['id']), 422, 'A localização não pertence ao corredor escolhido.');
if ($corridor && isset($selection['park'])) {
$eligible = array_column(app(InvestmentCorridorContext::class)->parks($corridor, $selection['territory']['id'] ?? null), 'id');
if (!in_array($selection['park']['id'], $eligible, true)) {
abort_if(!empty($data['selection']['park']), 422, 'A zona ou parque não tem enquadramento compatível documentado nesta localização.');
unset($selection['park']);
}
}
// A new opportunity may propose its explicitly stored sector; it never matches names.
if (isset($data['selection']['opportunity']) && ! array_key_exists('sector', $data['selection']) && isset($selection['opportunity']['fields']['sector_id'])) {
if (Sector::where('is_active', true)->whereKey($selection['opportunity']['fields']['sector_id'])->exists()) {
@@ -323,7 +445,7 @@ final class InvestorContext
}
$proposed = [];
$origins = [];
foreach (['opportunity', 'sector', 'park', 'territory'] as $slot) {
foreach (['portfolio', 'opportunity', 'sector', 'park', 'territory'] as $slot) {
if (in_array($slot, ['park', 'territory'], true) && array_intersect(array_keys($selection[$slot]['fields'] ?? []), array_keys(InvestmentGeography::FIELDS))) {
foreach (['province_id', 'district_id', 'admin_post_id', 'locality_id', 'province', 'district', 'location'] as $key) {
unset($proposed[$key],$origins[$key]);
@@ -359,22 +481,37 @@ final class InvestorContext
unset($fields[$key],$provenance[$key]);
}
}
if ($corridor) {
foreach (['province_id','district_id','admin_post_id','locality_id','province','district','location'] as $key) {
if (isset($selection['territory']['fields'][$key])) {
$fields[$key]=(string)$selection['territory']['fields'][$key];
$provenance[$key]=Arr::except($selection['territory'],['fields']);
} else unset($fields[$key],$provenance[$key]);
}
$fields['special_zone_id']=$selection['park']['id']??'';
$fields['investment_regime']=$selection['park']['fields']['investment_regime']??'general';
}
$replaced = [];
foreach (array_unique([...array_keys($old['fields']), ...array_keys($fields)]) as $key) {
if (($old['fields'][$key] ?? null) !== ($fields[$key] ?? null)) {
$replaced[] = ['field' => $key, 'before' => $old['fields'][$key] ?? null, 'after' => $fields[$key] ?? null];
}
}
foreach (['opportunity', 'sector', 'territory', 'park'] as $slot) {
foreach (['portfolio', 'opportunity', 'sector', 'territory', 'park'] as $slot) {
if (($old['selection'][$slot] ?? null) !== ($selection[$slot] ?? null)) {
$changed[] = $slot;
}
}
$changedFields = array_column($replaced, 'field');
if ($complements !== ($old['complements'] ?? [])) $changed[] = 'complements';
$choicesChanged = $choices !== ($old['opportunity_choices'] ?? []);
$choiceInputsChanged = array_map(fn($c)=>Arr::except($c,['portfolio_origins']),$choices) !== array_map(fn($c)=>Arr::except($c,['portfolio_origins']),$old['opportunity_choices']??[]);
if ($choiceInputsChanged) $changed = array_values(array_unique([...$changed, 'opportunity', 'territory']));
elseif ($choicesChanged) $changed[] = 'portfolio_origins';
$conditionsChanged = (bool) array_intersect($changedFields, array_diff(self::FIELDS, ['project_title', 'project_summary']));
$dependencyChanged = $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || $conditionsChanged;
$dependencyChanged = $choiceInputsChanged || in_array('complements', $changed, true) || $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || $conditionsChanged;
$privateConditionsChanged = (bool) array_intersect($changedFields, PrivateInvestmentPreparation::FIELDS);
$calculationInputsChanged = $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || (bool) array_intersect($changedFields, array_diff(self::FIELDS, ['project_title', 'project_summary', ...array_diff(PrivateInvestmentPreparation::FIELDS, ['total_investment', 'area_required', 'area_unit'])]));
$calculationInputsChanged = $choiceInputsChanged || $this->dependencyHash($old['selection']) !== $this->dependencyHash($selection) || (bool) array_intersect($changedFields, array_diff(self::FIELDS, ['project_title', 'project_summary', ...array_diff(PrivateInvestmentPreparation::FIELDS, ['total_investment', 'area_required', 'area_unit'])]));
$payload = $this->desk->decode($case->payload);
$results = $payload['investor_path']['results'] ?? [];
$requests = DB::table('desk_requests')->where('case_id', $id)->orderBy('id')->get(['id', 'status', 'protocol', 'version'])->all();
@@ -385,6 +522,7 @@ final class InvestorContext
if ($privateConditionsChanged) {
$steps = array_values(array_unique([...$steps, 'S02', 'S05', 'S06', 'S07']));
}
if (in_array('complements', $changed, true)) $steps = array_values(array_unique([...$steps, 'S02', 'S08']));
$privatePreparation = null;
if (app(PrivateInvestmentPreparation::class)->available()) {
$docs = $this->preparationDocuments($id);
@@ -392,11 +530,12 @@ final class InvestorContext
$afterPreparation = app(PrivateInvestmentPreparation::class)->assess(['fields' => $fields, 'selection' => $selection, 'preparation_documents' => $links], $docs);
$privatePreparation = ['before' => $beforePreparation, 'after' => $afterPreparation];
}
$plan = ['case_id' => $id, 'version' => (int) $case->version, 'revision' => (int) $old['revision'], 'selection' => $selection, 'fields' => $fields, 'provenance' => $provenance,
$plan = ['complements' => $complements, 'opportunity_choices' => $choices, 'case_id' => $id, 'version' => (int) $case->version, 'revision' => (int) $old['revision'], 'selection' => $selection, 'fields' => $fields, 'provenance' => $provenance,
'preparation_documents' => $links, 'private_investment' => $privatePreparation,
'updated' => $replaced, 'maintained' => $kept, 'changed_dimensions' => $changed, 'dependent_results' => (int) $case->user_id === $actor->id && $calculationInputsChanged ? array_map(fn ($r) => ['id' => $r['id'], 'engine' => $r['engine']], $results) : [],
'requests' => $requests, 'review_steps' => $steps, 'dependency_changed' => $dependencyChanged, 'calculation_inputs_changed' => $calculationInputsChanged, 'documents_preserved' => DB::table('desk_documents')->where('case_id', $id)->count(),
'notice' => 'Não confirma incentivos, licenças, disponibilidade de terra, reserva ou autorização. Submissões e decisões anteriores mantêm o conteúdo enviado.'];
$plan['requirements_assessment'] = app(InvestmentContextRequirements::class)->assess(['opportunity_choices' => $choices, 'fields' => $fields]);
$hash = hash_hmac('sha256', json_encode(Arr::sortRecursive([$actor->id, $data, $plan]), JSON_THROW_ON_ERROR), config('app.key'));
return [...$plan, 'preview_hash' => $hash];
@@ -435,14 +574,17 @@ final class InvestorContext
foreach ($plan['review_steps'] as $step) {
$review[$step] = ['revision' => $revision, 'reason' => 'O contexto mudou; reveja os pressupostos e a evidência aplicável.'];
}
$context = ['preparation_documents' => $plan['preparation_documents'], 'preparation_snapshot' => $plan['private_investment']['after'] ?? $before['preparation_snapshot'] ?? null, 'revision' => $revision, 'selection' => $plan['selection'], 'fields' => $plan['fields'], 'provenance' => $plan['provenance'], 'review_steps' => $review,
'dependency_hash' => $this->dependencyHash(['selection' => $plan['selection'], 'fields' => Arr::except($plan['fields'], ['project_title', 'project_summary'])]), 'updated_at' => now()->toIso8601String(), 'updated_by' => $actor->id];
$context = ['opportunity_choices' => $plan['opportunity_choices'], 'preparation_documents' => $plan['preparation_documents'], 'preparation_snapshot' => $plan['private_investment']['after'] ?? $before['preparation_snapshot'] ?? null, 'revision' => $revision, 'selection' => $plan['selection'], 'fields' => $plan['fields'], 'provenance' => $plan['provenance'], 'review_steps' => $review,
'dependency_hash' => $this->dependencyHash([...($plan['opportunity_choices'] !== [] ? ['opportunity_choices' => $plan['opportunity_choices']] : []), ...($plan['complements'] ? ['complements' => $plan['complements']] : []), 'selection' => $plan['selection'], 'fields' => Arr::except($plan['fields'], ['project_title', 'project_summary'])]), 'updated_at' => now()->toIso8601String(), 'updated_by' => $actor->id];
$context['requirements_assessment'] = $plan['requirements_assessment'];
$context['complements'] = $plan['complements'];
if ($plan['calculation_inputs_changed']) {
foreach ($payload['investor_path']['results'] ?? [] as $i => $r) {
$payload['investor_path']['results'][$i] = [...$r, 'context_state' => 'review_required', 'context_invalidated_revision' => $revision, 'context_invalidated_at' => now()->toIso8601String()];
}
}
$payload['investor_path']['context'] = $context;
unset($payload['investor_path']['context_drafts'][(string)$actor->id]);
DB::table('desk_cases')->where('id', $id)->update(['payload' => $this->desk->encode($payload), 'title' => $context['fields']['project_title'] ?? $case->title, 'version' => $case->version + 1, 'updated_at' => now()]);
$this->desk->event($this->desk->case($actor, $id), $actor, 'investment_context_changed', ['before' => $before, 'after' => $context, 'affected_result_ids' => array_column($plan['dependent_results'], 'id'), 'preserved_request_ids' => array_column($plan['requests'], 'id')]);
$result = ['case_id' => $id, 'version' => (int) $case->version + 1, 'revision' => $revision, 'replayed' => false];
@@ -452,12 +594,13 @@ final class InvestorContext
}, 3);
}
public function view(User $actor, string $id): array
public function view(User $actor, string $id, ?string $opportunity = null): array
{
$case = $this->desk->case($actor, $id);
abort_unless($this->desk->owns($actor, $case, false) || $actor->can('manage-portal'), 403);
$ctx = $this->state($case);
$path = app(InvestorPath::class)->view($actor, $id);
$ctx['land_preparation'] = $this->landPreparation($case, $opportunity);
$path = app(InvestorPath::class)->view($actor, $id, $opportunity);
$ctx['path_applicability'] = ['definition_id' => $path['definition_id'], 'definition_version' => $path['definition_version'], 'source_sha256' => $path['source_sha256'],
'steps' => array_values(array_map(fn ($step) => Arr::only($step, ['code', 'title', 'applicability', 'reason', 'state', 'context_review_required']), array_filter($path['steps'], fn ($step) => ! empty($step['branch']))))];
@@ -472,12 +615,19 @@ final class InvestorContext
}
}
$preparation = app(PrivateInvestmentPreparation::class)->available() ? app(PrivateInvestmentPreparation::class)->assess($ctx, $this->preparationDocuments($id)) : null;
$preparation = app(PrivateInvestmentPreparation::class)->available() ? app(PrivateInvestmentPreparation::class)->assess(app(InvestmentConsumerScope::class)->context($ctx, $opportunity), $this->preparationDocuments($id)) : null;
$ctx['preparation_assessment'] = $preparation;
$prefill = $this->prefill($ctx, $opportunity);
$saved = $this->desk->decode($case->payload);
if (!empty($saved['reuse_consent'])) {
$contacts = array_filter(['email' => $saved['email'] ?? null, 'phone' => $saved['profile']['phone'] ?? null], fn($v) => is_string($v) && $v !== '');
$prefill['simulator'] = [...$contacts, ...$prefill['simulator']];
$prefill['land'] = [...$contacts, ...(!empty($saved['name']) ? ['full_name' => $saved['name']] : []), ...$prefill['land']];
}
return ['private_investment' => $preparation, 'preparation_documents' => $this->preparationDocuments($id), 'simulator_context_revision' => $simulatorRevision, 'case' => $path['case'], 'context' => $ctx, 'steps' => array_map(fn ($s) => Arr::only($s, ['code', 'title', 'state', 'context_review_required']), $path['steps']),
'can_write' => $path['canWrite'], 'next' => $path['next'], 'results' => $path['results'], 'requests' => $path['requests'],
'prefill' => $this->prefill($ctx), 'notice' => 'A seleção apoia a preparação e não confirma benefícios, licenças, direitos ou disponibilidade.'];
'prefill' => $prefill, 'notice' => 'A seleção apoia a preparação e não confirma benefícios, licenças, direitos ou disponibilidade.'];
}
public function preparationDocuments(string $id): array
@@ -485,21 +635,57 @@ final class InvestorContext
return DB::table('desk_documents as l')->join('documents as d', 'd.id', '=', 'l.document_id')->where('l.case_id', $id)->whereNull('d.deleted_at')->get(['l.id', 'l.document_id', 'd.file_name', 'd.status', 'd.malware_scan_status', 'd.version_no', 'd.sha256'])->map(fn ($row) => (array) $row)->all();
}
public function prefill(array $ctx): array
public function landPreparation(\stdClass $case, ?string $opportunity = null): array
{
$payload = $this->desk->decode($case->payload);
$ctx = $this->state($case);
$key = app(InvestmentConsumerScope::class)->key($ctx, $opportunity);
$path = $payload['investor_path'] ?? [];
$need = app(InvestmentConsumerScope::class)->facts($payload, $ctx, $key)['land_needed'];
return ['need' => in_array($need, ['yes', 'no'], true) ? $need : 'unknown', 'reason' => $key ? ($path['opportunity_fact_reasons'][$key]['land_needed'] ?? '') : ($path['fact_reasons']['land_needed'] ?? '')];
}
public function prefill(array $ctx, ?string $opportunity = null): array
{
$original = $ctx;
$ctx = app(InvestmentConsumerScope::class)->context($ctx, $opportunity);
$f = $ctx['fields'];
$sim = Arr::except(Arr::only($f, self::FIELDS), ['sector', 'province', 'district', 'location', ...array_diff(PrivateInvestmentPreparation::FIELDS, ['total_investment', 'area_required', 'area_unit'])]);
// Entering this tool from an investment dossier selects the existing investment-analysis route.
// The reconciliation preserves any purpose deliberately chosen in an existing simulator draft.
$sim += ['journey_type' => 'investor', 'journey_type_label' => 'Avaliar o meu investimento', 'purpose' => 'simulate_only', 'purpose_label' => 'Apenas simular'];
if (($ctx['land_preparation']['need'] ?? null) === 'yes') {
$tenure = ['duat' => ['duat', 'DUAT'], 'lease' => ['leased', 'Arrendado']][$f['site_tenure'] ?? ''] ?? null;
if ($tenure) [$sim['land_status'], $sim['land_status_label']] = $tenure;
}
// Human labels travel with the exact existing identifiers, not inferred locations.
foreach (app(InvestmentGeography::class)->publicReferences()->whereIn('id', array_values(Arr::only($f, array_keys(InvestmentGeography::FIELDS))))->get(['id', 'name']) as $place) {
foreach (array_keys(InvestmentGeography::FIELDS) as $key) {
if (($f[$key] ?? null) === $place->id) $sim[$key.'_label'] = $place->name;
}
}
if (! empty($f['sector_id']) && ($sector = Sector::where('is_active', true)->find($f['sector_id']))) $sim['sector_id_label'] = $sector->name;
$zone = $ctx['selection']['park'] ?? null;
$sim['context_applicability_snapshot'] = json_encode([
'version' => 1, 'context_revision' => $ctx['revision'],
'consumer_opportunity' => $ctx['consumer_opportunity']['opportunity']['key'] ?? null,
'portfolio_origin' => $ctx['selection']['portfolio'] ?? null,
'zone' => $zone ? Arr::only($zone, ['id', 'title', 'href', 'version', 'sha256', 'fields', 'analysis']) : null,
'provenance' => $ctx['provenance'],
'opportunity_choices' => $ctx['opportunity_choices'] ?? [],
'complements' => $ctx['complements'] ?? [],
'requirements_assessment' => $ctx['requirements_assessment'] ?? null,
'path' => $ctx['path_applicability'] ?? null,
'land_preparation' => $ctx['land_preparation'] ?? null,
'field_provenance' => array_map(fn($origin) => Arr::only($origin, ['kind', 'title', 'version', 'context_revision']), $ctx['provenance'] ?? []),
'preparation' => isset($ctx['preparation_assessment']) ? Arr::except($ctx['preparation_assessment'], ['questions']) : null,
'fields' => Arr::only($f, ['investor_origin', 'tax_residency_country', 'entity_stage', 'currency', 'expected_start_date', 'investment_regime']),
'notice' => 'Referências e declarações para preparação; sem reconhecimento automático de elegibilidade ou benefício.',
], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
$scoped = app(InvestmentConsumerScope::class)->context($original, $opportunity);
$f = $scoped['fields'];
return ['simulator' => $sim, 'land' => array_filter(['project_reference' => $f['project_title'] ?? null, 'activity' => $f['sector'] ?? null, 'purpose' => $f['project_summary'] ?? null, 'parcels' => [Arr::only($f, array_keys(InvestmentGeography::FIELDS))]], fn ($v) => $v !== null),
'desk' => array_filter(['title' => $f['project_title'] ?? null, 'territory_id' => $f['locality_id'] ?? $f['admin_post_id'] ?? $f['district_id'] ?? $f['province_id'] ?? null, 'location_source' => isset($f['province_id']) ? 'Referência consultada no contexto v'.($ctx['revision'] ?? 0).': '.($f['location'] ?? 'território identificado').'. Não confirma disponibilidade.' : null, 'description' => $f['project_summary'] ?? null, 'sector' => $f['sector'] ?? null, ...Arr::only($f, array_keys(InvestmentGeography::FIELDS))], fn ($v) => $v !== null),
'submission' => array_filter(['currency' => $f['currency'] ?? null, 'sector' => $f['sector'] ?? null, 'objective' => $f['project_summary'] ?? null, 'location' => $f['location'] ?? null], fn ($v) => $v !== null)];
+38 -16
View File
@@ -68,7 +68,7 @@ final class InvestorPath
}
/** @return array<string,mixed> */
public function view(User $actor, string $id): array
public function view(User $actor, string $id, ?string $opportunity = null): array
{
abort_unless($this->available(), 404);
$case = $this->desk->case($actor, $id);
@@ -79,18 +79,26 @@ final class InvestorPath
$payload = $this->desk->decode($case->payload);
$path = $payload['investor_path'] ?? [];
$context = app(InvestorContext::class)->state($case);
$facts = $path['facts'] ?? ['land_needed' => 'unknown', 'external_funding' => 'unknown', 'viability' => 'unknown'];
$scope = app(InvestmentConsumerScope::class);
$opportunity = $scope->key($context, $opportunity);
$allChoices = $context['opportunity_choices'] ?? [];
$facts = $scope->facts($payload, $context, $opportunity);
$factReasons = $opportunity ? ($path['opportunity_fact_reasons'][$opportunity] ?? []) : ($path['fact_reasons'] ?? []);
$context = $scope->context($context, $opportunity);
$records = DB::table('journey_steps')->where('journey_id', $journey->id)->whereNull('deleted_at')->get()->keyBy('step_code');
$steps = [];
foreach ($definition['steps'] as $step) {
$row = $records->get($step['code']);
abort_unless($row !== null, 409, 'Etapa em falta; reparar a instalação sem reconstruir o histórico.');
$detail = $this->desk->decode($row->path_detail);
if ($opportunity && (count($allChoices) > 1 || isset($detail['opportunities'][$opportunity]))) {
$detail = $detail['opportunities'][$opportunity] ?? ['state' => 'not_started'];
}
$value = $step['branch'] ? ($facts[$step['branch']] ?? 'unknown') : 'yes';
$applicable = $value === 'unknown' ? 'undetermined' : ($value === 'no' ? 'not_needed_for_preparation' : 'applicable');
$state = $value === 'no' ? 'dispensed' : $detail['state'];
$steps[] = [...$step, 'id' => $row->id, 'version' => $row->version_no, 'state' => $state, 'saved_state' => $detail['state'],
'applicability' => $applicable, 'reason' => $value === 'no' ? ($path['fact_reasons'][$step['branch']] ?? '') : ($detail['reason'] ?? ''),
'applicability' => $applicable, 'reason' => $value === 'no' ? ($factReasons[$step['branch']] ?? '') : ($detail['reason'] ?? ''),
'detail' => $detail, 'preparation_allowed' => $value !== 'no',
'action_gaps' => []];
}
@@ -143,7 +151,8 @@ final class InvestorPath
$landCase = (int) $case->user_id === $actor->id
? LandAssistanceCase::where('user_id', $actor->id)->latest('updated_at')->get()
->first(fn ($land) => ($land->payload['investor_path_case_id'] ?? null) === $id) : null;
->first(fn ($land) => ($land->payload['investor_path_case_id'] ?? null) === $id
&& (!$allChoices || ($opportunity && ($land->payload['context_opportunity'] ?? null) === $opportunity))) : null;
$preparation = ($owner || $manager) && app(PrivateInvestmentPreparation::class)->available() ? app(PrivateInvestmentPreparation::class)->assess($context, $documents->map(fn ($d) => (array) $d)->all()) : null;
if ($preparation && $preparation['enabled']) {
@@ -152,11 +161,12 @@ final class InvestorPath
return ['private_investment' => $preparation, 'case' => ['id' => $id, 'title' => $case->title, 'version' => $case->version, 'closed' => $case->closed_at !== null],
'journey_id' => $journey->id, 'definition_id' => $version->id, 'definition_version' => $version->version_no, 'source_sha256' => $definition['source_sha256'],
'phases' => $definition['phases'], 'steps' => $steps, 'facts' => $facts, 'fact_reasons' => $path['fact_reasons'] ?? [],
'phases' => $definition['phases'], 'steps' => $steps, 'facts' => $facts, 'fact_reasons' => $factReasons,
'context_opportunity' => $opportunity, 'opportunity_options' => $allChoices,
'fintech' => ($owner || $manager) && (isset($path['fintech']) || collect($path['sector_contexts'] ?? [])->contains(fn ($s) => in_array($s['slug'], ['fintech', 'tecnologias-de-informacao', 'mercado-financeiro'], true)) || collect($path['content_sources'] ?? [])->contains('return_href', '/tech-fintech')) ? app(FintechInvestment::class)->view($payload, $steps) : null,
'canWrite' => $owner && ! $case->closed_at, 'canReview' => $manager && (int) $case->user_id !== $actor->id && ! $case->closed_at,
'next' => $next ? ['code' => $next['code'], 'title' => $next['title'], 'action' => 'Preparar', 'href' => $next['href'] ?? '#'.$next['code']] : null,
'investment_context' => ($owner || $manager) ? $context : null,
'investment_context' => ($owner || $manager) ? [...$context, 'opportunity_choices' => $opportunity ? $context['opportunity_choices'] : $allChoices] : null,
'results' => $results, 'requests' => $requests, 'documents' => $documents,
'zone_contexts' => ($owner || $manager) ? ($path['zone_contexts'] ?? []) : [],
'sector_contexts' => ($owner || $manager) ? ($path['sector_contexts'] ?? []) : [],
@@ -167,25 +177,31 @@ final class InvestorPath
->get(['id', 'title', 'status', 'version_no', 'due_at', 'assignee_user_id']),
'services' => DB::table('desk_service_versions')->where('status', 'published')->orderByDesc('version')->get(['id', 'code', 'definition'])
->unique('code')->values()->map(fn ($s) => ['id' => $s->id, 'title' => json_decode($s->definition, true)['title']]),
'tools' => ['simulator' => (int) $case->user_id === $actor->id ? '/simulador-fiscal?context='.$id.($case->simulation_id ? '&draft='.$case->simulation_id : '') : null,
'desk' => '/balcao-virtual/dossiers/'.$id, 'guidance' => '/balcao-virtual/dossiers/'.$id.'/orientacao',
'tools' => ['simulator' => (int) $case->user_id === $actor->id ? '/simulador-fiscal?context='.$id.($case->simulation_id ? '&draft='.$case->simulation_id : '').($opportunity ? '&opportunity='.urlencode($opportunity) : '') : null,
'desk' => '/balcao-virtual/dossiers/'.$id.($opportunity ? '?opportunity='.urlencode($opportunity) : ''), 'guidance' => '/balcao-virtual/dossiers/'.$id.'/orientacao',
'library' => '/documentos?context='.$id, 'opportunities' => '/oportunidades?context='.$id, 'territory' => '/zonas?context='.$id, 'partners' => '/parcerias/painel?context='.$id,
'land' => (int) $case->user_id === $actor->id ? ($landCase ? '/investidor/terra-duat/'.$landCase->id : '/investidor/terra-duat/novo?context='.$id) : null]];
'land' => ($facts['land_needed'] ?? 'unknown') !== 'no' && (int) $case->user_id === $actor->id ? ($landCase ? '/investidor/terra-duat/'.$landCase->id : '/investidor/terra-duat/novo?context='.$id.($opportunity ? '&opportunity='.urlencode($opportunity) : '')) : null]];
}
/** @param array<string,mixed> $input */
public function facts(User $actor, string $id, array $input): void
{
$data = Validator::make($input, ['version' => 'required|integer|min:1',
$data = Validator::make($input, ['version' => 'required|integer|min:1', 'context_opportunity' => 'nullable|string|max:100',
'land_needed' => ['required', Rule::in(['yes', 'no', 'unknown'])], 'external_funding' => ['required', Rule::in(['yes', 'no', 'unknown'])],
'viability' => ['required', Rule::in(['unknown', 'proceed', 'reformulate', 'archive'])],
'reason' => 'required|string|min:3|max:3000'])->validate();
DB::transaction(function () use ($actor, $id, $data): void {
$case = $this->writable($actor, $id, $data['version']);
$payload = $this->desk->decode($case->payload);
$choice = app(InvestmentConsumerScope::class)->key(app(InvestorContext::class)->state($case), $data['context_opportunity'] ?? null, true);
foreach (['land_needed', 'external_funding', 'viability'] as $key) {
$payload['investor_path']['facts'][$key] = $data[$key];
$payload['investor_path']['fact_reasons'][$key] = $data['reason'];
if ($choice) {
$payload['investor_path']['opportunity_facts'][$choice][$key] = $data[$key];
$payload['investor_path']['opportunity_fact_reasons'][$choice][$key] = $data['reason'];
} else {
$payload['investor_path']['facts'][$key] = $data[$key];
$payload['investor_path']['fact_reasons'][$key] = $data['reason'];
}
}
$this->savePayload($case, $payload);
$this->desk->event($this->desk->case($actor, $id), $actor, 'path_applicability_declared', $data);
@@ -195,7 +211,7 @@ final class InvestorPath
/** @param array<string,mixed> $input */
public function stage(User $actor, string $id, string $code, array $input): void
{
$data = Validator::make($input, ['version' => 'required|integer|min:1', 'state' => ['required', Rule::in(array_diff(InvestorPathDefinition::STATES, ['dispensed']))],
$data = Validator::make($input, ['version' => 'required|integer|min:1', 'context_opportunity' => 'nullable|string|max:100', 'state' => ['required', Rule::in(array_diff(InvestorPathDefinition::STATES, ['dispensed']))],
'reason' => 'required|string|min:3|max:3000', 'action' => ['required', Rule::in(['prepare', 'submit', 'execute', 'operate', 'review', 'record_external'])],
'document_id' => 'nullable|uuid', 'authority' => 'nullable|string|max:200', 'reference' => 'nullable|string|max:300',
'context_revision' => 'nullable|integer|min:0', 'context_reviewed' => 'nullable|boolean', 'decision_date' => 'nullable|date_format:Y-m-d|before_or_equal:today'])->validate();
@@ -203,7 +219,8 @@ final class InvestorPath
$case = $this->desk->case($actor, $id, false, true);
abort_if($case->closed_at, 409);
abort_unless((int) $case->version === $data['version'], 409, 'O dossier mudou; recupere a versão actual.');
$view = $this->view($actor, $id);
$key = app(InvestmentConsumerScope::class)->key(app(InvestorContext::class)->state($case), $data['context_opportunity'] ?? null, true);
$view = $this->view($actor, $id, $key);
$step = $this->findStep($view, $code);
abort_unless($step !== null && $step['preparation_allowed'], 422, 'Etapa dispensada de preparação; altere os pressupostos com fundamento.');
$state = $data['state'];
@@ -238,7 +255,10 @@ final class InvestorPath
}
abort_if($state === 'completed' && ($step['context_review_required'] ?? false) && (! (bool) ($data['context_reviewed'] ?? false) || ($data['context_revision'] ?? -1) !== ($view['investment_context']['revision'] ?? 0)), 422, 'O contexto desta etapa exige nova conferência fundamentada; o registo anterior permanece no histórico.');
$detail = [...$data, 'context_dependency_hash' => $view['investment_context']['dependency_hash'] ?? null, 'fintech_fingerprint' => $view['fintech']['review_fingerprints'][$code] ?? null, 'scope' => $scope, 'actor_id' => $actor->id, 'recorded_at' => now()->toIso8601String()];
DB::table('journey_steps')->where('id', $step['id'])->update(['path_detail' => $this->desk->encode($detail),
$stored = $this->desk->decode(DB::table('journey_steps')->where('id', $step['id'])->value('path_detail'));
if ($key) $stored['opportunities'][$key] = $detail;
else $stored = [...$stored, ...$detail];
DB::table('journey_steps')->where('id', $step['id'])->update(['path_detail' => $this->desk->encode($stored),
'status' => in_array($state, ['completed', 'approved'], true) ? 'completed' : ($state === 'not_started' ? 'pending' : 'active'),
'version_no' => $step['version'] + 1, 'updated_at' => now()]);
DB::table('desk_cases')->where('id', $id)->update(['version' => $case->version + 1, 'updated_at' => now()]);
@@ -267,11 +287,12 @@ final class InvestorPath
abort_unless(is_array($parsed) && ($parsed['version'] ?? null) === 1 && is_array($parsed['data'] ?? null), 422, 'Snapshot financeiro incompatível.');
$payload = $this->desk->decode($case->payload);
$context = app(InvestorContext::class)->state($case);
$opportunity = app(InvestmentConsumerScope::class)->key($context, $economic['context_opportunity'] ?? null, true);
if ($context['revision'] > 0) {
abort_unless(($data['context_revision'] ?? -1) === $context['revision'], 409, 'O contexto mudou; recupere e confira os pressupostos antes de devolver o resultado.');
abort_unless($data['context_reviewed'] ?? false, 422, 'Confirme a revisão dos pressupostos financeiros para este contexto.');
}
$resultKey = hash('sha256', $draft->id.':'.$draft->version_no.':'.$snapshot.':context:'.$context['revision']);
$resultKey = hash('sha256', $draft->id.':'.$draft->version_no.':'.$snapshot.':context:'.$context['revision'].($opportunity ? ':'.$opportunity : ''));
foreach ($payload['investor_path']['results'] ?? [] as $result) {
if ($result['source_key'] === $resultKey) {
return $result;
@@ -280,6 +301,7 @@ final class InvestorPath
abort_unless((int) $case->version === $data['version'], 409, 'Recupere a versão actual do dossier.');
$result = ['id' => (string) Str::uuid(), 'source_key' => $resultKey, 'draft_id' => $draft->id, 'draft_version' => $draft->version_no,
'snapshot_sha256' => $draft->snapshot_sha256, 'financial_snapshot' => $snapshot,
'context_opportunity' => $opportunity,
'currency' => $economic['currency'] ?? null, 'engine' => 'financial-calculators:v1',
'kind' => 'local_calculation_inputs', 'context_state' => 'current', 'context_revision' => $context['revision'], 'context_dependency_hash' => $context['dependency_hash'] ?? app(InvestorContext::class)->dependencyHash([]), 'recorded_at' => now()->toIso8601String()];
$payload['investor_path']['results'][] = $result;
+6 -3
View File
@@ -78,6 +78,9 @@ final class LegacyContent
$image = $this->publicResources()->where('r.id', $adaptation['image_resource_id'])->whereIn('d.media_type', ['image/png', 'image/jpeg', 'image/webp'])->first();
}
}
if ($slug === 'agronegocio') {
$localHtml = app(CorridorAgribusiness::class)->enrich($localHtml, app(CorridorAgribusinessOpportunities::class)->articleLinks());
}
preg_match_all('~href="([^"]+)"~i', $localHtml, $existingLinks);
$alreadyLinked = array_map(fn ($href) => html_entity_decode($href, ENT_QUOTES | ENT_HTML5, 'UTF-8'), $existingLinks[1]);
$relatedArticles = [];
@@ -279,7 +282,7 @@ final class LegacyContent
}
/** Allow presentation markup only. No scripts, styles, events, embeds or remote image execution. */
public function sanitize(string $html): string
public function sanitize(string $html, bool $preserveStructure = false): string
{
$doc = new DOMDocument;
$old = libxml_use_internal_errors(true);
@@ -296,7 +299,7 @@ final class LegacyContent
}
$headingOffset = 2 - (empty($sourceLevels) ? 2 : min($sourceLevels));
$previousHeading = 1;
$clean = function (DOMNode $node) use (&$clean, $doc, $headingOffset, &$previousHeading): void {
$clean = function (DOMNode $node) use (&$clean, $doc, $headingOffset, &$previousHeading, $preserveStructure): void {
foreach (iterator_to_array($node->childNodes) as $child) {
if (! $child instanceof DOMElement) {
continue;
@@ -311,7 +314,7 @@ final class LegacyContent
$node->replaceChild($section, $child);
$child = $section;
}
if (! in_array(strtolower($child->tagName), ['p', 'strong', 'b', 'em', 'i', 'ul', 'ol', 'li', 'br', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'a'], true)) {
if (! in_array(strtolower($child->tagName), array_merge(['p', 'strong', 'b', 'em', 'i', 'ul', 'ol', 'li', 'br', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'a'], $preserveStructure ? ['div', 'span', 'small', 'section', 'table', 'caption', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'figure', 'figcaption'] : []), true)) {
$node->removeChild($child);
continue;
@@ -0,0 +1,55 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
/** Read-only grouping of the existing public catalogue. */
final class OpportunityCorridorExplorer
{
public function groups(array $filters): array
{
$catalogue = app(InvestmentCatalogue::class);
$groups = [];
foreach ($catalogue->query($filters)->get() as $record) {
$context = $catalogue->context($record->id);
$classification = $context['classification'] ?? [];
$corridors = collect($context['corridors'])->mapWithKeys(fn ($c) => ['corridor:'.$c->id => $c->name])->all();
foreach ($classification as $relation) {
if ($relation['target_type'] === 'corridor' && ! in_array($relation['purpose'], ['proximity', 'administrative_boundary'], true)) {
$corridors['corridor:'.$relation['target_id']] = $relation['label'];
}
}
// The approved source names are not aliases for similarly named master records.
$source = data_get($record->workflow_context, 'corridor_agribusiness');
$chain = null;
if (is_array($source) && ($source['source_sha256'] ?? null) === CorridorAgribusinessOpportunities::SOURCE_HASH) {
$corridors['source:'.hash('sha256', $source['corridor'])] = $source['corridor'];
$chain = $source['chain'];
}
$chains = collect($classification)->where('target_type', 'chain')->pluck('label')->all();
if ($chain) $chains[] = $chain;
$stages = collect($classification)->pluck('production_stage')->filter()->unique()->values()->all();
// Keep the source's actual activity description rather than inventing stage labels.
if ($stages === [] && $chain && ! empty($source['summary'])) $stages = [$source['summary']];
$path = collect($context['primary_territory_path'] ?? []);
$province = $path->firstWhere('location_type', 'province')->name ?? $record->province;
$district = $path->firstWhere('location_type', 'district')->name ?? $record->district;
$item = ['id' => $record->id, 'title' => $record->title, 'slug' => $record->slug, 'summary' => $record->summary,
'province' => $province, 'district' => $district, 'chains' => array_values(array_unique($chains)),
'stages' => $stages, 'maturity_label' => $record->maturity_label];
foreach ($corridors ?: ['other' => 'Outras localizações'] as $key => $name) {
$groups[$key] ??= ['id' => $key, 'name' => $name, 'opportunities' => []];
$groups[$key]['opportunities'][$record->id] = $item;
}
}
foreach ($groups as &$group) {
$group['opportunities'] = array_values($group['opportunities']);
$group['count'] = count($group['opportunities']);
$group['locations'] = array_values(array_unique(array_filter(array_map(fn ($r) => implode(' / ', array_filter([$r['province'], $r['district']])), $group['opportunities']))));
}
unset($group);
uasort($groups, fn ($a, $b) => ($a['id'] === 'other' ? 1 : 0) <=> ($b['id'] === 'other' ? 1 : 0) ?: strnatcasecmp($a['name'], $b['name']));
return array_values($groups);
}
}
+3
View File
@@ -27,6 +27,9 @@ class OpportunityManagement
public function values(Opportunity $record): array
{
$base = $record->only(self::FIELDS);
if (data_get($record->workflow_context, 'publication.purpose') === OpportunityPromotion::PURPOSE) {
$base = [...$base, ...($record->workflow_context['promotional_private_base'] ?? [])];
}
$draft = $record->management_draft ? json_decode($record->management_draft, true, 512, JSON_THROW_ON_ERROR) : [];
return [...$base, ...($this->closed($record) ? $draft : array_intersect_key($draft, array_flip(self::PRIVATE_DRAFT_FIELDS)))];
+168
View File
@@ -0,0 +1,168 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
use App\Models\User;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
/** Tempo's promotional disclosure, independent of investment execution approval. */
final class OpportunityPromotion
{
public const PURPOSE = 'promotional_preparation';
public const NOTICE = 'Em preparação. A divulgação não confirma financiamento, disponibilidade de terreno, licenças ou autorização de execução do investimento.';
public function allowed(User $actor, Opportunity $record): bool
{
$access = app(PortalProfileAccess::class);
if ($record->trashed() || $record->owner_user_id === null || ! $access->canView($actor, $record)
|| $access->has($actor, 'auditor') || in_array($record->status, ['archived', 'rejected'], true)) return false;
// Never overwrite a normal approved publication or its workflow decisions.
if ($record->published_at && data_get($record->workflow_context, 'publication.purpose') !== self::PURPOSE) return false;
$internal = $access->internalAssignment($actor, $record->opportunity_category);
return ($internal && $access->promoterRecordScope($actor, $record) && $access->operational($actor, 'edit', $record->id))
|| ($access->scoped($actor, 'publisher', $record->organization_id, $record->opportunity_category)
&& $access->operational($actor, 'publish', $record->id));
}
private function authorize(User $actor, Opportunity $record): void
{
abort_unless($this->allowed($actor, $record), 403, 'A designação e o âmbito existentes não autorizam esta divulgação.');
if (! app(PortalProfileAccess::class)->mfa($actor)) {
throw new \Illuminate\Http\Exceptions\HttpResponseException(response()->json(['message' => 'Confirme a entrada normal com MFA recente para divulgar.'], 403)->header('X-Portal-Reauthentication', 'required'));
}
}
public function editor(User $actor, Opportunity $record): array
{
abort_unless($this->allowed($actor, $record), 403);
$saved = data_get($record->workflow_context, 'promotional_summary', []);
// Only previously public text is recovered automatically. No private contact/document is copied.
$existing = data_get($record->workflow_context, 'publication.purpose') === self::PURPOSE;
$form = $saved['input'] ?? ['title' => $existing ? $record->title : '', 'summary' => $existing ? $record->summary : '',
'description' => $existing ? $record->description : '', 'source_reference' => '', 'edition' => '', 'source_date' => '',
'limitations' => '', 'territory_ids' => $existing ? DB::table('opportunity_locations')->where('opportunity_id', $record->id)->pluck('geo_location_id')->all() : [],
'sector_id' => $record->sector_id];
return ['record' => ['id' => $record->id, 'reference' => $record->reference], 'etag' => app(OpportunityManagement::class)->etag($record),
'initial' => $form, 'publicNow' => $existing && $record->status === 'published',
'reauthenticationRequired' => ! app(PortalProfileAccess::class)->mfa($actor),
'sectors' => \App\Models\Sector::catalog()->orderBy('name')->get(['id', 'name']),
'territories' => app(InvestmentGeography::class)->publicReferences()->orderBy('name')->get(['id', 'name', 'location_type']),
'history' => DB::table('audit_events')->where('source_system', 'tempo-preparation-publication')
->where('after_data->record_id', $record->id)->orderByDesc('occurred_at')->get(['id', 'action', 'actor_user_id', 'occurred_at'])];
}
public function preview(User $actor, Opportunity $record, array $input): array
{
$this->authorize($actor, $record);
$data = Validator::make($input, ['etag' => 'required|string|size:64', 'action' => 'required|in:disclose,withdraw',
'title' => 'required_if:action,disclose|nullable|string|max:255', 'summary' => 'required_if:action,disclose|nullable|string|max:499',
'description' => 'nullable|string|max:6000', 'limitations' => 'nullable|string|max:2500',
'source_reference' => 'nullable|string|max:2000', 'edition' => 'nullable|string|max:150', 'source_date' => 'nullable|date_format:Y-m-d',
'sector_id' => ['nullable', 'integer', Rule::in(\App\Models\Sector::catalog()->pluck('id')->all())],
'territory_ids' => 'sometimes|array|max:30', 'territory_ids.*' => 'required|uuid|distinct',
])->validate();
abort_unless(hash_equals(app(OpportunityManagement::class)->etag($record), $data['etag']), 409, 'A ficha mudou. Reabra antes de preparar outra prévia.');
if ($data['action'] === 'withdraw') abort_unless(data_get($record->workflow_context, 'publication.purpose') === self::PURPOSE, 409);
$paths = [];
foreach ($data['territory_ids'] ?? [] as $id) {
$path = app(InvestmentGeography::class)->path($id, true);
abort_unless(count($path) > 0 && collect($path)->contains('id', $id), 422, 'Seleccione apenas territórios públicos existentes.');
$paths[] = $path;
}
$text = fn ($key) => trim(strip_tags($data[$key] ?? ''));
$body = implode("\n\n", array_filter([$text('description'), self::NOTICE,
'Limitações e lacunas: '.($text('limitations') ?: 'Informação ainda por completar.'),
'Fonte: '.($text('source_reference') ?: 'Não indicada.'), 'Edição: '.($text('edition') ?: 'Não indicada.'),
'Data-base: '.($data['source_date'] ?? 'Não indicada.')]));
$body = OpportunityPublicText::description($record, $body);
$projection = ['title' => $text('title'), 'summary' => $text('summary'), 'description' => $body,
'sector_id' => $data['sector_id'] ?? null, 'maturity_label' => 'Em preparação', 'notice' => self::NOTICE,
'territories' => array_map(fn ($p) => ['id' => end($p)->id, 'label' => implode(' / ', array_column($p, 'name'))], $paths)];
if ($data['action'] === 'disclose') abort_unless($projection['title'] !== '' && $projection['summary'] !== '', 422, 'Indique título e resumo em texto simples.');
if ($data['action'] === 'withdraw') $projection = [...$projection, ...$record->only(['title', 'summary', 'description', 'sector_id', 'maturity_label'])];
$payload = ['actor_id' => $actor->id, 'record_id' => $record->id, 'etag' => $data['etag'], 'action' => $data['action'],
'input' => $data, 'projection' => $projection, 'expires' => now()->addMinutes(15)->timestamp];
return ['action' => $data['action'], 'projection' => $projection, 'token' => Crypt::encryptString(json_encode($payload, JSON_THROW_ON_ERROR)),
'current' => $record->only(['title', 'summary', 'description', 'status']), 'writes' => false];
}
public function confirm(User $actor, int $id, array $input): array
{
$data = Validator::make($input, ['token' => 'required|string|max:300000', 'operation_key' => 'required|uuid',
'confirm' => 'required|accepted', 'reason' => 'required|string|min:10|max:1000'])->validate();
try { $preview = json_decode(Crypt::decryptString($data['token']), true, flags: JSON_THROW_ON_ERROR); }
catch (\Throwable) { abort(422, 'Prévia inválida. Prepare outra prévia.'); }
abort_unless(($preview['actor_id'] ?? null) === $actor->id && ($preview['record_id'] ?? null) === $id, 403);
return DB::transaction(function () use ($actor, $id, $data, $preview) {
DB::select('SELECT pg_advisory_xact_lock(hashtext(?))', ['promotional-operation:'.$data['operation_key']]);
$record = Opportunity::whereKey($id)->lockForUpdate()->firstOrFail();
$this->authorize($actor, $record);
$digest = hash('sha256', $data['token'].'|'.$data['reason']);
$replay = DB::table('audit_events')->where('source_system', 'tempo-preparation-publication')
->where('after_data->operation_key', $data['operation_key'])->first();
if ($replay) {
$prior = json_decode($replay->after_data, true);
abort_unless($prior['record_id'] === $id && (int) $replay->actor_user_id === $actor->id && hash_equals($prior['request_hash'], $digest), 409, 'Chave usada noutra operação.');
return ['id' => $id, 'replayed' => true, 'message' => 'Operação já registada; nenhuma alteração repetida.'];
}
abort_unless(($preview['expires'] ?? 0) >= now()->timestamp, 409, 'A prévia expirou. Prepare outra prévia.');
abort_unless(hash_equals(app(OpportunityManagement::class)->etag($record), $preview['etag']), 409, 'Alteração concorrente: a ficha foi preservada. Reabra e reveja a nova versão.');
$before = $record->getRawOriginal();
$oldLocations = DB::table('opportunity_locations')->where('opportunity_id', $id)->pluck('geo_location_id')->all();
$context = $record->workflow_context ?? [];
if ($preview['action'] === 'withdraw') {
$record->status = 'suspended';
$record->published_at = null;
$context['publication']['visibility'] = 'withdrawn';
$action = 'promotional_summary_withdrawn';
} else {
$p = $preview['projection'];
if ($p['sector_id'] !== null) abort_unless(\App\Models\Sector::catalog()->whereKey($p['sector_id'])->exists(), 409, 'O sector deixou de estar disponível no catálogo. Prepare outra prévia.');
$paths = [];
foreach ($preview['input']['territory_ids'] ?? [] as $territory) {
$path = app(InvestmentGeography::class)->path($territory, true);
abort_unless(count($path) && collect($path)->contains('id', $territory), 409, 'Um território deixou de estar disponível. Prepare outra prévia.');
$paths[] = $path;
}
$currentTerritories = array_map(fn ($path) => ['id' => end($path)->id, 'label' => implode(' / ', array_column($path, 'name'))], $paths);
abort_unless($currentTerritories === $p['territories'], 409, 'O enquadramento territorial mudou. Prepare outra prévia.');
// Preserve the original private draft bytes; retain its former base
// columns in the existing hidden context before projecting public text.
$context['promotional_private_base'] ??= $record->only(OpportunityManagement::FIELDS);
$context['working_state'] ??= app(PortalProfileAccess::class)->state($record);
$context['promotional_summary'] = ['input' => $preview['input'], 'projection' => $p];
$context['publication'] = ['visibility' => 'public', 'purpose' => self::PURPOSE, 'actor_id' => $actor->id,
'at' => now()->toIso8601String(), 'execution_approved' => false, 'private_draft_preserved' => true];
$action = data_get($before, 'status') === 'published' ? 'promotional_summary_updated' : 'promotional_summary_published';
foreach (['title', 'summary', 'description', 'sector_id', 'maturity_label'] as $field) $record->{$field} = $p[$field];
foreach (['promoter_name', 'promoter_type', 'financing_modality', 'expected_impact', 'maturity_level', 'estimated_investment_amount', 'estimated_investment_currency'] as $field) $record->{$field} = null;
$main = $paths[0] ?? [];
$record->primary_territory_id = $main ? end($main)->id : null;
$record->province = collect($main)->firstWhere('location_type', 'province')?->name;
$record->district = collect($main)->firstWhere('location_type', 'district')?->name;
$record->geography_scope = count($paths) > 1 ? 'multiple' : ($main ? 'specific' : 'unspecified');
DB::table('opportunity_locations')->where('opportunity_id', $id)->delete();
foreach ($preview['input']['territory_ids'] ?? [] as $territory) DB::table('opportunity_locations')->insert(['opportunity_id' => $id, 'geo_location_id' => $territory]);
$record->status = 'published';
$record->is_featured = false;
$record->last_validated_at = null;
$record->published_at = now();
}
$record->workflow_context = $context;
$record->management_version++;
$record->save();
DB::table('audit_events')->insert(['source_system' => 'tempo-preparation-publication', 'entity_type' => 'opportunity',
'actor_user_id' => $actor->id, 'action' => $action, 'data_classification' => 'restricted', 'correlation_id' => (string) Str::uuid(),
'before_data' => json_encode(['record_id' => $id, 'record' => $before, 'territories' => $oldLocations], JSON_THROW_ON_ERROR),
'after_data' => json_encode(['record_id' => $id, 'operation_key' => $data['operation_key'], 'request_hash' => $digest,
'reason' => $data['reason'], 'projection' => $preview['projection'], 'execution_approved' => false,
'record' => $record->getRawOriginal()], JSON_THROW_ON_ERROR)]);
return ['id' => $id, 'replayed' => false, 'message' => $preview['action'] === 'withdraw' ? 'Resumo retirado; cadastro e histórico preservados.' : 'Resumo divulgado como Em preparação. Não autoriza execução do investimento.'];
});
}
}
+32
View File
@@ -0,0 +1,32 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
/** Presentation only: originals, editorial fields and audit records remain intact. */
final class OpportunityPublicText
{
public static function description(Opportunity $record, string $text): string
{
$source = data_get($record->workflow_context, 'corridor_agribusiness');
if (! is_array($source) || ($source['source_sha256'] ?? null) !== CorridorAgribusinessOpportunities::SOURCE_HASH) return $text;
$hash = CorridorAgribusinessOpportunities::SOURCE_HASH;
$sourceLine = 'Fonte: '.$source['source'].'; SHA-256 '.$hash;
$paragraphs = explode("\n\n", $text);
$result = [];
foreach ($paragraphs as $paragraph) {
$paragraph = trim($paragraph);
if (in_array($paragraph, [$sourceLine, $sourceLine.'.', 'Edição: Não indicada.', 'Data-base: Não indicada.',
'Limitações e lacunas: '.CorridorAgribusinessOpportunities::LIMITATIONS,
OpportunityPromotion::NOTICE], true)) continue;
if ($paragraph === 'Enquadramento documental: '.$source['corridor'].'.') $paragraph = $source['corridor'].'.';
if ($paragraph === CorridorAgribusinessOpportunities::LIMITATIONS) {
$paragraph = 'A localização exacta, a disponibilidade de terreno e as condições do investimento serão definidas durante a preparação do projecto.';
}
if ($paragraph !== '') $result[] = $paragraph;
}
return implode("\n\n", $result);
}
}
+5 -2
View File
@@ -184,7 +184,9 @@ class PortalProfileAccess
public function canCreate(User $actor, ?string $organization, string $type): bool
{
$included = in_array($type, OpportunityCanonicalContract::BASE_CATEGORIES, true) || app(OpportunityModularProfiles::class)->enabled();
// Draft preparation is allowed within the assigned modality. Executable
// submission support is checked separately by the canonical contract.
$included = in_array($type, OpportunityManagement::CATEGORIES, true);
// This is creation as an authorized Promotor, never an exceptional SU act.
return $included && $this->available() && $this->scoped($actor, 'promoter', $organization, $type) && ! $this->has($actor, 'auditor');
@@ -370,7 +372,8 @@ class PortalProfileAccess
foreach (json_decode($grant->opportunity_types, true, 512, JSON_THROW_ON_ERROR) as $type) {
$key = ($grant->organization_id ?? 'individual').'|'.$type;
if (! isset($seen[$key]) && $this->canCreate($actor, $grant->organization_id, $type)) {
$contexts[] = ['organization_id' => $grant->organization_id, 'type' => $type];
$contexts[] = ['organization_id' => $grant->organization_id,
'organization_name' => $grant->organization_id ? DB::table('organizations')->where('id', $grant->organization_id)->value('name') : null, 'type' => $type];
$seen[$key] = true;
}
}
+287
View File
@@ -0,0 +1,287 @@
<?php
namespace App\Services;
use App\Models\Opportunity;
use App\Models\User;
use Carbon\CarbonImmutable;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
/** Publication of notices; never receives bids or changes the linked investment. */
final class Procurement
{
public const TEXT = ['title', 'reference', 'responsible_unit', 'modality', 'object', 'object_kind', 'quantities', 'financier', 'instrument', 'edition', 'rule_source', 'financing_agreement', 'eligibility', 'requirements', 'proposal_validity', 'guarantee_status', 'guarantees', 'delivery_channel', 'delivery_address', 'delivery_url', 'public_contact', 'dissemination', 'origin_url', 'origin_published_at', 'clarifications_at', 'deadline', 'opening_at', 'timezone', 'minimum_source', 'minimum_edition', 'minimum_modality', 'minimum_day_basis', 'result', 'internal_notes', 'public_reason', 'minimum_working_days', 'minimum_holidays', 'minimum_calendar_source'];
public function available(): bool
{
return config('procurement.enabled') && Schema::hasTable('portal_tenders');
}
public function access(?User $actor): bool
{
if (! $actor || ! $actor->hasVerifiedEmail()) {
return false;
}
$docs = app(DocumentManagementAccess::class);
return ! app(PortalProfileAccess::class)->has($actor, 'auditor') && ($docs->full($actor) || $docs->editorial($actor));
}
public function guard(?User $actor): void
{
abort_unless($this->available(), 404);
abort_unless($this->access($actor), 403, 'Use a autorização editorial já atribuída.');
}
public function references(User $actor): array
{
$this->guard($actor);
$editable = app(DocumentManagementAccess::class)->documents($actor)->select('id');
return ['regimes' => config('procurement.regimes'), 'acts' => config('procurement.acts'),
'organizations' => DB::table('organizations')->whereNull('deleted_at')->orderBy('name')->get(['id', 'name']),
'sectors' => DB::table('sectors')->orderBy('name')->get(['id', 'name']),
'territories' => app(InvestmentGeography::class)->references(true)->orderBy('name')->get(['id', 'name', 'location_type']),
'opportunities' => app(PortalProfileAccess::class)->scope(Opportunity::query(), $actor)->orderBy('title')->get(['id', 'title']),
'projects' => DB::table('projects')->whereNull('deleted_at')->whereIn('data_classification', ['internal', 'public'])->orderBy('name')->get(['id', 'name']),
'documents' => DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->whereNull('d.deleted_at')
->where(fn ($q) => $q->whereIn('d.id', $editable)->orWhere(fn ($p) => $p->where('r.published', true)->where('d.data_classification', 'public')))
->orderBy('r.title')->get(['r.id', 'r.title', 'r.published', 'd.malware_scan_status'])];
}
public function record(string $id): object
{
abort_unless($this->available(), 404);
return DB::table('portal_tenders')->where('id', $id)->firstOrFail();
}
public function save(User $actor, ?string $id, array $input): string
{
$this->guard($actor);
$v = Validator::make($input, ['version' => 'required|integer|min:0', 'reason' => 'required|string|min:20|max:1000', 'draft' => 'required|array']);
$v->validate();
$draft = $this->normalize($actor, $input['draft']);
return DB::transaction(function () use ($actor, $id, $input, $draft) {
$old = $id ? DB::table('portal_tenders')->where('id', $id)->lockForUpdate()->firstOrFail() : null;
abort_unless((int) ($old->version ?? 0) === (int) $input['version'], 409, 'A versão mudou; recupere o concurso antes de guardar.');
$id ??= (string) Str::uuid();
$version = ($old->version ?? 0) + 1;
if ($old) {
DB::table('portal_tenders')->where('id', $id)->update(['draft' => json_encode($draft, JSON_THROW_ON_ERROR), 'version' => $version, 'updated_at' => now()]);
} else {
DB::table('portal_tenders')->insert(['id' => $id, 'draft' => json_encode($draft, JSON_THROW_ON_ERROR), 'version' => $version, 'created_by' => $actor->id, 'created_at' => now(), 'updated_at' => now()]);
}
$this->version($actor, $id, $version, 'draft', $draft, $input['reason'], false);
return $id;
});
}
private function normalize(User $actor, array $input): array
{
$rules = array_fill_keys(self::TEXT, 'nullable|string|max:12000');
$rules = [...$rules, 'regime' => 'nullable|in:state,external,private,other', 'organization_id' => 'nullable|uuid|exists:organizations,id',
'opportunity_id' => 'nullable|integer|exists:opportunities,id', 'project_id' => 'nullable|uuid|exists:projects,id', 'sector_id' => 'nullable|integer|exists:sectors,id',
'territory_id' => 'nullable|uuid|exists:geo_locations,id', 'contact_authorized' => 'boolean', 'minimum_days' => 'nullable|integer|min:0|max:3650',
'lots' => 'array|max:100', 'lots.*' => 'array:code,description,quantities', 'lots.*.code' => 'required|string|max:80|distinct', 'lots.*.description' => 'required|string|max:3000', 'lots.*.quantities' => 'nullable|string|max:1500',
'attachments' => 'array|max:100', 'attachments.*' => 'array:resource_id,public,purpose', 'attachments.*.resource_id' => 'required|integer|exists:portal_resources,id', 'attachments.*.public' => 'required|boolean', 'attachments.*.purpose' => 'required|string|max:150'];
foreach (['origin_url', 'delivery_url', 'rule_source'] as $url) {
$rules[$url] = 'nullable|url:http,https|max:2000';
}
$data = Validator::make($input, $rules)->validate();
if (! empty($data['opportunity_id'])) {
abort_unless(app(PortalProfileAccess::class)->scope(Opportunity::query(), $actor)->whereKey($data['opportunity_id'])->exists(), 403);
}
if (! empty($data['project_id'])) {
abort_unless(DB::table('projects')->where('id', $data['project_id'])->whereNull('deleted_at')->whereIn('data_classification', ['internal', 'public'])->exists(), 422);
}
foreach ($data['attachments'] ?? [] as $attachment) {
$resource = DB::table('portal_resources')->where('id', $attachment['resource_id'])->firstOrFail();
abort_unless($this->publicDocuments()->where('r.id', $resource->id)->exists() || app(DocumentManagementAccess::class)->documents($actor)->where('id', $resource->document_id)->exists(), 403);
}
return $data;
}
public function preview(User $actor, string $id, string $act): array
{
$this->guard($actor);
$record = $this->record($id);
abort_unless(array_key_exists($act, config('procurement.acts')), 422);
$p = json_decode($record->draft, true, 512, JSON_THROW_ON_ERROR);
Validator::make($p, array_fill_keys(['title', 'reference', 'organization_id', 'modality', 'object', 'regime', 'instrument', 'edition', 'rule_source', 'origin_published_at', 'deadline', 'delivery_channel', 'timezone'], 'required'))->validate();
Validator::make($p, ['timezone' => 'timezone', 'object_kind' => 'nullable|in:works,goods,services,mixed,other', 'guarantee_status' => 'nullable|in:required,not_required,unknown'])->validate();
Validator::make($p, ['public_reason' => 'required|string|min:20|max:1000'])->validate();
$dates = [];
foreach (['origin_published_at', 'clarifications_at', 'deadline', 'opening_at'] as $field) {
if (empty($p[$field])) {
continue;
}
$validator = Validator::make([$field => $p[$field]], [$field => 'date_format:Y-m-d\TH:i']);
$validator->validate();
$dates[$field] = CarbonImmutable::createFromFormat('!Y-m-d\TH:i', $p[$field], $p['timezone']);
}
$this->require($dates['deadline']->greaterThan($dates['origin_published_at']), 'deadline', 'Entrega anterior à publicação de origem.');
if (isset($dates['clarifications_at'])) {
$this->require($dates['clarifications_at']->betweenIncluded($dates['origin_published_at'], $dates['deadline']), 'clarifications_at', 'Esclarecimentos fora do período de publicação/entrega.');
}
if (isset($dates['opening_at'])) {
$this->require($dates['opening_at']->greaterThanOrEqualTo($dates['deadline']), 'opening_at', 'A abertura indicada é anterior à entrega.');
}
if (($p['guarantee_status'] ?? '') === 'required') {
$this->require(! empty($p['guarantees']), 'guarantees', 'Descreva a garantia documentada exigida.');
}
if (isset($p['minimum_days'])) {
foreach (['minimum_source', 'minimum_edition', 'minimum_modality', 'minimum_day_basis'] as $field) {
$this->require(! empty($p[$field]), $field, 'Identifique fonte, edição, modalidade e contagem do prazo mínimo.');
}
$this->require($p['minimum_modality'] === $p['modality'], 'minimum_modality', 'A regra indicada pertence a outra modalidade.');
$earliest = $dates['origin_published_at'];
if ($p['minimum_day_basis'] === 'business') {
$this->require(! empty($p['minimum_calendar_source']), 'minimum_calendar_source', 'Identifique a fonte do calendário de dias úteis e feriados.');
$weekdays = array_filter(array_map('trim', explode(',', (string) ($p['minimum_working_days'] ?? ''))));
$this->require(count($weekdays) > 0 && ! array_diff($weekdays, ['1', '2', '3', '4', '5', '6', '7']), 'minimum_working_days', 'Indique os dias de trabalho documentados (1=segunda, 7=domingo).');
$holidays = array_values(array_filter(preg_split('/[\s,;]+/', (string) ($p['minimum_holidays'] ?? ''))));
Validator::make(['dates' => $holidays], ['dates' => 'array|max:1000', 'dates.*' => 'date_format:Y-m-d'])->validate();
for ($left = (int) $p['minimum_days'],$iterations = 0; $left > 0; $iterations++) {
$this->require($iterations < 36500, 'minimum_days', 'Calendário insuficiente para calcular o prazo indicado.');
$earliest = $earliest->addDay();
if (in_array((string) $earliest->isoWeekday(), $weekdays, true) && ! in_array($earliest->format('Y-m-d'), $holidays, true)) {
$left--;
}
}
} else {
$this->require($p['minimum_day_basis'] === 'calendar', 'minimum_day_basis', 'Identifique dias corridos ou calendário de dias úteis documentado.');
$earliest = $earliest->addDays((int) $p['minimum_days']);
}
$this->require($dates['deadline']->greaterThanOrEqualTo($earliest), 'deadline', 'Prazo inferior ao mínimo documentado para esta modalidade/edição/calendário.');
}
$previous = $record->published_version_id ? $this->publishedVersion($record->published_version_id) : null;
$this->require($previous ? $act !== 'initial' : $act === 'initial', 'act', $previous ? 'O anúncio inicial já existe; publique um acto associado.' : 'Publique primeiro o anúncio inicial.');
if ($previous) {
$before = $previous['payload'];
if (($before['deadline'] ?? '') !== $p['deadline'] || ($before['timezone'] ?? '') !== $p['timezone']) {
$this->require($act === 'extension', 'act', 'Uma mudança do prazo exige acto de prorrogação, com data anterior e nova.');
}
if ($act === 'extension') {
$this->require($dates['deadline']->greaterThan(CarbonImmutable::parse($before['deadline'], $before['timezone'])), 'deadline', 'A prorrogação deve avançar o prazo anterior.');
$p['deadline_previous'] = $before['deadline'];
$p['timezone_previous'] = $before['timezone'];
}
$p['extended'] = ($before['extended'] ?? false) || $act === 'extension';
$p['procedural_state'] = $before['procedural_state'] ?? null;
}
if ($act === 'award') {
$p['procedural_state'] = 'results';
}
if ($act === 'cancellation') {
$p['procedural_state'] = 'cancelled';
}
if (in_array($act, ['award', 'cancellation', 'other'], true)) {
$this->require(! empty($p['result']), 'result', 'Descreva o acto ou resultado documentado.');
}
$p['organization_name'] = DB::table('organizations')->where('id', $p['organization_id'])->whereNull('deleted_at')->value('name');
$this->require((bool) $p['organization_name'], 'organization_id', 'Entidade eliminada; recupere a referência.');
$p['sector_name'] = empty($p['sector_id']) ? null : DB::table('sectors')->where('id', $p['sector_id'])->value('name');
$p['territory_name'] = empty($p['territory_id']) ? null : app(InvestmentGeography::class)->references(true)->where('id', $p['territory_id'])->value('name');
if (! empty($p['territory_id'])) {
$this->require((bool) $p['territory_name'], 'territory_id', 'Referência territorial indisponível.');
}
unset($p['internal_notes']);
if (! ($p['contact_authorized'] ?? false)) {
unset($p['public_contact']);
}
$attachments = [];
foreach ($p['attachments'] ?? [] as $item) {
if (! $item['public']) {
continue;
}
$doc = $this->publicDocuments()->where('r.id', $item['resource_id'])->first(['r.id', 'r.title', 'd.sha256', 'd.id as document_id']);
$this->require((bool) $doc, 'attachments', 'Anexo público exige publicação autorizada, scan limpo e direitos sem restrição na biblioteca.');
$attachments[] = [...$item, 'title' => $doc->title, 'sha256' => trim($doc->sha256), 'document_id' => $doc->document_id];
}
$p['attachments'] = $attachments;
if (! empty($p['opportunity_id'])) {
$o = Opportunity::published()->whereKey($p['opportunity_id'])->first(['id', 'title', 'slug']);
$p['opportunity'] = $o ? ['title' => $o->title, 'url' => '/oportunidades/'.$o->slug] : null;
}
if (! empty($p['project_id'])) {
$p['project_name'] = DB::table('projects')->where('id', $p['project_id'])->whereNull('deleted_at')->where('data_classification', 'public')->value('name');
}
unset($p['opportunity_id'],$p['project_id']);
$plan = ['id' => $id, 'version' => $record->version, 'act' => $act, 'payload' => $p];
$plan['hash'] = hash_hmac('sha256', json_encode($plan, JSON_THROW_ON_ERROR), config('app.key'));
return $plan;
}
public function publish(User $actor, string $id, array $input): void
{
$this->guard($actor);
Validator::make($input, ['hash' => 'required|string|size:64', 'act' => 'required|string', 'reason' => 'required|string|min:20|max:1000'])->validate();
DB::transaction(function () use ($actor, $id, $input) {
$record = DB::table('portal_tenders')->where('id', $id)->lockForUpdate()->firstOrFail();
$plan = $this->preview($actor, $id, $input['act']);
abort_unless(hash_equals($plan['hash'], $input['hash']), 409, 'Prévia alterada; reveja o conteúdo antes de publicar.');
abort_unless($input['reason'] === $plan['payload']['public_reason'], 409, 'O motivo público deve coincidir com a prévia.');
$version = $record->version + 1;
$vid = $this->version($actor, $id, $version, $input['act'], $plan['payload'], $input['reason'], true);
DB::table('portal_tenders')->where('id', $id)->update(['published_version_id' => $vid, 'version' => $version, 'updated_at' => now()]);
});
}
private function version(User $actor, string $id, int $version, string $act, array $payload, string $reason, bool $published): string
{
$vid = (string) Str::uuid();
DB::table('portal_tender_versions')->insert(['id' => $vid, 'tender_id' => $id, 'version' => $version, 'act' => $act, 'payload' => json_encode($payload, JSON_THROW_ON_ERROR), 'reason' => $reason, 'actor_id' => $actor->id, 'published_at' => $published ? now() : null, 'created_at' => now()]);
DB::table('audit_events')->insert(['source_system' => 'procurement', 'entity_type' => 'portal_tenders', 'entity_id' => $id, 'actor_user_id' => $actor->id, 'action' => $published ? 'notice_published' : 'tender_draft_saved', 'data_classification' => 'internal', 'after_data' => json_encode(['version_id' => $vid, 'act' => $act, 'reason' => $reason], JSON_THROW_ON_ERROR)]);
return $vid;
}
public function publicDocuments(): Builder
{
return DB::table('portal_resources as r')->join('documents as d', 'd.id', '=', 'r.document_id')->where('r.published', true)->where('r.rights_status', '!=', 'restricted')->where('d.rights_status', '!=', 'restricted')->where('d.data_classification', 'public')->where('d.status', 'active')->whereNull('d.deleted_at')->where('d.malware_scan_status', 'clean')->whereColumn('d.sha256', 'd.malware_scanned_sha256')
->where(fn ($q) => $q->whereNull('d.source_system')->orWhereNotIn('d.source_system', ['opportunity-resources', 'opportunity-image-derivatives']))
->whereNotExists(fn ($q) => $q->selectRaw('1')->from('opportunity_documents as od')->whereColumn('od.document_id', 'd.id')->whereRaw("NOT jsonb_exists(COALESCE(od.payload,'{}'::jsonb),'library_source')"))
->whereNotExists(fn ($q) => $q->selectRaw('1')->from('opportunity_images as oi')->whereColumn('oi.document_id', 'd.id')->whereRaw("NOT jsonb_exists(COALESCE(oi.payload,'{}'::jsonb),'library_source')"));
}
public function publishedVersion(string $id): array
{
$v = DB::table('portal_tender_versions')->where('id', $id)->whereNotNull('published_at')->firstOrFail();
$p = json_decode($v->payload, true, 512, JSON_THROW_ON_ERROR);
foreach ($p['attachments'] ?? [] as $i => $item) {
$p['attachments'][$i]['available'] = $this->publicDocuments()->where('r.id', $item['resource_id'])->where('d.id', $item['document_id'])->where('d.sha256', $item['sha256'])->exists();
}
return ['id' => $v->id, 'version' => $v->version, 'act' => $v->act, 'payload' => $p, 'published_at' => $v->published_at, 'reason' => $v->reason];
}
public function state(array $version): string
{
$p = $version['payload'];
if (in_array($p['procedural_state'] ?? '', ['cancelled', 'results'], true)) {
return $p['procedural_state'];
}
if (CarbonImmutable::parse($p['deadline'], $p['timezone'])->isPast()) {
return 'deadline_ended';
}
return ($p['extended'] ?? false) ? 'extended' : 'open';
}
private function require(bool $condition, string $field, string $message): void
{
if (! $condition) {
throw ValidationException::withMessages([$field => $message]);
}
}
}
+37 -1
View File
@@ -60,9 +60,11 @@ final class SimulationFormDrafts
throw new HttpException(409, 'Já existe um rascunho activo. Carregue-o antes de guardar novas alterações.');
}
if ($case) $data['economic_snapshot'] = $this->landContext($data['economic_snapshot'], $case);
$snapshotHash = hash('sha256', json_encode($this->canonical($data), JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE));
$draft = SimulationFormDraft::query()->create([
'id' => (string) Str::uuid(), 'owner_user_id' => $actorId, 'anonymous_token_hash' => $tokenHash,
'version_no' => 1, 'create_key_hash' => $keyHash, 'create_payload_hash' => $payloadHash, 'snapshot_sha256' => $payloadHash,
'version_no' => 1, 'create_key_hash' => $keyHash, 'create_payload_hash' => $payloadHash, 'snapshot_sha256' => $snapshotHash,
'personal_snapshot' => SimulationFormDraft::encryptSnapshot($data['personal_snapshot']),
'economic_snapshot' => SimulationFormDraft::encryptSnapshot($data['economic_snapshot']),
'expires_at' => $actorId === null ? now()->addDays(30) : null,
@@ -89,6 +91,7 @@ final class SimulationFormDrafts
$this->checkContext($request, $draft);
$this->requireMatch($request, $draft);
$previousEconomic = SimulationFormDraft::decryptSnapshot($draft->economic_snapshot);
$data['economic_snapshot'] = $this->preserveInactiveLandStatus($draft, $data['economic_snapshot'], $previousEconomic, $actorId);
if (($data['economic_snapshot']['reuse_simulation'] ?? null) === 'no') {
unset($data['economic_snapshot']['simulation_sources']);
} elseif (is_array($previousEconomic['simulation_sources'] ?? null)) {
@@ -456,6 +459,39 @@ final class SimulationFormDrafts
return $query;
}
private function preserveInactiveLandStatus(SimulationFormDraft $draft, array $economic, array $previous, ?int $actorId): array
{
if (! $actorId || ! config('investor-path.enabled') || ! app(VirtualDesk::class)->installed()) return $economic;
// Use the real owner-bound dossier even if a request omits its context parameter.
$case = DB::table('desk_cases')->where('simulation_id', $draft->id)->where('user_id', $actorId)->first();
if (! $case) return $economic;
return $this->landContext($economic, $case, $previous);
}
private function landContext(array $economic, \stdClass $case, ?array $previous = null): array
{
$snapshot = json_decode($economic['context_applicability_snapshot'] ?? $previous['context_applicability_snapshot'] ?? '', true);
$key = $economic['context_opportunity'] ?? $snapshot['consumer_opportunity'] ?? null;
$key = app(InvestmentConsumerScope::class)->key(app(InvestorContext::class)->state($case), is_string($key) ? $key : null);
$decision = app(InvestorContext::class)->landPreparation($case, $key);
if ($decision['need'] !== 'yes' && $previous !== null) {
if (array_key_exists('land_status', $previous)) $economic['land_status'] = $previous['land_status'];
else unset($economic['land_status']);
if (isset($previous['selection_labels']['land_status'])) $economic['selection_labels']['land_status'] = $previous['selection_labels']['land_status'];
else unset($economic['selection_labels']['land_status']);
}
$snapshot = json_decode($economic['context_applicability_snapshot'] ?? $previous['context_applicability_snapshot'] ?? '', true);
if (! is_array($snapshot) || ($snapshot['version'] ?? null) !== 1) {
$snapshot = ['version' => 1, 'context_revision' => app(InvestorContext::class)->state($case)['revision']];
}
$snapshot['land_preparation'] = $decision;
$snapshot['consumer_opportunity'] = $key;
if ($key) $economic['context_opportunity'] = $key;
$economic['context_applicability_snapshot'] = json_encode($snapshot, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
return $economic;
}
private function checkContext(Request $request, SimulationFormDraft $draft): void
{
$context = $request->input('context');
+19 -4
View File
@@ -14,16 +14,31 @@ final class TerritoryGeometry
abort_unless($geography->references($management)->where('id', $id)->exists(), 404);
$path = $geography->path($id, $management);
$ids = array_map(fn ($node) => $node->id, $path);
$approved = app(ApprovedAdministrativeBoundaries::class);
$rows = DB::table('geo_geometries as g')->join('geo_locations as l', 'l.id', '=', 'g.geo_location_id')
->whereIn('g.geo_location_id', $ids)->whereNull('g.deleted_at')->whereNull('l.deleted_at')
->whereIn('g.data_classification', $management ? ['internal', 'public'] : ['public'])
->where(function ($query) use ($management, $approved) {
$query->where('g.data_classification', 'public');
$query->orWhere(function ($internal) use ($management, $approved) {
$internal->where('g.data_classification', 'internal');
if (! $management) {
$internal->whereIn('g.id', array_keys($approved->snapshots()));
}
});
})
->whereRaw("g.properties->>'purpose' = 'administrative_boundary'")
->whereIn('g.geometry_type', ['polygon', 'multipolygon'])
->whereRaw('ST_IsValid(g.geom) AND NOT ST_IsEmpty(g.geom) AND ST_SRID(g.geom)=4326')
->orderBy('g.geo_location_id')->orderBy('g.id')->limit(101)
->get(['g.id', 'g.geo_location_id', 'l.name', 'l.location_type', 'g.properties', 'g.data_classification',
DB::raw('ST_AsGeoJSON(ST_SimplifyPreserveTopology(g.geom,0.0001),6) as geometry')]);
$areas = $rows->take(100)->map(function ($row) use ($id) {
DB::raw('ST_AsGeoJSON(ST_SimplifyPreserveTopology(g.geom,0.0001),6) as geometry'),
DB::raw("encode(sha256(ST_AsEWKB(g.geom)),'hex') as geometry_sha256"),
DB::raw("encode(sha256(convert_to(g.properties::text,'UTF8')),'hex') as properties_sha256")]);
if (! $management) {
$rows = $rows->filter(fn ($row) => $row->data_classification === 'public'
|| $approved->allows($row->id, $row->geo_location_id, $row->geometry_sha256, $row->properties_sha256))->values();
}
$areas = $rows->take(100)->map(function ($row) use ($id, $management) {
$source = json_decode($row->properties, true, 512, JSON_THROW_ON_ERROR);
return ['id' => $row->id, 'territory_id' => $row->geo_location_id, 'location_type' => $row->location_type,
@@ -31,7 +46,7 @@ final class TerritoryGeometry
'title' => 'Limite administrativo: '.$row->name, 'purpose' => 'administrative_boundary',
'source_reference' => $source['authority'] ?? null, 'source_date' => $source['source_version'] ?? null,
'source_url' => $source['source_url'] ?? null, 'source_sha256' => $source['source_sha256'] ?? null,
'data_classification' => $row->data_classification, 'legal_currentness' => $source['legal_currentness'] ?? 'not_determined', 'url' => ''];
'data_classification' => $management ? $row->data_classification : 'public', 'legal_currentness' => $source['legal_currentness'] ?? 'not_determined', 'url' => ''];
})->all();
return ['territory_id' => $id, 'territory_registered' => true,
+1 -1
View File
@@ -20,7 +20,7 @@ class TerritoryGeometryImport
private function guard(User $actor, bool $write = false): void
{
abort_unless($actor->can('manage-portal'), 403);
abort_unless($actor->can('manage-portal') || app(ScopedPortalAdministration::class)->administrative($actor), 403);
abort_unless(config('geometry-import.enabled'), 503, 'Importação cartográfica não disponibilizada.');
if (! $write) {
return;
+18 -4
View File
@@ -170,11 +170,11 @@ class VirtualDesk
});
}
public function createRequest(User $actor, string $caseId, string $serviceId, string $clientKey): \stdClass
public function createRequest(User $actor, string $caseId, string $serviceId, string $clientKey, ?string $opportunity = null): \stdClass
{
abort_unless(Str::isUuid($serviceId) && Str::isUuid($clientKey), 422);
return DB::transaction(function () use ($actor, $caseId, $serviceId, $clientKey) {
return DB::transaction(function () use ($actor, $caseId, $serviceId, $clientKey, $opportunity) {
$case = $this->case($actor, $caseId, true, true);
abort_if($case->closed_at, 409, 'Dossier encerrado.');
$service = DB::table('desk_service_versions')->where('id', $serviceId)->where('status', 'published')->first();
@@ -197,7 +197,10 @@ class VirtualDesk
$this->event($case, $actor, 'request_prefill_prepared', ['draft_id' => $draft->id, 'draft_version' => $draft->version_no, 'snapshot_sha256' => $draft->snapshot_sha256, 'fields' => ['title', 'description']]);
}
$context = app(InvestorContext::class)->state($case);
$mapped = app(InvestorContext::class)->prefill($context)['desk'];
if (count($context['opportunity_choices'] ?? []) > 1 && !$opportunity) $payload['description'] = '';
$mapped = app(InvestorContext::class)->prefill($context, $opportunity)['desk'];
if ($opportunity) $payload['context_opportunity'] = $opportunity;
$payload = app(InvestmentConsumerScope::class)->bind($actor, $caseId, $payload);
$serviceFields = json_decode($service->definition, true)['fields'];
foreach (['territory_id' => 'territory_id', 'location_source' => 'location_source', 'title' => 'title', 'description' => 'description', 'sector' => 'sector', 'province_id' => 'province_id', 'district_id' => 'district_id', 'admin_post_id' => 'admin_post_id', 'locality_id' => 'locality_id'] as $field => $source) {
if (isset($serviceFields[$field],$mapped[$source]) && (empty($payload[$field]) || in_array($field, ['title', 'description'], true) && $context['revision'] > 0)) {
@@ -230,6 +233,12 @@ class VirtualDesk
$draft = SimulationFormDraft::query()->whereKey($draft->id)->lockForUpdate()->firstOrFail();
}
$economic = SimulationFormDraft::decryptSnapshot($draft->economic_snapshot);
$contextChoices = app(InvestorContext::class)->state($case)['opportunity_choices'] ?? [];
if (count($contextChoices) > 1) {
$snapshot = json_decode($economic['context_applicability_snapshot'] ?? '{}', true);
$draftChoices = $snapshot['opportunity_choices'] ?? [];
if (count($draftChoices) !== 1 || ($draftChoices[0]['opportunity']['key'] ?? null) !== ($payload['context_opportunity'] ?? null)) return null;
}
$description = (string) ($economic['project_summary'] ?? '');
if (trim($description) === '') {
return null;
@@ -250,7 +259,9 @@ class VirtualDesk
* @return array<string,mixed> */
public function validateFields(array $payload, array $definition, bool $submitting): array
{
$rules = ['payload' => ['required', 'array:'.implode(',', [...array_keys($definition['fields']), 'country', 'declared_origin_country_code', 'context_reuse'])],
$rules = ['payload' => ['required', 'array:'.implode(',', [...array_keys($definition['fields']), 'country', 'declared_origin_country_code', 'context_reuse', 'context_opportunity', 'context_opportunity_snapshot'])],
'payload.context_opportunity' => ['nullable', 'string', 'max:100'],
'payload.context_opportunity_snapshot' => ['nullable', 'string', 'max:200000'],
'payload.context_reuse' => ['nullable', 'string', 'max:10000'],
'payload.country' => ['nullable', 'string', 'max:100', app(CountryCatalogue::class)->legacyCountryRule()],
'payload.declared_origin_country_code' => ['nullable', 'string', app(CountryCatalogue::class)->rule()]];
@@ -334,6 +345,9 @@ class VirtualDesk
}
}
$payload = $this->validateFields($data['payload'], $this->definition($request), $submit);
if ($request->status !== 'returned' || in_array('context_opportunity', json_decode($request->editable_fields ?? '[]', true), true)) {
$payload = app(InvestmentConsumerScope::class)->bind($actor, $request->case_id, $payload, $submit);
}
if ($request->status === 'returned') {
$editable = json_decode($request->editable_fields ?? '[]', true);
$previous = $this->decode($request->payload);
+13
View File
@@ -0,0 +1,13 @@
<?php
// Functional configuration expressly defined by Tempo, 23/10/2026.
// Codes identify the existing national territorial registry; no geometry is inferred.
return [
'pemba-lichinga' => ['name' => 'Corredor de Pemba–Lichinga', 'provinces' => ['02', '01']],
'nacala' => ['name' => 'Corredor de Nacala', 'provinces' => ['03']],
'vale-zambeze' => ['name' => 'Corredor do Vale do Zambeze', 'provinces' => ['05', '04']],
'beira' => ['name' => 'Corredor da Beira', 'provinces' => ['07', '06']],
'limpopo' => ['name' => 'Corredor do Limpopo', 'provinces' => ['09']],
// Tempo's final clarification: both Maputo Province and Maputo City.
'maputo' => ['name' => 'Corredor de Maputo', 'provinces' => ['10', '11']],
];
+170
View File
@@ -0,0 +1,170 @@
[
{
"external_id": "legacy-tempo-post-62413-20170626",
"sha256": "b471c1afd7235f359acdcc16a93088f77e1f988706c8d3c4d4f11c5d560aea47",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-73945-20170731",
"sha256": "2aa0ce0eb305bfdf93e390a978d3694d0fbc0129034077b68cebce418f878415",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-76474-20170808",
"sha256": "8f769aec4715449d056c8c25294060b2ff290ec0893c28e9bdcc4e8092fc75f5",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62414-20170626",
"sha256": "a040c0b7cb95dd7f053f4d13662dd58b2b06453b6fa61a2d531d0257a8db8c17",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62418-20170626",
"sha256": "e8ccafa68f0d1aa80f2e41d9e09f7b13e7c653a8472a731798cfd5e04ce2963e",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-75002-20170804",
"sha256": "7b6fbd998be2b47b96e9a4724560c192c502709fa308d6590c0797ddcdb10544",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-73246-20170728",
"sha256": "430ee8674c71104fc126bed2911d676f150ac623857a1ada75662987fd9ac390",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-77232-20170811",
"sha256": "27544d3127803b7495bef9fd633147d0225d8c31816c4d59ed05a2edd59de070",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62416-20170626",
"sha256": "ac575ce340571192552c89b63f0bd62a84dbc47828e6930133af5ff70e249319",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62929-20170627",
"sha256": "488017b062c6760659d9147b7f12aea4afd8d824121adb9462e2c7a2ae58437b",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62649-20170626",
"sha256": "38a858713472759a2d20a308bdd9d8afa9cfb76dcaf8d11ca709e89261573e42",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62739-20170626",
"sha256": "5870fc0fad9bb7af537b7b1468151cde138b1b886ce846c7be25647b630245dd",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62854-20170627",
"sha256": "44b1ba9d593bb625cf53de8909e78eb0b3129742c3ec9d58ec68c984e8930bce",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-63128-20170627",
"sha256": "74be8f29e5053f53ab1a39a2f63208145c30f23357ca6d78b637dd02bf9c1fb4",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-63181-20170627",
"sha256": "3d0f9ac14d36156d8178e33f8616d6406f31ea4cd69c8308cbf4227586d7ccb3",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-63146-20170627",
"sha256": "542353466cc6d82b651619c495f138b0576a4be41d21aad194ae2005050cb1bc",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-62688-20170626",
"sha256": "a210a789b06d425822f4124f74226a2b27246c086c5ec5f041f1b2237d7c2b65",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-63248-20170628",
"sha256": "6c30e61197b8568332af6d9b19bbba7ad8665b3873bb031a8c8aedd41536b060",
"kind": "historico_noticioso",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173220-20260616",
"sha256": "5b76c3d84dcf7f9a489686d90e3857ae6536705c918e841310bb42b354e80976",
"kind": "setorial",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173222-20260616",
"sha256": "e64d7063d1ac4dda028c97e1ba64938d2a9e426a0b630c57ee5df52a41312cc7",
"kind": "setorial",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173482-20260915",
"sha256": "6f888e133a779c719073246f89bcae150198e5897c0e7d9b7ba75f54c54a7830",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173484-20260915",
"sha256": "297df455a9c6fd1f0ab7ca7bbe124ce483c86fe55be26baa695f03089b3ac049",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173478-20260915",
"sha256": "d4e320ed99dd9d53d205e47932f73651976d43081d5d39f2bfc2996901408644",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173480-20260915",
"sha256": "c3ee6401eda5b582c61969b5e3b74fdf26ef34ca481b1aca8c4c309d845147ae",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173476-20260915",
"sha256": "72fbf28391db4804e0637b64e7f59e9fa597812a2681b4562dc3d6dfb4093a30",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173470-20260915",
"sha256": "26feeae6b8d04972c7a64ee360583cccdcaeb4b0d8795fd7bc2fd3c38866cc19",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173474-20260915",
"sha256": "9fa741a17b746bfa2f3ce7b6ce1d2bb34d3a35d3b58330b0554f9e0a6844f049",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
},
{
"external_id": "legacy-tempo-post-173463-20260915",
"sha256": "4f34b7bac4b3030c0614844d379f6e3cfad1b7f6ea3db575a58c33ae033b0e73",
"kind": "trabalho_domestico",
"original_image_sha256": "28f41f12e10ab34545d8e432f6e8c74f86960e17e0c4a9956f514bcde4881eaa"
}
]
+1 -1
View File
@@ -23,7 +23,7 @@ return [
'opportunity_other_qa_subtypes' => [],
'operator_name' => env('PORTAL_OPERATOR_NAME'),
// Tempo, 19/10/2026: institutional contact; commercial department remains separate.
'institutional_contact_email' => env('PORTAL_INSTITUTIONAL_CONTACT_EMAIL', 'info@tempo.co.mz'),
'institutional_contact_email' => env('PORTAL_INSTITUTIONAL_CONTACT_EMAIL', 'comercial@tempo.co.mz'),
'support' => [
'email' => env('PORTAL_SUPPORT_EMAIL'),
'phone' => env('PORTAL_SUPPORT_PHONE'),
+7
View File
@@ -0,0 +1,7 @@
<?php
return [
'enabled' => (bool) env('PROCUREMENT_ENABLED', false),
'regimes' => ['state' => 'Contratação pública do Estado', 'external' => 'Financiamento externo', 'private' => 'Concurso privado', 'other' => 'Outro regime documentado'],
'acts' => ['initial' => 'Anúncio inicial', 'clarification' => 'Esclarecimento', 'correction' => 'Rectificação', 'extension' => 'Prorrogação', 'award' => 'Resultado / adjudicação', 'cancellation' => 'Cancelamento', 'other' => 'Outro acto'],
];
@@ -0,0 +1,181 @@
{
"source": "investimentos nos corredores.docx",
"source_sha256": "1473b06c48aa234e771660e3f2a51b9d2e4e1943bd52d878e0ae854ee6657055",
"introduction": "Os corredores de desenvolvimento integram cadeias de valor prioritárias que podem ser apresentadas no portal InvesteMoz como oportunidades concretas de investimento na produção, transformação, logística e comercialização. Para cada corredor, são destacadas abaixo as oportunidades associadas aos produtos com maior potencial.",
"segments": [
"Produção primária e fornecimento de insumos",
"Processamento e transformação agro-industrial",
"Armazenagem, cadeia de frio e logística",
"Embalagem, distribuição, comercialização e exportação",
"Infraestruturas e serviços de apoio às cadeias de valor"
],
"groups": [
{
"name": "Corredor de Pemba–Lichinga",
"opportunities": [
{
"chain": "Batata, trigo, feijão, milho e soja",
"description": "Produção comercial, armazenamento e processamento de batata, trigo, feijão, milho e soja."
},
{
"chain": "Algodão",
"description": "Descaroçamento, fiação e produção de óleo e derivados de algodão."
},
{
"chain": "Sésamo",
"description": "Limpeza, prensagem, embalagem e exportação de sésamo."
},
{
"chain": "Florestas",
"description": "Viveiros, plantações comerciais, madeira processada e produtos florestais sustentáveis."
},
{
"chain": "Avicultura",
"description": "Produção de rações, incubação, criação, abate e cadeia de frio para avicultura."
}
]
},
{
"name": "Corredor de Nacala",
"opportunities": [
{
"chain": "Mandioca",
"description": "Produção e transformação de mandioca em farinha, amido e outros derivados."
},
{
"chain": "Milho, amendoim e sésamo",
"description": "Produção, armazenagem e processamento de milho, amendoim e sésamo."
},
{
"chain": "Algodão",
"description": "Descaroçamento e transformação de algodão."
},
{
"chain": "Frutas e caju",
"description": "Pomares, processamento, embalagem e exportação de frutas e caju."
},
{
"chain": "Florestas",
"description": "Silvicultura comercial, madeira processada e produtos florestais."
},
{
"chain": "Avicultura",
"description": "Produção de rações, criação, abate e distribuição de produtos avícolas."
}
]
},
{
"name": "Corredor do Vale do Zambeze",
"opportunities": [
{
"chain": "Arroz",
"description": "Produção irrigada, moagem, embalagem e comercialização de arroz."
},
{
"chain": "Milho e batata",
"description": "Produção, secagem, armazenagem e transformação de milho e batata."
},
{
"chain": "Sésamo",
"description": "Limpeza, prensagem e exportação de sésamo."
},
{
"chain": "Algodão",
"description": "Descaroçamento e transformação de algodão."
},
{
"chain": "Avicultura",
"description": "Produção de rações, incubação, criação e abate de aves."
},
{
"chain": "Bovinos e caprinos",
"description": "Criação, engorda, abate, processamento de carne e cadeia de frio para bovinos e caprinos."
}
]
},
{
"name": "Corredor da Beira",
"opportunities": [
{
"chain": "Milho, trigo e arroz",
"description": "Produção, silos, moagem e processamento de milho, trigo e arroz."
},
{
"chain": "Soja",
"description": "Esmagamento de soja, produção de óleo vegetal e fabrico de rações."
},
{
"chain": "Hortícolas",
"description": "Produção irrigada, conservação, embalagem e distribuição de hortícolas."
},
{
"chain": "Sésamo",
"description": "Limpeza, prensagem e exportação de sésamo."
},
{
"chain": "Açúcar",
"description": "Produção e refinação de açúcar e aproveitamento de subprodutos."
},
{
"chain": "Florestas",
"description": "Plantações comerciais, processamento de madeira e produtos florestais."
},
{
"chain": "Carne bovina",
"description": "Criação, engorda, abate, processamento e cadeia de frio para carne bovina."
}
]
},
{
"name": "Corredor do Limpopo",
"opportunities": [
{
"chain": "Arroz",
"description": "Produção irrigada, moagem, embalagem e comercialização de arroz."
},
{
"chain": "Hortícolas",
"description": "Produção em estufas e campo aberto, conservação, embalagem e distribuição de hortícolas."
},
{
"chain": "Carne vermelha",
"description": "Criação, engorda, abate, processamento e cadeia de frio para carne vermelha."
},
{
"chain": "Avicultura",
"description": "Produção de rações, incubação, criação, abate e distribuição de produtos avícolas."
},
{
"chain": "Infraestruturas e serviços de apoio",
"description": "Infraestruturas de irrigação, armazenagem, transporte refrigerado e centros de comercialização."
}
]
},
{
"name": "Corredor de Maputo",
"opportunities": [
{
"chain": "Arroz",
"description": "Produção irrigada, moagem, embalagem e fornecimento de arroz aos mercados urbanos e regionais."
},
{
"chain": "Hortícolas",
"description": "Produção, conservação, embalagem, transformação e distribuição de hortícolas."
},
{
"chain": "Carne vermelha",
"description": "Criação, engorda, abate, processamento, distribuição e exportação regional de carne vermelha."
},
{
"chain": "Avicultura",
"description": "Produção de rações, incubação, criação, abate e comercialização de produtos avícolas."
},
{
"chain": "Infraestruturas e serviços de apoio",
"description": "Plataformas logísticas, centros de distribuição, cadeia de frio e serviços de exportação."
}
]
}
],
"sector": "Agronegócio"
}
@@ -0,0 +1,50 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('portal_tenders', function (Blueprint $t) {
$t->uuid('id')->primary();
$t->jsonb('draft');
$t->unsignedInteger('version')->default(1);
$t->uuid('published_version_id')->nullable();
$t->foreignId('created_by')->constrained('users')->restrictOnDelete();
$t->timestampsTz();
});
Schema::create('portal_tender_versions', function (Blueprint $t) {
$t->uuid('id')->primary();
$t->foreignUuid('tender_id')->constrained('portal_tenders')->restrictOnDelete();
$t->unsignedInteger('version');
$t->string('act', 24);
$t->jsonb('payload');
$t->text('reason');
$t->foreignId('actor_id')->constrained('users')->restrictOnDelete();
$t->timestampTz('published_at')->nullable();
$t->timestampTz('created_at')->useCurrent();
$t->unique(['tender_id', 'version']);
});
Schema::create('portal_tender_watches', function (Blueprint $t) {
$t->foreignUuid('tender_id')->constrained('portal_tenders')->restrictOnDelete();
$t->foreignId('user_id')->constrained('users')->restrictOnDelete();
$t->uuid('seen_version_id')->nullable();
$t->timestampsTz();
$t->primary(['tender_id', 'user_id']);
});
}
public function down(): void
{
if (DB::table('portal_tenders')->exists()) {
throw new RuntimeException('Preserve procedures, acts and history; use a reviewed data reversal.');
}
Schema::dropIfExists('portal_tender_watches');
Schema::dropIfExists('portal_tender_versions');
Schema::dropIfExists('portal_tenders');
}
};
+19
View File
@@ -0,0 +1,19 @@
FROM node:22-bookworm AS node
FROM php:8.4-cli-bookworm
RUN apt-get update \
&& apt-get install -y --no-install-recommends libpq-dev libzip-dev unzip git curl \
&& docker-php-ext-install -j"$(nproc)" pdo_pgsql pgsql zip \
&& rm -rf /var/lib/apt/lists/*
COPY --from=node /usr/local/bin/node /usr/local/bin/node
COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules
RUN ln -s ../lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
&& ln -s ../lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx \
&& ln -s ../lib/node_modules/corepack/dist/corepack.js /usr/local/bin/corepack
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --no-audit --no-fund
COPY . .
+13
View File
@@ -0,0 +1,13 @@
FROM php:8.4-cli-bookworm
RUN apt-get update \
&& apt-get install -y --no-install-recommends libpq-dev libzip-dev unzip git curl \
&& docker-php-ext-install -j"$(nproc)" pdo_pgsql pgsql zip \
&& rm -rf /var/lib/apt/lists/*
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
COPY composer.json composer.lock ./
RUN composer install --no-interaction --prefer-dist --no-progress --no-scripts
COPY . .
RUN composer dump-autoload --optimize
@@ -0,0 +1,176 @@
<!DOCTYPE html>
<html lang="pt">
<head>
<meta charset="utf-8">
<title>InvestMoz — Levantamento funcional e modelos</title>
<style>
@page { size: A4; margin: 18mm 17mm 18mm 17mm; }
body { font-family: Aptos, Calibri, Arial, sans-serif; color:#1d2939; font-size:10.5pt; line-height:1.42; }
h1 { color:#123d68; font-size:26pt; margin:0 0 8pt; }
h2 { color:#123d68; font-size:17pt; border-bottom:2px solid #13a789; padding-bottom:5pt; margin-top:24pt; }
h3 { color:#145b82; font-size:13pt; margin:17pt 0 5pt; }
p { margin:5pt 0 8pt; }
.cover { padding-top:100pt; page-break-after:always; }
.kicker { text-transform:uppercase; letter-spacing:2px; color:#138a77; font-weight:bold; }
.subtitle { color:#52657a; font-size:15pt; }
.meta { margin-top:35pt; padding:12pt; background:#eff6fb; border-left:4px solid #1d75bd; }
.callout { background:#fff7e8; border-left:4px solid #ee9b20; padding:9pt 12pt; margin:12pt 0; }
.note { color:#52657a; font-size:9pt; }
table { border-collapse:collapse; width:100%; margin:8pt 0 14pt; font-size:9.2pt; }
th { background:#123d68; color:white; text-align:left; padding:6pt; }
td { border:1px solid #cbd5e1; padding:5pt 6pt; vertical-align:top; }
tr:nth-child(even) td { background:#f5f8fb; }
.diagram { text-align:center; margin:12pt 0; page-break-inside:avoid; }
.diagram svg { width:100%; height:auto; }
.legend { color:#52657a; font-size:9pt; }
.small { font-size:9pt; }
.pagebreak { page-break-before:always; }
ul { margin-top:3pt; }
</style>
</head>
<body>
<section class="cover">
<p class="kicker">Documento de análise funcional</p>
<h1>InvestMoz</h1>
<p class="subtitle">Levantamento profissional do projecto, casos de uso reais, actores e diagramas</p>
<div class="meta"><b>Data:</b> 9 de Outubro de 2026<br><b>Âmbito:</b> aplicação Laravel/React e documentação do repositório Investidor-V2<br><b>Versão:</b> 1.0 · análise do código e dos documentos disponíveis</div>
<p style="margin-top:42pt;font-size:13pt">Portal de descoberta de oportunidades e serviços de investimento, ligado a fluxos autenticados de candidatura, tratamento institucional, evidência documental e acompanhamento.</p>
<p class="note" style="margin-top:55pt">Documento técnico-funcional. A presença de uma rota, tabela, job ou descrição não demonstra, por si só, activação em produção.</p>
</section>
<h2>1. Sumário executivo</h2>
<p>O InvestMoz é uma plataforma digital que aproxima investidores, promotores e instituições. A experiência começa no portal público, onde se consultam sectores, oportunidades, negócios existentes, território, zonas e serviços. A partir daí, a pessoa pode manifestar interesse, iniciar uma simulação ou pedir apoio. Os percursos que exigem continuidade passam para a área autenticada, onde se mantêm perfil, rascunhos, candidaturas, anexos e comunicação.</p>
<p>Do lado institucional, os pedidos podem ser revistos e acompanhados por CRM local, tarefas, revisões e eventos. A plataforma também contém domínios de catálogo territorial, zonas de investimento, documentação, governação fiscal, educação e competências, assistência de terra, parcerias, balcão virtual e IA baseada em fontes.</p>
<div class="callout"><b>Leitura funcional:</b> trata-se de uma plataforma de encaminhamento e gestão de jornadas de investimento, e não apenas de um catálogo de anúncios. A camada pública informa e capta pedidos; a camada autenticada conserva o trabalho; a camada de gestão analisa, valida e decide segundo permissões e evidência.</div>
<p>O README descreve a base inicial de sectores, oportunidades e manifestações de interesse. Rotas, controladores, migrations e documentação de domínio mostram uma solução mais abrangente. O levantamento de casos detalhados tem 24 casos de uso; este relatório acrescenta cenários concretos, diagramas UML/ER e a leitura da frequência dos eventos.</p>
<h2>2. O que o projecto faz</h2>
<table><tr><th>Capacidade</th><th>Valor para o utilizador</th><th>Exemplos de dados</th></tr>
<tr><td>Descoberta pública</td><td>Encontrar oportunidades, negócios, sectores, serviços e referências territoriais.</td><td>sectors, opportunities, existing_businesses, investment_zones</td></tr>
<tr><td>Captação de interesse</td><td>Enviar manifestação associada a uma oportunidade ou negócio, com consentimento.</td><td>interest_requests, consents, receipts</td></tr>
<tr><td>Jornada do investidor</td><td>Guardar itens, criar dossier/submissão, anexar documentos e acompanhar mensagens.</td><td>investment_submissions, revisions, messages, attachments</td></tr>
<tr><td>Tratamento institucional</td><td>Qualificar pedidos, atribuir responsável, criar tarefas e acompanhar a negociação.</td><td>leads, contacts, crm_opportunities, tasks, activities</td></tr>
<tr><td>Planeamento territorial</td><td>Relacionar projectos, clusters, corredores, localizações e zonas.</td><td>projects, economic_clusters, development_corridors, geo_locations</td></tr>
<tr><td>Documentos e evidência</td><td>Preservar origem, versões, hash, scan, classificação e autorização de divulgação.</td><td>documents, document_versions, malware_scans, associations</td></tr>
<tr><td>Simulação e regras fiscais</td><td>Guardar rascunhos, executar simulações com parâmetros/fontes rastreáveis e governar versões.</td><td>simulations, scenarios, results, tax_rule_versions, legal_sources</td></tr>
<tr><td>Serviços complementares</td><td>Registar educação, assistência de terra, parcerias, balcão virtual e apoio com IA.</td><td>training needs, land cases, partnerships, desk cases, ai runs</td></tr></table>
<h2>3. Actores e fronteiras de acesso</h2>
<table><tr><th>Actor</th><th>O que pretende</th><th>Zona típica</th></tr>
<tr><td>Visitante</td><td>Consultar conteúdos públicos e iniciar interesse, apoio ou simulação.</td><td>Portal público</td></tr>
<tr><td>Investidor / utilizador registado</td><td>Manter perfil, favoritos, rascunhos, submissões, anexos e mensagens.</td><td>Área autenticada</td></tr>
<tr><td>Promotor / proprietário de negócio</td><td>Registar ou actualizar negócio e responder a pedidos de informação.</td><td>Área autenticada e workflow de revisão</td></tr>
<tr><td>Gestor de portal / CRM</td><td>Rever interesses, qualificar leads, atribuir tarefas e gerir conteúdos.</td><td>Gestão interna</td></tr>
<tr><td>Gestor territorial</td><td>Manter projectos, relações, zonas, geometria e referências territoriais.</td><td>Gestão interna</td></tr>
<tr><td>Revisor documental / gestor fiscal</td><td>Validar metadados, evidência, versões e regras sob as respectivas funções.</td><td>Gestão restrita</td></tr>
<tr><td>Agente de serviço / parceiro institucional</td><td>Tratar casos ou colaborar em parcerias e salas.</td><td>Serviços e colaboração</td></tr>
<tr><td>Administrador / worker</td><td>Gerir segurança/configuração ou executar trabalho assíncrono autorizado.</td><td>Administração / sistema</td></tr></table>
<p class="note">Os nomes acima são papéis funcionais consolidados. A autorização efectiva depende das policies, middleware, MFA, configuração e permissões em vigor.</p>
<h2>4. Diagrama de casos de uso com actores</h2>
<p>O diagrama destaca actores (“bonecos”) e os principais serviços que usam. As associações mostram interacções típicas; não indicam que todos os serviços estejam activos na mesma instalação.</p>
<div class="diagram">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1050 610" role="img" aria-label="Diagrama UML de casos de uso InvestMoz com actores">
<defs><style>.actor{stroke:#173b60;stroke-width:3;fill:none}.line{stroke:#728397;stroke-width:1.7}.uc{fill:#eef6fc;stroke:#2778b8;stroke-width:2}.txt{font:16px Arial;fill:#17324d}.label{font:bold 15px Arial;fill:#17324d}.boundary{fill:#fbfdff;stroke:#9bb0c3;stroke-width:2;stroke-dasharray:8 5}</style></defs>
<rect x="220" y="22" width="795" height="558" rx="14" class="boundary"/><text x="245" y="52" class="label">Sistema InvestMoz</text>
<!-- stick actors -->
<g class="actor"><circle cx="95" cy="115" r="17"/><path d="M95 132v65m-30-38h60m-30 38-27 42m27-42 27 42"/></g><text x="50" y="245" class="label">Visitante</text>
<g class="actor"><circle cx="95" cy="335" r="17"/><path d="M95 352v65m-30-38h60m-30 38-27 42m27-42 27 42"/></g><text x="37" y="465" class="label">Investidor</text>
<g class="actor"><circle cx="95" cy="510" r="17"/><path d="M95 527v45m-30-25h60m-30 25-22 33m22-33 22 33"/></g><text x="15" y="606" class="label">Gestor</text>
<g class="actor"><circle cx="1025" cy="165" r="15"/><path d="M1025 180v55m-25-33h50m-25 33-22 36m22-36 22 36"/></g><text x="979" y="267" class="label">Revisor</text>
<g class="actor"><circle cx="1025" cy="400" r="15"/><path d="M1025 415v55m-25-33h50m-25 33-22 36m22-36 22 36"/></g><text x="967" y="502" class="label">Parceiro</text>
<!-- use cases -->
<g><ellipse cx="410" cy="112" rx="145" ry="31" class="uc"/><text x="410" y="118" text-anchor="middle" class="txt">Consultar catálogo e mapa</text>
<ellipse cx="730" cy="112" rx="145" ry="31" class="uc"/><text x="730" y="118" text-anchor="middle" class="txt">Pesquisar oportunidade/negócio</text>
<ellipse cx="410" cy="205" rx="145" ry="31" class="uc"/><text x="410" y="211" text-anchor="middle" class="txt">Manifestar interesse</text>
<ellipse cx="730" cy="205" rx="145" ry="31" class="uc"/><text x="730" y="211" text-anchor="middle" class="txt">Executar simulação</text>
<ellipse cx="410" cy="300" rx="145" ry="31" class="uc"/><text x="410" y="306" text-anchor="middle" class="txt">Criar candidatura / dossier</text>
<ellipse cx="730" cy="300" rx="145" ry="31" class="uc"/><text x="730" y="306" text-anchor="middle" class="txt">Anexar e acompanhar documentos</text>
<ellipse cx="410" cy="397" rx="145" ry="31" class="uc"/><text x="410" y="403" text-anchor="middle" class="txt">Tratar interesse no CRM</text>
<ellipse cx="730" cy="397" rx="145" ry="31" class="uc"/><text x="730" y="403" text-anchor="middle" class="txt">Validar e publicar conteúdo</text>
<ellipse cx="410" cy="495" rx="145" ry="31" class="uc"/><text x="410" y="501" text-anchor="middle" class="txt">Gerir território e zonas</text>
<ellipse cx="730" cy="495" rx="145" ry="31" class="uc"/><text x="730" y="501" text-anchor="middle" class="txt">Colaborar em parceria/serviço</text></g>
<!-- actor associations -->
<g class="line"><path d="M112 115H264M112 115 585 112M112 145 265 195M112 355 265 300M112 370 265 300M112 388 585 300M112 515 265 397M112 525 265 495M112 540 585 495M1008 175 875 397M1008 190 875 300M1008 410 875 495"/></g>
</svg></div>
<p class="legend">Exemplo do percurso mais comum: visitante pesquisa → manifesta interesse → investidor cria/acompanha candidatura → gestão trata o pedido → revisão e decisão.</p>
<h2>5. Casos de uso reais — jornadas ilustrativas</h2>
<h3>UC-A — Investidor encontra oportunidade e manifesta interesse</h3>
<ol><li>O visitante consulta sectores, filtra oportunidades por localização e abre o detalhe.</li><li>Escolhe “manifestar interesse”, informa contacto, modalidade e mensagem, e aceita o consentimento aplicável.</li><li>O sistema valida o alvo, regista o pedido e, quando configurado, um recibo/idempotência.</li><li>O investidor pode autenticar-se para guardar a oportunidade ou avançar para uma submissão.</li><li>Um gestor consulta o pedido, verifica consentimentos, atribui responsável, qualifica e cria tarefa de seguimento.</li><li>As alterações relevantes ficam no histórico; notificações e integrações só são consideradas entregues quando o disparo e o serviço estiverem confirmados.</li></ol>
<p><b>Resultado:</b> pedido rastreável ligado à oportunidade e encaminhado para tratamento. <b>Entidades:</b> Opportunity, Investor/User, InterestRequest, Consent, Lead, Task, AuditEvent.</p>
<h3>UC-B — Proprietário submete um negócio para divulgação</h3>
<ol><li>O proprietário cria rascunho e informa modalidade, objectos, localização e documentos de suporte.</li><li>Submete o registo; o estado passa para revisão conforme o workflow aplicável.</li><li>O gestor analisa e pode aprovar, rejeitar ou pedir informação complementar.</li><li>O revisor documental confere original, hash, versão, scan e autorização de divulgação.</li><li>Só após as validações necessárias o conteúdo pode ser publicado ao público; publicação não altera a situação jurídica do documento.</li></ol>
<p><b>Resultado:</b> negócio com histórico e decisão rastreável. <b>Estados documentados:</b> draft → submitted → in_review → approved → published, com ramos needs_information, rejected, withdrawn, suspended e archived.</p>
<h3>UC-C — Gestor territorial valida zona e relações</h3>
<ol><li>O gestor regista a zona e a referência/fonte pertinente.</li><li>Associa localização, operador, categoria, geometria e relações com projectos, clusters ou corredores.</li><li>As relações sem evidência verificada permanecem pendentes e identificadas.</li><li>Um revisor valida a evidência e as regras de publicação; alterações ficam versionadas.</li><li>A zona só aparece no portal conforme estado e autorização de divulgação.</li></ol>
<h3>UC-D — Utilizador guarda um rascunho e executa simulação</h3>
<ol><li>O utilizador preenche o formulário; os dados incompletos podem ser guardados como rascunho recuperável.</li><li>Quando solicita o cálculo, o sistema selecciona questionário e parâmetros elegíveis.</li><li>O job de simulação executa após a transacção e grava cenários, resultados, obrigações e fontes usadas.</li><li>O relatório pode ser consultado; o rascunho continua distinto do cálculo executado.</li></ol>
<div class="callout"><b>Regra de integridade:</b> importar ou publicar fonte documental não activa automaticamente uma regra fiscal. Parâmetros ausentes/ambíguos permanecem indeterminados.</div>
<h3>UC-E — Parceiros colaboram numa parceria ou serviço</h3>
<p>Um actor cria uma proposta; outro manifesta interesse; após aceitação, os participantes podem colaborar numa sala, trocar mensagens/documentos e acompanhar marcos. O balcão virtual segue padrão semelhante para pedidos de serviço: registo, análise, pedido de documentos, eventos, revisão e resolução.</p>
<h2>6. Diagrama de classes (visão lógica)</h2>
<p>O diagrama apresenta as classes de domínio principais, atributos representativos e operações. É uma vista funcional; não reproduz todos os campos nem métodos Laravel.</p>
<div class="diagram"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1100 690" role="img" aria-label="Diagrama UML de classes InvestMoz">
<defs><style>.box{fill:#fff;stroke:#276c9b;stroke-width:2}.head{fill:#e8f2f9}.ct{font:14px Arial;fill:#17324d}.ch{font:bold 15px Arial;fill:#123d68}.rel{stroke:#60768b;stroke-width:1.8;fill:none}.mult{font:12px Arial;fill:#455b70}</style></defs>
<!-- classes -->
<g><rect x="30" y="30" width="220" height="120" rx="5" class="box"/><rect x="30" y="30" width="220" height="32" class="head"/><text x="140" y="52" text-anchor="middle" class="ch">User</text><text x="44" y="82" class="ct">id, email, verified_at</text><text x="44" y="105" class="ct">2FA / passkeys</text><text x="44" y="132" class="ct">+ authenticate()</text>
<rect x="315" y="30" width="220" height="120" rx="5" class="box"/><rect x="315" y="30" width="220" height="32" class="head"/><text x="425" y="52" text-anchor="middle" class="ch">Investor</text><text x="329" y="82" class="ct">id, user_id, profile</text><text x="329" y="105" class="ct">company interests</text><text x="329" y="132" class="ct">+ manageProfile()</text>
<rect x="600" y="30" width="220" height="120" rx="5" class="box"/><rect x="600" y="30" width="220" height="32" class="head"/><text x="710" y="52" text-anchor="middle" class="ch">Opportunity</text><text x="614" y="82" class="ct">sector, slug, status</text><text x="614" y="105" class="ct">location, investment</text><text x="614" y="132" class="ct">+ publish()</text>
<rect x="865" y="30" width="205" height="120" rx="5" class="box"/><rect x="865" y="30" width="205" height="32" class="head"/><text x="967" y="52" text-anchor="middle" class="ch">Sector</text><text x="879" y="82" class="ct">id, name, slug</text><text x="879" y="105" class="ct">active / published</text><text x="879" y="132" class="ct">+ listOpportunities()</text>
<rect x="30" y="230" width="235" height="130" rx="5" class="box"/><rect x="30" y="230" width="235" height="32" class="head"/><text x="147" y="252" text-anchor="middle" class="ch">InterestRequest</text><text x="44" y="282" class="ct">target, contact, consent</text><text x="44" y="305" class="ct">status, submitted_at</text><text x="44" y="338" class="ct">+ submit() / qualify()</text>
<rect x="325" y="230" width="235" height="130" rx="5" class="box"/><rect x="325" y="230" width="235" height="32" class="head"/><text x="442" y="252" text-anchor="middle" class="ch">Lead / Task</text><text x="339" y="282" class="ct">owner, next_action</text><text x="339" y="305" class="ct">due_at, status</text><text x="339" y="338" class="ct">+ assign() / complete()</text>
<rect x="620" y="230" width="235" height="130" rx="5" class="box"/><rect x="620" y="230" width="235" height="32" class="head"/><text x="737" y="252" text-anchor="middle" class="ch">Submission</text><text x="634" y="282" class="ct">owner, target, state</text><text x="634" y="305" class="ct">revisions, needs</text><text x="634" y="338" class="ct">+ save() / submit()</text>
<rect x="910" y="230" width="160" height="130" rx="5" class="box"/><rect x="910" y="230" width="160" height="32" class="head"/><text x="990" y="252" text-anchor="middle" class="ch">Document</text><text x="924" y="282" class="ct">hash, source</text><text x="924" y="305" class="ct">version, status</text><text x="924" y="338" class="ct">+ scan()</text>
<rect x="30" y="450" width="235" height="130" rx="5" class="box"/><rect x="30" y="450" width="235" height="32" class="head"/><text x="147" y="472" text-anchor="middle" class="ch">Project / Zone</text><text x="44" y="502" class="ct">territory, geometry</text><text x="44" y="525" class="ct">relations, evidence</text><text x="44" y="558" class="ct">+ validate() / publish()</text>
<rect x="325" y="450" width="235" height="130" rx="5" class="box"/><rect x="325" y="450" width="235" height="32" class="head"/><text x="442" y="472" text-anchor="middle" class="ch">Simulation</text><text x="339" y="502" class="ct">questionnaire, input</text><text x="339" y="525" class="ct">scenario, result, sources</text><text x="339" y="558" class="ct">+ execute() / report()</text>
<rect x="620" y="450" width="235" height="130" rx="5" class="box"/><rect x="620" y="450" width="235" height="32" class="head"/><text x="737" y="472" text-anchor="middle" class="ch">TaxRuleVersion</text><text x="634" y="502" class="ct">source, dates, parameters</text><text x="634" y="525" class="ct">review / approval state</text><text x="634" y="558" class="ct">+ resolveForPeriod()</text>
<rect x="910" y="450" width="160" height="130" rx="5" class="box"/><rect x="910" y="450" width="160" height="32" class="head"/><text x="990" y="472" text-anchor="middle" class="ch">AuditEvent</text><text x="924" y="502" class="ct">actor, entity</text><text x="924" y="525" class="ct">action, time</text><text x="924" y="558" class="ct">+ record()</text></g>
<!-- relations -->
<g class="rel"><path d="M250 90H315M535 90H600M820 90H865M140 150V230M425 150V230M710 150V230M265 295H325M560 295H620M855 295H910M140 360V450M442 360V450M737 360V450M855 515H910M250 130 900 470"/></g>
<g class="mult"><text x="270" y="82">1 : 0..1</text><text x="547" y="82">0..*</text><text x="834" y="82">1</text><text x="148" y="205">1 : 0..*</text><text x="273" y="286">0..1</text><text x="567" y="286">1..*</text><text x="861" y="286">0..*</text><text x="145" y="435">1 : 0..*</text><text x="450" y="435">1 : 0..*</text></g>
</svg></div>
<p class="note">A relação exacta Investor/User, a associação Submission/target e os vínculos Document/entidade podem ser opcionais ou implementados por tabelas polimórficas/de junção; confirme no schema antes de gerar código ou migrações.</p>
<h2>7. Diagrama de relacionamento (ER simplificado)</h2>
<div class="diagram"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1080 560" role="img" aria-label="Diagrama de relacionamento das entidades InvestMoz">
<defs><style>.e{fill:#edf5fb;stroke:#2477b6;stroke-width:2}.et{font:bold 15px Arial;fill:#123d68}.r{stroke:#61788d;stroke-width:2;fill:none}.rt{font:12px Arial;fill:#40566b}</style></defs>
<g><rect x="35" y="45" width="155" height="60" rx="9" class="e"/><text x="112" y="81" text-anchor="middle" class="et">SECTOR</text><rect x="260" y="45" width="180" height="60" rx="9" class="e"/><text x="350" y="81" text-anchor="middle" class="et">OPPORTUNITY</text><rect x="515" y="45" width="190" height="60" rx="9" class="e"/><text x="610" y="81" text-anchor="middle" class="et">INTEREST_REQUEST</text><rect x="805" y="45" width="160" height="60" rx="9" class="e"/><text x="885" y="81" text-anchor="middle" class="et">INVESTOR</text>
<rect x="35" y="205" width="155" height="60" rx="9" class="e"/><text x="112" y="241" text-anchor="middle" class="et">USER</text><rect x="260" y="205" width="180" height="60" rx="9" class="e"/><text x="350" y="241" text-anchor="middle" class="et">SUBMISSION</text><rect x="515" y="205" width="190" height="60" rx="9" class="e"/><text x="610" y="241" text-anchor="middle" class="et">DOCUMENT</text><rect x="805" y="205" width="160" height="60" rx="9" class="e"/><text x="885" y="241" text-anchor="middle" class="et">AUDIT_EVENT</text>
<rect x="35" y="365" width="155" height="60" rx="9" class="e"/><text x="112" y="401" text-anchor="middle" class="et">PROJECT</text><rect x="260" y="365" width="180" height="60" rx="9" class="e"/><text x="350" y="401" text-anchor="middle" class="et">CLUSTER</text><rect x="515" y="365" width="190" height="60" rx="9" class="e"/><text x="610" y="401" text-anchor="middle" class="et">INVESTMENT_ZONE</text><rect x="805" y="365" width="160" height="60" rx="9" class="e"/><text x="885" y="401" text-anchor="middle" class="et">LEGAL_SOURCE</text>
<rect x="145" y="490" width="180" height="55" rx="9" class="e"/><text x="235" y="523" text-anchor="middle" class="et">SIMULATION</text><rect x="450" y="490" width="180" height="55" rx="9" class="e"/><text x="540" y="523" text-anchor="middle" class="et">TAX_RULE_VERSION</text><rect x="755" y="490" width="180" height="55" rx="9" class="e"/><text x="845" y="523" text-anchor="middle" class="et">SIMULATION_RESULT</text></g>
<g class="r"><path d="M190 75H260M440 75H515M705 75H805M190 235H260M440 235H515M705 235H805M190 395H260M440 395H515M705 395H805M235 425V490M325 518H450M630 518H755M350 105V205M610 105V205M610 265V365M885 105V205M885 425V455H540V490"/></g>
<g class="rt"><text x="210" y="67">1 : N</text><text x="465" y="67">1 : N</text><text x="730" y="67">N : 0..1</text><text x="210" y="227">1 : N</text><text x="462" y="227">N : M* via links</text><text x="730" y="227">1 : N</text><text x="210" y="387">N : M*</text><text x="462" y="387">N : M*</text><text x="730" y="387">1 : N</text><text x="235" y="466">1 : N</text><text x="346" y="510">1 : N</text><text x="650" y="510">1 : N</text><text x="354" y="160">1 : N</text><text x="617" y="160">association</text><text x="894" y="160">actor</text><text x="670" y="448">source</text></g>
</svg></div>
<p class="note">N:M = muitos-para-muitos, normalmente resolvido por tabela de associação. Ligações genéricas de documentos/auditoria podem não ser FKs directas. Este mapa é uma vista funcional, não um substituto do ERD integral em docs/investmoz/erd.mmd e do dicionário de dados.</p>
<h2>8. Eventos e frequência</h2>
<table><tr><th>Evento/processo</th><th>Gatilho</th><th>Frequência confirmada</th><th>Leitura operacional</th></tr>
<tr><td>Escalar tarefas vencidas</td><td>Scheduler Laravel</td><td>A cada 15 minutos; sem sobreposição configurada</td><td>Cadência declarada em routes/console.php. O scheduler do servidor tem de estar activo.</td></tr>
<tr><td>Executar simulação (RunSimulation)</td><td>Pedido de cálculo aceite</td><td>Por pedido, via fila, afterCommit</td><td>Assíncrono; volume depende da utilização e dos workers.</td></tr>
<tr><td>Scan de malware (ScanDocumentForMalware)</td><td>Upload ou pedido de análise em fluxos suportados</td><td>Por documento, via fila; job único</td><td>Depende de worker e scanner. Upload não prova análise concluída.</td></tr>
<tr><td>Comparação de compatibilidade MNE</td><td>Alteração aplicável do negócio</td><td>Por alteração aplicável, em fila de sombra</td><td>Job identificado; frequência de alterações não medida.</td></tr>
<tr><td>Notificação de interesse</td><td>Recepção de interesse</td><td>Disparo não confirmado</td><td>Job NotifyInterestReceived existe, mas não foi localizada chamada dispatch().</td></tr>
<tr><td>Outbox/inbox e sincronização externa</td><td>Evento/mensagem externa</td><td>Sem calendário operacional confirmado</td><td>Estrutura preparada; documentação indica sincronização real pendente.</td></tr>
<tr><td>Pesquisas, submissões, revisões e auditoria</td><td>Acção do visitante/utilizador/gestor</td><td>Sob procura ou acção; contagem indisponível</td><td>Sem logs/analytics não se calculam ocorrências por período.</td></tr></table>
<p><b>Frequência configurada não é frequência observada.</b> Não foram disponibilizados logs, contagens de eventos da base activa, filas, analytics nem tráfego HTTP. Assim, eventos por hora/dia/mês, sazonalidade, falhas e utilizadores activos permanecem indeterminados. Não se extrapolam estes valores a partir de testes, seeders, screenshots ou schema.</p>
<h2>9. Inventário dos 24 casos de uso</h2>
<table><tr><th>Grupo</th><th>Casos</th></tr>
<tr><td>Portal e catálogo</td><td>UC-01 Consultar página inicial e serviços; UC-02 Pesquisar sectores e oportunidades; UC-03 Consultar negócio existente.</td></tr>
<tr><td>Conta e jornada</td><td>UC-04 Criar conta/autenticar/recuperar acesso; UC-05 Manifestar interesse numa oportunidade; UC-06 Manifestar interesse num negócio; UC-07 Guardar oportunidade; UC-08 Manter submissão; UC-09 Submeter candidatura.</td></tr>
<tr><td>Negócios e CRM</td><td>UC-10 Gerir negócio existente; UC-11 Tratar interesses no CRM.</td></tr>
<tr><td>Território e documentos</td><td>UC-12 Gerir catálogo territorial; UC-13 Gerir zonas; UC-14 Carregar, verificar e publicar documento.</td></tr>
<tr><td>Simulação/fiscalidade</td><td>UC-15 Criar rascunho; UC-16 Executar simulação; UC-17 Gerir regra fiscal.</td></tr>
<tr><td>Serviços especializados</td><td>UC-18 Gerir educação e competências; UC-19 Assistência de terra; UC-20 Gerir parceria; UC-21 Usar balcão virtual.</td></tr>
<tr><td>Transversal</td><td>UC-22 Usar IA com evidência; UC-23 Sincronizar sistemas externos; UC-24 Auditar alterações.</td></tr></table>
<p>Os pré-requisitos, fluxos alternativos e tabelas associadas por UC encontram-se no ficheiro <i>casos-de-uso-aplicacao-actual.md</i>.</p>
<h2>10. Integridade, segurança e limitações</h2>
<ul><li>Disponibilidade para consulta, situação jurídica/documental e uso em regra/cálculo são estados independentes.</li><li>Respeitar autorização de divulgação e âmbito; relações sem evidência ficam pendentes.</li><li>Preservar original, proveniência, ID exacto, edição/data, hash e histórico. Não confirmar autenticidade, vigência, direitos ou scan sem evidência.</li><li>Importação não é publicação; publicação documental não activa cálculo fiscal; rascunho não é candidatura aprovada.</li><li>Integração desenhada não significa sincronização activa. Cobertura e estado de cada domínio devem ser verificados nos respectivos relatórios de validação.</li><li>Antes de alterações a dados activos, confirmar backup/restauro e acção autenticada. Testes e migrações usam exclusivamente base QA isolada.</li></ul>
<h2>11. Fontes de análise</h2>
<ul><li>README.md do repositório;</li><li>docs/investmoz/casos-de-uso-aplicacao-actual.md;</li><li>docs/investmoz/erd.mmd, data-dictionary.csv e table-catalog.csv;</li><li>rotas, controladores, modelos, jobs, comando de escalada e migrations;</li><li>InvestMoz — Levantamento funcional, casos de uso e diagramas.docx, em Downloads.</li></ul>
<p class="note">O inventário cobriu 981 caminhos listados por rg --files, excluindo vendor e node_modules. Isso descreve o repositório acessível, não anexos externos, conteúdo de armazenamento privado ou base de dados de produção.</p>
</body></html>
@@ -0,0 +1,526 @@
# Casos de uso da aplicação actual
Este documento descreve os processos actualmente implementados ou previstos
pelas rotas, controladores, serviços e migrations existentes no projecto.
Não substitui regras legais nem autoriza publicação de dados.
## 1. Actores
| Actor | Responsabilidade |
|---|---|
| Visitante | Consulta o portal, oportunidades, negócios, zonas e documentos públicos. |
| Utilizador registado | Mantém perfil, rascunhos, submissões, favoritos e mensagens. |
| Investidor | Pesquisa oportunidades, manifesta interesse e acompanha candidaturas. |
| Gestor | Trata interesses, leads, tarefas, oportunidades e catálogo. |
| Revisor documental | Verifica documentos, malware, versões e autorização de divulgação. |
| Gestor territorial | Gere projectos, clusters, corredores, geografia e zonas. |
| Gestor fiscal | Gere fontes legais, versões de regras e parâmetros do simulador. |
| Gestor de educação | Gere competências, necessidades, cursos e propostas. |
| Parceiro institucional | Participa em parcerias, salas, mensagens, documentos e marcos. |
| Administrador | Gere utilizadores, permissões, configurações e instalação de módulos. |
| Sistema externo | Recebe/envi­a eventos através de outbox, inbox e sincronizações. |
## 2. Visão geral do ciclo da aplicação
```text
Portal público
-> consulta de catálogo
-> interesse, apoio ou simulação
-> autenticação/conta quando necessário
-> candidatura ou submissão
-> documentos e validação
-> CRM, tarefas e comunicação
-> decisão, parceria ou acompanhamento
```
Os principais agregados são `opportunities`, `existing_businesses`,
`interest_requests`, `investment_submissions`, `documents`, `investment_zones`
e `simulations`.
## 3. UC-01 — Consultar a página inicial e serviços
**Actor:** Visitante.
**Pré-condições:** O portal está disponível.
**Fluxo principal:**
1. O visitante abre `/`.
2. O sistema apresenta a página inicial e os serviços publicados.
3. O visitante escolhe oportunidades, negócios, zonas, simulador, documentos,
apoio ou parcerias.
4. O sistema aplica apenas dados que estejam disponíveis para o público.
**Dados:** `portal_resources`, `documents`, `opportunities`, `sectors`,
`existing_businesses`, `investment_zones`.
**Resultado:** O visitante é encaminhado para o processo escolhido.
## 4. UC-02 — Pesquisar sectores e oportunidades
**Actor:** Visitante ou investidor.
**Fluxo principal:**
1. O actor consulta `/oportunidades` ou a API de oportunidades.
2. O sistema filtra por sector, localização, slug, estado e outros critérios.
3. O detalhe da oportunidade mostra perfil, território, relações, documentos
públicos e informação de investimento.
4. O actor pode iniciar uma manifestação de interesse ou guardar a oportunidade.
**Dados:** `sectors`, `opportunities`, `opportunity_profiles`,
`opportunity_facets`, `opportunity_clusters`, `opportunity_corridors`,
`opportunity_projects`, `opportunity_locations`, `opportunity_favourites`.
**Resultado:** Consulta pública ou início de UC-05/UC-06.
## 5. UC-03 — Consultar um negócio existente
**Actor:** Visitante ou investidor.
**Fluxo principal:**
1. O actor consulta `/negocios`.
2. O sistema lista negócios cujo estado e autorização permitem divulgação.
3. O actor abre o detalhe pelo `slug`.
4. O sistema apresenta apenas título, descrição, modalidade, localização,
objectos e documentos autorizados.
5. O actor pode iniciar uma manifestação de interesse.
**Dados:** `existing_businesses`, `existing_business_objects`,
`existing_business_locations`, `existing_business_document_links`,
`documents`, `interest_requests`.
**Regra:** Dados privados, mandatos e documentos não autorizados não são
expostos pelo portal público.
## 6. UC-04 — Criar conta, autenticar e recuperar acesso
**Actor:** Visitante/utilizador.
**Fluxo principal:**
1. O visitante cria uma conta com nome, email e palavra-passe.
2. O sistema cria `users`.
3. O utilizador confirma o email quando aplicável.
4. O utilizador inicia sessão.
5. O sistema aplica as políticas de autenticação, confirmação de palavra-passe
e, para operações protegidas, segundo factor.
**Dados:** `users`, `passkeys`, `sessions`, `password_reset_tokens`.
**Alternativas:** Registo rejeitado por email existente; palavra-passe
incorrecta; recuperação por token; desafio de dois factores.
## 7. UC-05 — Manifestar interesse numa oportunidade
**Actor:** Visitante ou investidor.
**Fluxo principal:**
1. O actor abre o formulário de interesse.
2. Informa contacto, oportunidade, modalidade, valor e mensagem.
3. O sistema valida os dados, consentimentos e alvo.
4. É criado `interest_requests`.
5. O sistema regista recibo/idempotência quando aplicável.
6. O sistema envia notificação ou evento de tratamento.
**Dados:** `interest_requests`, `consents`, `interest_submission_receipts`,
`notifications`, `outbox_events`.
**Estado inicial:** `received`, `submitted` ou equivalente configurado.
**Resultado:** O interesse fica disponível para tratamento no CRM.
## 8. UC-06 — Manifestar interesse num negócio existente
**Actor:** Investidor.
**Fluxo principal:**
1. O investidor escolhe um `existing_business` publicado.
2. Selecciona a modalidade e, se aplicável, percentagem e intervalo de valor.
3. O sistema verifica que o negócio pode receber interesse.
4. Cria `interest_requests.existing_business_id`.
5. Regista consentimento para contacto e partilha da informação.
6. O caso passa para tratamento interno.
**Dados:** `existing_businesses`, `interest_requests`, `investors`, `consents`.
**Regra:** Um pedido não pode apontar simultaneamente para uma oportunidade e
para um negócio existente.
## 9. UC-07 — Guardar uma oportunidade e manter espaço do investidor
**Actor:** Utilizador autenticado.
**Fluxo principal:**
1. O utilizador abre uma oportunidade.
2. Escolhe guardar/iniciar no espaço do investidor.
3. O sistema regista a relação em `opportunity_favourites` ou inicia uma
submissão/dossier.
4. O utilizador consulta os seus itens em `/investidor` ou `/carteira`.
**Dados:** `users`, `opportunity_favourites`, `investment_dossiers`,
`investor_accounts`, `investment_accounts`.
## 10. UC-08 — Criar e manter uma submissão de investimento
**Actor:** Investidor.
**Pré-condições:** Utilizador autenticado e verificado.
**Fluxo principal:**
1. O investidor cria uma submissão.
2. O sistema cria `investment_submissions` com estado `draft`.
3. O investidor grava o payload e as necessidades específicas.
4. Pode adicionar anexos e mensagens.
5. O sistema cria eventos e revisões para manter histórico.
6. O investidor consulta ou actualiza a submissão.
**Dados:** `investment_submissions`, `investment_specific_needs`,
`investment_submission_attachments`, `investment_submission_events`,
`investment_submission_revisions`, `investment_messages`, `documents`.
## 11. UC-09 — Submeter candidatura
**Actor:** Investidor.
**Fluxo principal:**
1. O investidor confirma os dados da submissão.
2. O sistema verifica campos obrigatórios, alvo e anexos.
3. A submissão muda de `draft` para `submitted`.
4. É associado ou criado o pedido de interesse, quando exigido.
5. O sistema cria evento de submissão e notifica a gestão.
**Resultado:** A candidatura deixa de ser apenas rascunho e entra na fila de
tratamento interno.
## 12. UC-10 — Gerir um negócio existente
**Actor:** Investidor, proprietário ou gestor.
**Fluxo principal:**
1. O actor cria ou actualiza o negócio.
2. Regista modalidade, descrição, objectos, localização e documentos.
3. O sistema cria revisões e mantém o snapshot anterior.
4. Um gestor pode solicitar informação, rever ou rejeitar.
5. O negócio percorre o workflow configurado.
6. Apenas após validação e autorização poderá ser publicado.
**Dados:** `existing_businesses`, `existing_business_objects`,
`existing_business_revisions`, `existing_business_reviews`,
`business_workflow_transitions`, `existing_business_mandates`, `documents`.
**Estados possíveis:** `draft`, `submitted`, `in_review`,
`needs_information`, `approved`, `published`, `suspended`, `rejected`,
`withdrawn`, `archived`.
## 13. UC-11 — Tratar interesses no CRM
**Actor:** Gestor.
**Fluxo principal:**
1. O gestor abre a fila de interesses.
2. Consulta o pedido, consentimentos e alvo.
3. Atribui o caso a um responsável.
4. Converte o interesse em `leads`, quando aplicável.
5. Cria tarefas e actividades.
6. Actualiza o estado e regista o resultado.
7. Pode associar um `crm_opportunity` e continuar a negociação.
**Dados:** `interest_requests`, `leads`, `investors`, `contacts`,
`crm_opportunities`, `tasks`, `activities`, `consents`.
**Estados de interesse:** recebimento, qualificação, contacto, diligência,
negociação, conversão, recusa, cancelamento ou encerramento.
## 14. UC-12 — Gerir catálogo territorial
**Actor:** Gestor territorial.
**Fluxo principal:**
1. O gestor cria ou actualiza projectos, clusters e corredores.
2. Liga projectos a locais.
3. Liga projectos a clusters e corredores.
4. Cria cadeias de valor e lacunas de investimento.
5. Regista a fonte e o estado da relação.
6. Outro gestor pode validar ou revogar a relação.
**Dados:** `projects`, `economic_clusters`, `value_chains`,
`value_chain_links`, `development_corridors`, `cluster_projects`,
`corridor_projects`, `corridor_clusters`, `investment_gaps`, `geo_locations`.
## 15. UC-13 — Gerir zonas de investimento
**Actor:** Gestor territorial com permissão e MFA quando exigido.
**Fluxo principal:**
1. Regista a fonte legal em `investment_legal_sources`.
2. Cria a zona em `investment_zones`.
3. Associa operador, categoria e localização.
4. Adiciona geometria, anexos e relações com projectos, clusters ou corredores.
5. Um revisor valida a informação.
6. A zona é publicada, suspensa ou revogada.
7. O sistema mantém revisões imutáveis.
**Estados:** `draft`, `published`, `suspended`; validação `pending`,
`validated`, `historical`.
**Dados:** `investment_zones`, `investment_legal_sources`,
`investment_zone_geometries`, `investment_zone_relations`,
`investment_zone_links`, `investment_zone_attachments`, `investment_zone_revisions`.
## 16. UC-14 — Carregar, verificar e publicar documento
**Actor:** Gestor documental.
**Fluxo principal:**
1. O gestor carrega o ficheiro.
2. O sistema preserva o original e calcula o hash.
3. Detecta duplicados e conflitos de versão.
4. Regista `documents` e, quando necessário, `document_versions`.
5. Executa análise antimalware.
6. O gestor revê classificação, datas, fonte e autorização.
7. O documento é associado ao negócio, candidatura, zona, projecto ou portal.
8. Só então pode ser disponibilizado publicamente.
**Dados:** `documents`, `document_versions`, `document_malware_scans`,
`portal_resources`, `portal_resource_revisions` e tabelas `*_documents`.
**Estados documentais:** pendente, limpo, infectado, rejeitado, privado,
publicável, publicado ou revogado.
## 17. UC-15 — Criar rascunho de simulação
**Actor:** Visitante ou utilizador.
**Fluxo principal:**
1. O actor abre o simulador.
2. O sistema cria ou recupera um cookie de recuperação.
3. Guarda os dados em `simulation_form_drafts`.
4. O actor pode continuar mais tarde.
5. Um utilizador autenticado pode reclamar o rascunho.
6. O rascunho pode ser ligado a um negócio existente, mediante autorização.
**Resultado:** Dados incompletos permanecem como rascunho e não são tratados
como cálculo fiscal executado.
## 18. UC-16 — Executar simulação
**Actor:** Visitante ou utilizador.
**Fluxo principal:**
1. O actor submete os dados do simulador.
2. O sistema escolhe a versão do questionário.
3. Resolve os parâmetros fiscais elegíveis.
4. Cria `simulations` e `simulation_scenarios`.
5. Executa o cálculo através de job.
6. Guarda resultados, obrigações e fontes.
7. Gera relatório quando solicitado.
8. Regista auditoria e idempotência.
**Dados:** `questionnaire_versions`, `simulations`, `simulation_scenarios`,
`simulation_results`, `simulation_obligations`, `simulation_reports`,
`simulation_jobs`, `simulation_result_sources`, `simulation_audit_events`.
## 19. UC-17 — Gerir regra fiscal
**Actor:** Autor, revisor, aprovador ou publicador fiscal.
**Fluxo principal:**
1. O autor cria uma versão da regra.
2. Associa a regra a uma fonte legal.
3. O revisor verifica expressão, datas e parâmetros.
4. O aprovador decide.
5. O publicador disponibiliza a versão.
6. O sistema regista cada transição.
**Dados:** `simulation_tax_rule_versions`, `simulation_tax_rule_events`,
`investment_legal_sources`, `users`.
**Regra:** Importar ou publicar um documento não activa automaticamente um
cálculo fiscal.
## 20. UC-18 — Gerir educação e competências
**Actor:** Gestor de educação.
**Fluxo principal:**
1. Mantém catálogo de competências, profissões, instituições e cursos.
2. Regista necessidades de formação de projectos.
3. Associa ocupações e competências.
4. Regista capacidades e oportunidades educativas.
5. Analisa lacunas.
6. Cria proposta de investimento educativo.
**Dados:** `skills`, `occupations`, `training_needs`, `training_providers`,
`courses`, `education_opportunities`, `investment_gaps`,
`education_investment_proposals` e tabelas `skills_edu`.
## 21. UC-19 — Abrir e tratar assistência de terra
**Actor:** Investidor e gestor de assistência.
**Fluxo principal:**
1. O investidor cria um caso de assistência.
2. Regista localização, necessidade e documentos.
3. O gestor analisa o caso.
4. São registadas revisões, eventos e pedidos adicionais.
5. O caso é encaminhado ou encerrado.
**Dados:** `land_assistance_cases`, `land_assistance_revisions`,
`land_assistance_events`, `land_assistance_documents`, `documents`, `users`.
## 22. UC-20 — Criar e gerir parceria
**Actor:** Investidor, organização ou parceiro institucional.
**Fluxo principal:**
1. O actor cria um rascunho de parceria.
2. Regista origem, sector, local e objectivo.
3. Outro actor manifesta interesse.
4. A candidatura é aceite ou recusada.
5. É aberta uma sala de parceria.
6. Os participantes trocam mensagens e documentos.
7. São definidos marcos, pagamentos ou acordo.
8. O sistema regista eventos e notificações.
**Dados:** `portal_partnerships`, `partnership_origins`,
`partnership_locations`, `partnership_interests`, `partnership_rooms`,
`partnership_messages`, `partnership_documents`, `partnership_milestones`,
`partnership_events`, `partnership_notifications`.
## 23. UC-21 — Usar o balcão virtual
**Actor:** Utilizador autenticado e agente de atendimento.
**Fluxo principal:**
1. O utilizador abre um pedido no balcão.
2. O sistema cria um caso e associa o serviço.
3. O agente recebe o pedido.
4. São trocadas mensagens e solicitados documentos.
5. O caso passa por estados e revisões.
6. Eventos, notificações e pagamentos são registados.
7. O caso é resolvido ou encerrado.
**Dados:** `desk_service_versions`, `desk_cases`, `desk_requests`,
`desk_documents`, `desk_events`, `desk_revisions`, `desk_messages`,
`desk_notifications`, `desk_institutional_links`, `desk_payments`.
## 24. UC-22 — Usar inteligência artificial com evidência
**Actor:** Gestor autorizado.
**Fluxo principal:**
1. O gestor activa a capacidade em `ai_controls`.
2. Regista uma fonte ou documento.
3. O sistema cria chunks da fonte.
4. O gestor inicia uma execução de IA.
5. O sistema grava `ai_runs`.
6. O resultado pode ser revisto ou receber feedback.
7. A aplicação mantém a fonte que suporta a resposta.
**Dados:** `ai_controls`, `ai_sources`, `ai_chunks`, `ai_runs`, `ai_feedback`,
`documents`, `users`.
## 25. UC-23 — Sincronizar com sistemas externos
**Actor:** Sistema externo ou processo de integração.
**Fluxo principal:**
1. A aplicação gera um evento em `outbox_events`.
2. Um worker publica o evento.
3. O sistema externo responde ou envia evento para `inbox_events`.
4. A aplicação cria `sync_runs`.
5. Falhas ou divergências são registadas em `reconciliation_issues`.
6. O processo pode ser repetido de forma idempotente.
## 26. UC-24 — Auditoria e controlo de alterações
**Actor:** Sistema, gestor ou auditor.
**Fluxo principal:**
1. Uma operação protegida é executada.
2. O sistema identifica actor, entidade, acção e correlação.
3. Regista evento de auditoria.
4. Alterações de entidades versionadas geram revisão/snapshot.
5. O auditor consulta o histórico sem alterar o registo original.
**Dados:** `audit_events`, `simulation_audit_events`, `investment_zone_revisions`,
`existing_business_revisions`, `investment_submission_revisions`,
`desk_revisions`, `outbox_events`.
## 27. Regras transversais da aplicação
- Dados privados exigem autenticação e autorização.
- Divulgação pública depende do estado de publicação e autorização registada.
- Documentos originais devem ser preservados.
- Hash, versão e proveniência devem permanecer associados ao documento.
- Relações jurídicas ou territoriais não validadas ficam pendentes.
- Rascunho não é submissão aprovada.
- Importação não é publicação.
- Publicação de documento não é activação de regra fiscal.
- Cálculos fiscais devem usar fonte e parâmetro identificados.
- Histórico e auditoria não devem ser apagados por rollback destrutivo.
- Operações de migração e testes devem usar base QA isolada.
## 28. Mapa resumido dos processos
```text
Visitante
-> consulta catálogo
-> interesse / apoio / simulação
Investidor
-> conta
-> favoritos / dossier
-> submissão
-> documentos
-> mensagens
Gestor
-> interesse
-> lead
-> tarefas
-> oportunidade CRM
-> decisão
Gestor territorial
-> projecto / cluster / corredor
-> zona
-> geometria
-> fonte legal
-> validação / publicação
Gestor fiscal
-> regra
-> revisão
-> aprovação
-> publicação
-> parâmetro usado pelo simulador
Parceiros
-> parceria
-> candidatura
-> sala
-> mensagens / documentos / marcos
```
@@ -4,6 +4,10 @@ Data: 2026-10-03. Âmbito: prompt master recebido em `Pasted text.txt`, document
## Estado inicial e ambiente
**Orientação de publicação e percurso do lote, 23/10/2026:** as 34 oportunidades de Agronegócio ficam publicáveis sem relações obrigatórias com corredores/clusters/projectos. Lacuna encontrada: a comparação múltipla existente não era transportada ao dossier. Correcção aditiva no contexto cifrado existente, com escolhas identificadas e localização por ficha, confirmação de alternativa, requisitos/fontes/documentos/entidades por contexto, reutilização no simulador e conservação de resultados/histórico. Sete testes do contexto (132 asserções) e um do lote pela sessão HTTP (15) passaram. Publicação QA efectuada; instalação no destino separa código, cadastro privado e divulgação autenticada. Ver [orientação e guia no manual](unification/traceability-and-manual.md). Não altera Turismo de Inhambane nem concede benefícios por localização. Lacunas de modalidade/dimensão/acto concreto permanecem explícitas, sem nova revalidação de fontes oficiais aceites.
**Correcção de âmbito, 23/10/2026 — agronegócio e percurso existente:** a lista informativa instalada não encerrava o cadastro. Preparadas e efectivamente cadastradas 34 oportunidades privadas em QA, com as seis designações documentais intactas, sector, fonte/hash e lacunas explícitas. Reutilizada a candidata de divulgação promocional `9d3bfa89` no fluxo necessário, sem alterações independentes de administração de contas nem novos papéis. Equipa edita/recupera e divulga/actualiza/retira pela interface; público acede à ficha individual, manifestação e roteiro com referência confirmada no mesmo dossier. Três testes específicos, 553 asserções; tipos/build concluídos; tabelas/linhas preexistentes comparadas e preservadas. As divulgações dos testes foram revertidas; as 34 fichas permanecem privadas. Sem alteração da homologação nesta correcção. Carregamento inicial técnico QA já executado; não é dependência das operações correntes. Guia, limites e recibo na [secção de correcção do manual](unification/traceability-and-manual.md#correcção-de-âmbito--34-oportunidades-cadastradas-e-roteiro-em-qa-23102026). Não encerra viabilidade, implantação, financiamento ou execução das oportunidades.
| Item | Evidência observada |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Branch / commit | `main` / `4f35313d06ccd597a4ebf9ed043964d898c95813` |
@@ -315,3 +319,459 @@ Situação comum observada: `publication_status=draft`, `validation_status=valid
- Verificação: `php artisan test tests/Feature/PortalServicesTest.php` — 17 testes/497 asserções aprovados em QA; cobrem publicação autorizada com pesquisa textual e filtros combinados, ficha, download, associação ao módulo e links de requisitos com estados confirmados/pendentes. `npm.cmd run build` concluído. O build alerta sobre pacote opcional `fontaine` e chunk `services` acima de 500 KB; sem erro de compilação. Não houve browser autenticado disponível, portanto não se declara publicação, pesquisa ou download públicos concluídos.
- A autorização documental não foi aplicada a zonas, parques, negócios privados ou oportunidades de demonstração. A regra de publicação de parque não exige área confirmada; divergência de área, isoladamente, não é um gate técnico. Se a ficha avançar por decisão própria, deve omitir o total disputado ou mostrar os valores reportados com fonte/escopo, sem alegar disponibilidade. Beluluane, Munhava e Topuito requerem revisão por registo para fonte/localização pública e para retirar ou qualificar a área; Topuito só tem província associada no mestre geográfico, pelo que não se pode anunciar uma associação administrativa a Larde enquanto essa referência não existir. ZEE/ZFI continuam dependentes de acto oficial estruturado e validado, regime e relações territoriais apropriadas; uma área sem confirmação não substitui essas evidências.
- Proposta para as seis oportunidades de demonstração já públicas: preservar os registos e IDs, adicionar origem/tipo `demo` e identificá-los visivelmente como **Exemplo de demonstração**, separar a pesquisa de exemplos da pesquisa de oportunidades reais e excluir os exemplos dos resultados reais por defeito. Não os converter nem retirar em massa; cada registo real exigirá origem e proponente documentados. Nenhuma alteração foi feita nesta execução.
### Referência da entrada única de gestão — QA, 22/10/2026
Nos requisitos existentes `MASTER-9f6dd1d9-0001`, `MASTER-9f6dd1d9-0003` e `MASTER-02f44baf-0002`, acrescentar como evidência delimitada a secção «Entrada única de gestão — preparação em QA, 22/10/2026» do manual de rastreabilidade e `tests/Feature/ContentManagementEntryTest.php`: quatro testes/99 asserções, ClamAV real e reversão transaccional em QA. Origem do objectivo e das regras operacionais: decisão expressa da Tempo; navegação, filtros e recuperação do upload são escolhas de implementação. Reutilizados biblioteca, armazenamento, perfis e histórico. Não altera os critérios de aceitação nem fecha os requisitos integrais: integração/contas reais e categorias não demonstradas conservam o seu estado. Geometrias permanecem separadas.
AUD-GEO-02/03: Recuperação da demarcação territorial — QA, 22/10/2026. 408/581 limites recuperados em QA; cadeia territorial guardada/reaberta no portal. Homologacao ainda sem reposicao; consultar a nova secao no manual existente. Mantidas 173 correspondencias pendentes e ausencia de geometrias proprias das localidades. Origem: pedido expresso da Tempo de recuperar funcionalidade; enquadramento e mensagens sao escolhas tecnicas. Nao encerra o criterio de reposicao no destino.
AUD-GEO-02/03 - 22/10/2026: Demarcação territorial reposta na homologação — 22/10/2026. 408 limites (11/133/264) importados pela conta real/MFA, com tres recibos auditados; backup/restauro de 171 tabelas conferido, 333 ficheiros verificados. Consulta do mapa demonstrada na oportunidade real #30, sem a alterar. Acessos previstos e originais privados preservados. Reposicao no destino concluida; 26+147 correspondencias e ausencia de poligonos proprios de localidades mantidas como lacunas reais. Ver fecho e guia no manual existente; sem repetir provas QA aceites.
### Incremento Concursos e anúncios — QA, 22/10/2026
Instalação autorizada e concluída na homologação em 22/10/2026: integração funcional `f4d09709`, schema selectivo/contrato/activação conferidos após backup e restauro isolado de 171 tabelas. Gestão real com MFA: cadastro, recuperação e prévia de rascunho privado auditado; catálogo público 200, zero anúncios publicados. Preservados dados/permissões/originais e geometrias. Evidência e links finais em «Instalação concluída na homologação» no manual e `unification/procurement-installation-receipt-20261022.json`. Provas QA aceites reutilizadas. Este fecho substitui o estado de proposta pendente de instalação abaixo, sem declarar aceite pela Tempo o guia não conferido nem expandir o âmbito para recepção de propostas.
Proposta de entrega da candidata `1bcf34c0`: ver «Proposta de instalação compatível com deploy automático» no manual existente. Identificados três novos cadastros e o gate real de contrato de migrations do pipeline. Sequência proposta: revisão → coordenação do deploy → backup/restauro isolado → migration selectiva autenticada com flag desligada → contrato → integração/build/promoção → activação → conferência do delta no destino. Reversão conserva tabelas, actos, auditoria e originais posteriores; não restaura backup antigo sobre dados novos. Provas QA reutilizadas; nenhuma integração, migration remota, activação ou publicação real executada nesta passagem. A Tempo ainda não conferiu links locais/guia; não registar aceitação nem entrega no destino por essa razão.
Nos requisitos existentes de gestão/publicação `MASTER-9f6dd1d9-0001`, `MASTER-9f6dd1d9-0003` e `MASTER-02f44baf-0002`, registar o recorte solicitado pela Tempo: procedimentos com regime/edição/fontes, lotes, rascunhos recuperáveis, prévia, actos versionados, catálogo/ficha/anexos anónimos, filtros, impressão e acompanhamento por conta simples. Evidência: secção «Concursos e anúncios — implementação em QA» do manual existente e `tests/Feature/ProcurementTest.php`, com passagem adicional no navegador dos três regimes, prorrogação, cancelamento, download e acompanhamento. Reutilizadas autorizações e biblioteca; não foram criados papéis ou aprovadores. Origem funcional: pedido expresso da Tempo; flag, prévia assinada e controlo de versão são escolhas técnicas. Entrega delimitada a QA: integração em main, migração/activação no destino e anúncios reais seguem o processo existente. Não fecha requisitos integrais de contratação/recepção de propostas, nem declara parametrizado todo o articulado legal. Geometrias permanecem no recorte separado já entregue.
### Preservação do concluído e reposição — 23/10/2026
Origem: pedido expresso da Tempo de inventariar o concluído e repor funcionalidades desaparecidas antes de outra ronda de testes/validações. Inventariados os mesmos 43 componentes do manual e os 17 percursos da matriz executável existente; os componentes de interface referenciados estão presentes. Estados históricos foram reconciliados com entregas posteriores, sem revogar aceitações por falta de nova prova. Não se criou nova matriz/backlog nem se promoveu uma funcionalidade parcial a concluída.
Perda confirmada: carteira e projectos âncora. Os 29 dossiers existiam em homologação, todos em rascunho, apesar de os exemplares locais idênticos estarem publicados com aprovação documental do proprietário de 26/09. Conteúdo, fonte e título conferidos por identidade/código e hashes nos 29; o commit `e65cb269` de 06/10 retirou o caminho de publicação com essa aprovação do importador. Isso explica a diferença do processo de instalação; não prova quando a visibilidade desapareceu de um endereço específico. Reposta a visibilidade dos 15 projectos, 8 clusters e 6 corredores em QA e homologação, com versões e 29 eventos de reposição; sem importação, reescrita de conteúdos, alteração dos mestres ou novas aprovações/papéis.
Backup/restauro fresco de 174 tabelas antes da escrita activa; depois da reposição, 171 tabelas inalteradas. Diferenças limitadas a dossiers, auditoria e sessões. Biblioteca, 20 artigos públicos, 28 privados, geometrias e permissões preservados. Conferência pública delimitada: carteira 29, projectos 15, clusters 8, corredores 6. Sem suite geral de testes nesta passagem. Evidência, limites e regra de preservação em `unification/preservation-inventory-20261023.json`, secção «Preservação do concluído — inventário e reposição» do manual e instrução permanente de 23/10 em `AGENTS.md`.
### Acervo legado — correspondência e preparação QA, 22/10/2026
Fecho do delta privado na homologação: candidata `fb4e7d89` integrada em `65eddf6b`; backup/restauro isolado, transporte privado e cadastro autenticado dos 28 concluídos, sem publicação. Pesquisa/editor/prévia/recuperação conferidos para os 28; gravação/recuperação visual da revisão 3 pela conta real no recurso 32. Originais, registos anteriores e permissões preservados. Recibo `unification/legacy-editorial-installation-receipt-20261022.json` e secção «Legado — cadastro privado concluído na homologação» do manual. Publicação e revisão editorial efectiva cabem à equipa pela interface; dois originais continuam incompletos. Não fecha nem diagnostica a falha separada da carteira/projectos âncora, nem constitui aceitação do commit/pacote pela Tempo.
Actualização do mesmo requisito: os 28 rascunhos têm edição, leitura privada, prévia sem guardar, recuperação e publicação/retirada pela interface em QA, preservando originais, origem e revisões. Seis testes/1.000 asserções, TypeScript e build passaram; publicação positiva apenas em transacções revertidas. Pacote privado v2 preparado com 28 originais e proveniência; não transportado nem publicado na homologação. Guia, permissões existentes, lacunas de imagens, dependências da entrega e reversão na secção «Legado — edição e leitura dos 28 rascunhos em QA» do manual. Pedido funcional expresso da Tempo; hash de âmbito, prévia e controlo de versão são escolhas técnicas, sem novo papel/aprovador. Conserva o saldo de 20 públicos aceites e dois originais incompletos, sem repetir provas ou fechar a integração integral.
Referência do acervo legado, 22/10/2026: a lista única `v2/auditoria-portal/legado-correspondencia-integral.md` e o CSV existente reconciliam 50 identidades (20 publicados, 28 por integrar no destino, um vazio, um sem título). 20/20 páginas conferidas por HTTP anónimo/identidade/origem; cartões de Turismo observados no destino. Os 28 restantes avançaram para rascunhos internos QA, com ClamAV real e repetição idempotente, sem publicação. Recibo e limites no manual, secção «Legado — correspondência integral e avanço privado QA». As duas lacunas editoriais foram confirmadas no original. Não fecha a integração integral nem substitui revisão editorial por prova HTTP; nenhuma alteração activa nesta passagem.
## 25/10/2026 — L5: dispensas e convenção demonstradas em QA
Base de código `2b33a1c3`, ramo `codex/irpc-l5-reliefs-qa-20261025`. O último relatório de instalação mantém o portal nessa entrega; este candidato não executa instalação. O inventário anterior de L3, ISPC, câmbio, fontes e provas aceites é reutilizado. Comparação do delta: sem alteração nesses módulos, em schema/migrações, configuração ou permissões; sem escrita na base activa. As correcções de codificação que tinham atingido trechos históricos durante a preparação foram retiradas do delta; os registos anteriores são conservados.
**Executável:** dispensa 68(d) para serviços/uso de equipamento 67(1)b/g com natureza por conta, titular sujeito a IRPC relativamente ao rendimento; dispensa 68(f) para rendas de sociedade de gestão de imóveis próprios fora da transparência fiscal 6(1)c; limite convencional de 10% sobre royalties/uso de equipamento qualificados PT–MZ, não digitais, titular residente convencional em Portugal, beneficiário efectivo, sem EP em Moçambique, devedor residente em Moçambique e montante sem excesso por relações especiais. As condições são dados documentados do caso, sem aprovador adicional. A selecção de regra não é substituída por texto livre ou taxa manual. Outros ramos continuam separados.
Reutilizados contraparte, residência/EP, documento, qualificação, montante e conversão da linha. Diploma, artigo, período, documentos e condições ficam no mesmo livro e no histórico. Alterar a prova invalida apenas a correspondência do resultado afectado. A dispensa produz retenção zero justificada, apresentada como dispensa, sem isentar o rendimento nem gerar crédito anual. Informação insuficiente, negativa, período incompatível ou artigo divergente fica indeterminada, sem zero/taxa reduzida presumidos. A existência de prova de entrega numa linha dispensada pede reconciliação sem apagar o pagamento.
**Demonstração:** Wayfinder `wayfinder:generate --with-form`, pelo wrapper QA guardado `tools/irpc-reliefs-qa.php routes`; TypeScript passou; compilação completa QA passou. Nove testes novos e cinco verificações dirigidas de compatibilidade IRPC passaram. API privada: um teste/17 verificações, base `simulator_fiscal_delta_20261021_test`, loopback55441, transacção com rollback. Resultados 68(d),68(f), convenção e informação insuficiente recuperados com documentos/histórico. Relatório de retenções, exportação de preparação e dossier financeiro conferidos a partir da recuperação da API. Corrigida a associação da secção «IRPC — retenções» à secção financeira do dossier: a linha existia, mas era omitida nessa apresentação. UI sintética do componente real demonstra cálculo, gravação/recuperação local e relatório; esta prova local é distinta da API privada.
**Reprodução:** gerar routes/actions com `php tools/irpc-reliefs-qa.php routes`; executar `node --test tests/frontend/irpc-reliefs.test.mjs` (produz a amostra sintética); executar `php tools/irpc-reliefs-qa.php test`. Usar PHP8.5/Node24 e dependências existentes. `tsc --noEmit`; compilação `INVESTMOZ_QA_BUILD=1 vp build` no ramo QA. Os módulos gerados são artefactos locais, sem edição manual ou commit.
**Saldo na mesma matriz:** restantes alíneas68, categorias digitais/residentes não correspondidas, outras convenções/Estados e casos com EP, dividendos/juros ou excesso por relações especiais mantêm correspondência própria. Juros de mora, rectificações, agregação, rubricas/CER e preenchimento do MRFTA permanecem discriminados. O cálculo convencional não declara cumpridas as formalidades de accionamento, recepção ou aceitação AT. Não são transportados formulários portugueses21-RFI para obrigações moçambicanas. Pendências condicionam apenas os casos dependentes. L5, IRPC e IRPS não estão integralmente concluídos. L3/ISPC/câmbio não foram retestados; as suas provas são reutilizadas. Entrega conjunta preparada apenas para os recortes demonstrados. Instalação futura segue o procedimento Git e os controlos de destino/backup/restauro já existentes.
Recibo: `docs/investmoz/simulations/irpc-l5-reliefs-qa-20261025.json`; provas locais em `outputs/irpc-reliefs/`.
## 25/10/2026 — dispensas IRPC e convenção PT–MZ instaladas pelo Git
Instalada `ce746d88`, com `2b33a1c3` preservada como release anterior. Backup fresco2026-10-25T18:00:39Z:174 tabelas e369 ficheiros/configuração;restauro isolado em contentor sem rede/55441 passou. Quatro ficheiros de execução conferidos,28 protegidos L3/ISPC/câmbio e29 originais preservados. Schema,permissões e configuração iguais;zero migrações/importações. As172 tabelas de negócio mantêm checksums;apenas cache operacional e sessões anónimas das verificações foram reconciliadas. O mínimo de espaço do instalador foi reposto pelo arquivo e verificação de dependências de5 releases antigas,sem tocar na actual/anterior nem apagar dados/backups.
Manifesto público/revisão servida,8marcadores compilados e simuladorHTTP200 conferidos. Provas QA aceites reutilizadas;CI habitual do procedimento Git passou. Sem ampliar a cobertura:68(d/f) e royalties/uso de equipamento PT–MZ nos casos efectivamente demonstrados. Juros,MRFTA e restantes casos continuam na mesma matriz;L5 permanece parcial. Seguimento em QA separado,sem instalar novos cálculos. Recibo:`irpc-l5-reliefs-delivery-20261025.json`.
## 25/10/2026 — juros e preenchimento MRFTA: incremento QA após ce746d88
O portal mantém a entrega instalada `ce746d88`, com `2b33a1c3` preservada;recibo de instalação `irpc-l5-reliefs-delivery-20261025.json`. Seguimento isolado em `codex/irpc-juros-mrfta-qa-20261025`,sem nova instalação. Reutilizadas as provas aceites;29 originais e29 ficheiros protegidos conferidos por hash. Sem delta de schema,configuração ou permissões.
**Preenchimento:** quadros1–7 do MRFTA de preparação,um mês/ano;identidade fiscal reutilizável entre livros sem sobrescrever edições nem misturar NUIT distintos. Base,taxa,imposto,documentos e entregas vêm do cálculo IRPC guardado. Agrupamento apenas da mesma rubrica/taxa/CER. Retenções sofridas,dispensas e outros períodos ficam separados. CER requer referência aplicável;os números de campos do M/39 antigo não são convertidos em códigos de receita. Rubricas digitais/especiais desconhecidas e múltiplas taxas na mesma rubrica permanecem discriminadas. Quadros8/9 não são assinados/preenchidos pelo portal. Exportação HTML de preparação,não alteração do PDF oficial nem declaração submetida.
**Juros:** Decreto9/2008,25/35,PDF6/8,p121/123 identifica MAIBOR12meses+2p.p.;BM documenta a descontinuidade da publicação. Não foi obtido parâmetro fiscal sucessor aplicável2026;MIMO/Prime não o substituem. Implementada transcrição de juros compensatórios de liquidação documentada,com período,data,montante e referência;ou ausência de atraso quando entrega integral e datas/prazo documentados coincidem. Informação insuficiente não vira zero. Juros de mora continuam por implementar. O subtotal do principal permanece disponível;total do formulário fica indeterminado enquanto faltarem juros,CER,completude ou situação de outras rubricas (IRPS/autónoma),sem isenções ou créditos presumidos. A completude é um dado da preparação,não novo aprovador organizacional.
**Prova do delta:**12 testes novos+1 de apresentação IRPC;TypeScript e compilação QA passaram. API privada1teste/14verificações com rollback no55441;preparação→gravação→recuperação→relatório/dossier. UI real em exemplo sintético:preparação,gravação/recuperação local,informação insuficiente e download HTML;prova API separada. CER999 é fictício de teste,não taxa/código oficial activado. Exemplo:principal20000MZN,entrega3000,juros documentados500,total17500;alterar provas conserva histórico e desactualiza a preparação. Não foram repetidas manualmente suites L3/ISPC/câmbio.
**Saldo:**cálculo automático dos juros e taxa aplicável2026,juros de mora,catálogo CER integral,rubricas digitais/especiais,mistura de taxas e obrigações IRPS/autónomas fora do recorte. Limita apenas as parcelas dependentes;L5/IRPC/IRPS continuam parciais. Recibo `irpc-juros-mrfta-qa-20261025.json`;provas locais `outputs/irpc-mrfta/`.
Reprodução QA: `php tools/irpc-mrfta-qa.php routes`; `node --test tests/frontend/irpc-mrfta.test.mjs`; `php tools/irpc-mrfta-qa.php test`. PHP8.5,Node24,dependências existentes;alvo e identidadeQA guardados antes de fornecedores/testes.
## 25/10/2026 — entrega5fa64bc0 instalada;seguimento restrito a juros/CER em QA
Instalada pelo Git a revisão exacta `5fa64bc0`,com `ce746d88` preservada como release anterior. Backup fresco2026-10-25T18:28:38Z;174tabelas e369ficheiros/configuração;restauro isolado sem rede/55441 passou. Quatro ficheiros de execução,29protegidos e30originais conferidos. Schema,permissões e configuração iguais;zero migrações/importações. As172tabelas de negócio mantêm checksums;apenas cache operacional e sessões anónimas da instalação/verificação foram reconciliadas. Revisão/manifesto públicos,8marcadores compilados e simuladorHTTP200 passaram. Provas aceites reutilizadas,sem nova ronda manual;CI habitual do instalador passou.
Cobertura instalada:preparação por período,registo de juros documentados e relatório/exportação MRFTA. Registar não significa calcular automaticamente;CER/rubricas desconhecidos continuam identificados sem preenchimento presumido. Não houve submissão ou aceitação AT. Seguimento isolado apenas de juros automáticos eCER/rubricas;L5continua parcial,L3/ISPC/câmbio preservados. Recibo:`irpc-mrfta-delivery-20261025.json`.
## 25/10/2026 — seguimento QA restrito: juros automáticos e casos CER/rubricas
Portal instalado em `5fa64bc0`,com `ce746d88` preservada;recibo `irpc-mrfta-delivery-20261025.json`. Novo ramo `codex/irpc-interest-cer-qa-20261025`,sem instalação. Não foram reabertos outros saldos L5.
**Juros:** nova aritmética racional diária por parâmetros documentados do caso:taxa anual final,fonte/fundamento fiscal,vigência na data de liquidação,base anual,arredondamento do total e ocorrência. Nenhum valor vem pré-definido. Intervalos começam no dia posterior ao prazo documentado;entregas reduzem a base após o seu dia e o pagamento integral pára encargos. Contagem por ano/base365/366 e arredondamento só conforme convenção preenchida com referência. Definitiva e por conta retida cobertas neste recorte;por conta não retida e mora mantêm regra própria. Sem perfil completo,juros indeterminados e principal preservado. A taxa10%,base365 e convenções dos testes são fictícias,sem activação de parâmetro fiscal2026. O registo de liquidação documentada da entrega instalada mantém significado e histórico.
**CER/rubricas:** separação estável por período,rubrica,taxa e CER,com documentos e referências. Fichas de trabalhoHTML independentes conservam as pendências globais;não são declarações autónomas,anexos oficiais nem uma taxa média. Teste integrado distingue retenções20%/10% e CERfictícios999/998;juros por perfil permanecem demonstráveis,mas o total do formulário continua indeterminado pela transposição de rubricas distintas. Ausência de código ou referência continua identificada,sem preenchimento presumido. Nenhum catálogo CER oficial foi acrescentado.
**Compatibilidade/provas:** campos novos adicionais conservam os modos conhecidos pelo leitor5fa64bc0. Prova só de leitura/gravação exacta do novo payload nesse leitor:retenções actuais e nova preparação histórica,sem executar novamente cálculos antigos. Preservados31ficheiros de execução e30originais por hash. TypeScript,buildQA e13testes novos passaram;API1teste/19verificações com rollback em55441. UI:parâmetro fictício explícito,sem taxa→indeterminado,gravação/recuperação,relatório e download de casos20%/999 e10%/998. Relatório do dossier a partir da recuperação API. Provas aceites L3/ISPC/câmbio e5fa64bc0 reutilizadas;sem nova ronda manual das suites antigas.
**Saldo,apenas os mesmos dois pontos:** (1)corresponder fonte/parâmetro fiscal vigente2026 e convenções aplicáveis,além dos ramos mora/por conta não retida fora desta aritmética;(2)corresponder catálogo CER/rubricas ainda pendentes e procedimento oficial para taxas/códigos distintos. O inventário oficial AT189documentos foi consultado por metadados,não relido integralmente;nenhuma taxa/código foi inferido de rascunho,número de campo,agregado orçamental,MIMO ouPrime. L5 continua parcial. Recibo `irpc-interest-cer-qa-20261025.json`;provas em`outputs/irpc-interest-cer/`.
Reprodução do delta em QA: `php tools/irpc-interest-cer-qa.php routes`;`node --test tests/frontend/irpc-interest-cer.test.mjs`;`php tools/irpc-interest-cer-qa.php test`. Dependências existentes,PHP8.5/Node24;alvo QA guardado antes dos fornecedores/testes.
## 25/10/2026 — esclarecimentos concretos para a AT (AUD-SIM-INT02, L5 parcial)
Esta discriminação desenvolve os mesmos dois pontos; não cria outra matriz nem reabre provas aceites. Base instalada: `5fa64bc0`; funcionalidade demonstrada em QA: `acf8ec3c`. Os exemplos abaixo são perguntas de aplicação, não parâmetros ou códigos oficiais. Não foram enviados à AT por este registo.
| Dúvida na mesma matriz | Parâmetro ou correspondência exacta em falta / esclarecimento a obter | Exemplo para acompanhar o esclarecimento | Comportamento enquanto falta |
|---|---|---|---|
| J1 — taxa e vigência | Valor anual final aplicável na data de liquidação em 2026, incluindo eventual acréscimo; série/diploma sucessor da referência MAIBOR 12 meses + 2 p.p., fonte, início e fim de vigência (`annualRate`, `rateSource`, `fiscalBasis`, `validFrom`, `validTo`). | Retenção definitiva de 7 300 MZN, prazo documentado 20/11/2026 e liquidação em 30/11/2026: qual taxa anual final usar? Os 10% do ensaio são fictícios. | Sem taxa predefinida; não substituir por MIMO/Prime. Perfil completo permite apenas simulação pelos dados introduzidos. |
| J2 — contagem diária | Base anual aplicável: 365, 366 ou dias efectivos por ano (`dayBasis`, `dayBasisRef`); incidência do dia da entrega parcial e divisão de períodos entre anos. | Mesmo principal de 7 300 MZN, entrega de 3 650 em 25/11 e liquidação em 30/11: a redução começa em 26/11? Num intervalo 31/12/2027–02/01/2028, qual denominador em cada ano? | Motor demonstra dia posterior ao prazo, dia da entrega incluído e redução no dia seguinte; só usar como pressuposto de simulação até esclarecer a aplicação. |
| J3 — arredondamento | Método e momento oficiais: total ou parcela/dia, cêntimos, metade por excesso ou outra convenção (`rounding`, `roundingRef`). | 7 300 MZN × taxa fictícia 10,0025% × 10/365 = 20,005 MZN: declarar 20,00 ou 20,01? Arredondar só o total ou cada segmento? | As duas opções do motor são convenções explícitas de simulação; outra convenção mantém o caso por implementar. |
| J4 — retenção por conta não efectuada | Regra e datas específicas dependentes da declaração/liquidação anual, base e limite temporal; não equiparar a retenção efectuada ou definitiva (`retention`, `occurrenceRef`). | Retenção por conta de 7 300 MZN não efectuada em Novembro/2026: até que evento anual se contam juros e sobre que montante? | Ramo indeterminado; não herda a fórmula do ramo demonstrado. |
| J5 — mora | Taxa, fundamento, início/fim, base após pagamentos e articulação com juros compensatórios, evitando duplicação. | Liquidação documentada de compensatórios, com saldo de imposto de 3 650 MZN ainda não pago após o prazo: quando começa a mora e sobre que parcelas? | Mora não calculada; registo de liquidação documentada mantém-se independente. |
| C1 — CER de capitais e prediais por conta | Código CER exacto e referência/versão para cada rubrica “Taxa normal — Rendimentos de capitais e mais valias” e “Taxa normal — Rendimentos prediais”. | Dois pagamentos no mesmo mês: juros de financiamento e renda de imóvel, ambos com retenção por conta: quais CER respectivos? São códigos distintos? | CER por identificar; nome da rubrica já correspondido não prova o código. |
| C2 — CER das quatro rubricas liberatórias | Código CER exacto e referência/versão por rubrica: actividade intelectual/industrial e informações; uso de equipamento; aplicação de capitais e rendimentos prediais; comissões/intermediação/prestação de serviços. | No mesmo período, royalties, aluguer de equipamento, juros e comissão a não residentes: indicar o CER de cada natureza e eventual distinção adicional. | Cada natureza permanece separada; não reutilizar números de campos do M/39 como CER. |
| C3 — rendimentos digitais/especiais | Rubrica MRFTA e CER exactos para cada categoria não correspondida, conforme qualificação fiscal documentada; distinguir de serviços comuns. | Pagamento a não residente por serviço digital já qualificado no livro IRPC: em que rubrica/CER deve ser transcrito? Um serviço comum tem a mesma correspondência? | Categoria sem correspondência continua pendente; não copiar para serviços comuns por aproximação. |
| C4 — taxas diferentes na mesma rubrica | Forma oficial de transcrever várias taxas: linhas adicionais, anexo ou outro procedimento, com indicação dos campos; confirmar se o CER varia com regime/convenção. | Royalties de base 10 000 MZN à taxa interna de 20% e outros de 10 000 à taxa convencional demonstrada de 10%, no mesmo mês: como apresentar bases/impostos sem taxa média? | Duas fichas de trabalho; total oficial permanece indeterminado enquanto depender dessa transposição. |
| C5 — códigos diferentes na mesma rubrica | Forma oficial de conservar códigos distintos no mesmo período/rubrica e regra de totalização/entregas; obter os códigos reais antes de preencher. | Duas parcelas agrupáveis por rubrica mas com CER distintos segundo documentos do caso: uma ou várias linhas/guias? Nos ensaios, 999/998 são apenas marcadores fictícios. | Separar período/rubrica/taxa/CER; não inventar declarações autónomas nem reconhecer marcadores como oficiais. |
**Entrega funcional independente:** aritmética pelos pressupostos explicitados, reconciliação de entregas, gravação/recuperação/relatório e fichas separadas podem acompanhar a entrega. Interface e exportações identificam simulação e CER introduzido sem validação por catálogo; referência digitada não equivale a confirmação fiscal. Não activar taxa ou catálogo global por esta entrega. A ausência de dados conserva indeterminação e principal. As respostas da AT poderão completar apenas as células correspondentes, com fonte e vigência, sem outra pesquisa genérica ou nova aprovação inventada.
**Preservação:** L3, ISPC, câmbio, `ce746d88` e `5fa64bc0` conservam provas aceites; nenhum caso aceite foi reaberto. L5 permanece parcial. O presente delta de apresentação/documentação não altera schema, API, permissões, originais ou regras de retenção.
## 25/10/2026 — L5 operacional no âmbito demonstrado; entrega 7a11c4ef
Instalado pelo Git `7a11c4ef8f06ef149eb0488be3cd0749dc609bd0`, sobre `5fa64bc0`, sem força, migrações ou importações. Backup fresco em 25/10/2026 19:14:23 UTC, restaurado em PostgreSQL isolado (rede nenhuma/porta55441):174 tabelas por contagem/checksum. Conferidos4ficheiros do delta,31protegidos,30originais e369ficheiros/configuração persistentes. Schema,roles/grants e permissões conservados.172tabelas de negócio iguais;cache/sessões reconciliadas com reinício da fila,throttle e sessões anónimas da verificação. Versão5fa64bc0 conservada como anterior;L3,ISPC,câmbio e provas aceites preservados. Arquivadas e verificadas dependências de8versões antigas para respeitar espaço mínimo,sem eliminar fontes,dados ou backups nem modificar versões actual/anterior.
Revisão/manifest públicos,8marcadores compilados,4assets e simuladorHTTP200 conferidos. Pipeline normal:1teste/3106asserções,59testes/317asserções,872testesfrontend,tipo/build;sem outra ronda manual das provas aceites. Recibo:`irpc-interest-cer-delivery-20261025.json`.
**L5 fica operacional apenas no âmbito demonstrado**, incluindo preparação por período,registo de juros documentados,simulação por pressupostos explícitos e fichas separadas porCER/rubrica/taxa. Não confirma fiscalmente juros nem converte códigos provisórios em correspondências oficiais. As dez dúvidas J1–J5/C1–C5 da secção anterior acompanham a reunião com a AT;permanecem pendentes e não foram enviadas por esta operação. Sem informação nova,não reabrir a pesquisa desses pontos. Não declararL5 integralmente concluído.
**Sequência autorizada:**L6—IRPC normal,começando pela ponte do resultado financeiro aos ajustamentos documentados. Retenções/créditos anuais,amortizações,perdas e colecta conservam desenvolvimento próprio;nenhuma pendênciaL5 bloqueia o primeiro recorte independenteL6.
## 25/10/2026 — L6 iniciado em QA: primeiros ajustamentos ao resultado financeiro
Base instalada7a11c4ef;L5 operacional apenas no âmbito demonstrado. Primeiro recorteL6 reutiliza a ponte financeira reconciliada por oportunidade,receitas/custos discriminados e resultado antes de imposto. Corresponde explicitamente12meses aJan–Dez2026,MZN,sujeito residente no regime geral fora de transparência/regimes especiais. Projecção com pressupostos,não demonstração contabilística confirmada. Art17(1)é enquadramento da ponte,não equivalência automática do resultado antes de imposto ao lucro tributável.
Implementados acréscimos integrais36(1)c de multas/encargos por infracções sem origem contratual e juros compensatórios já incluídos no custo de origem. Documento/linha,qualificação,montante e inclusão têm suporte/pressuposto expresso. Não classifica juros comerciais nem multas contratuais por aproximação,não importa juros simuladosL5 como despesa efectiva. Limites por custo da origem e duplicação documental previnem dupla contagem. Encargo já excluído não é acrescentado de novo. Lacuna limita a respectiva parcela;acréscimos independentes continuam disponíveis,resultado parcial agregado indeterminado se houver parcela não resolvida.
Exemplo sintético:resultado financeiro6480MZN,multa100 e juros compensatórios20 incluídos;acréscimos120,resultado parcial6600. Sem suporte da multa:apenas20 demonstrados,resultado parcial indeterminado. Lucro tributável,matéria colectável e imposto permanecem indeterminados em todos os casos. Outros ajustamentos,custos/variações patrimoniais,amortizações,perdas,deduções/colecta,créditos anuais eM20/M22 seguem por recortes próprios;EP/regimes especiais,outra moeda/exercício/horizonte não abrangidos.
Prova do delta:7testes novos;APIprivada1teste/19asserções comrollback naQA55441;routes/actions gerados pelo procedimentoWayfinder;TypeScript/buildQA passaram. UI real:cálculo,gravação/recuperação local,relatório,informação insuficiente e download;API demonstrada separadamente,dossier gerado da recuperaçãoAPI. LivroL6 separado mantém payloadL5 e restante histórico;alterar plano/entradas torna resultado histórico sem o apagar.32ficheiros anteriores protegidos e30originais sem alteração;integração mínima emsimulation-form/project-dossier/project-dossier-report. Provas aceites não repetidas. Recibo:`irpc-l6-adjustments-qa-20261025.json`;QA isolada,sem instalaçãoL6.
Fonte adicional necessária apenas paraL6:exemplar oficialAT intitulado19/2009 contém tambémLei20/2009;PDF4/p272(16),36(1)a–i mantidas ealíneasj–n aditadas,conferido visualmente. Lei4/2012PDF2/3 e19/2013PDF1/2 mantêm36(1)c. Não reabre as dez dúvidasL5,que ficam paraAT até informação nova. L5 eL6 não integralmente concluídos.
## 25/10/2026 — L6: percurso delimitado até ao lucro tributável demonstrado em QA
Base instalada `7a11c4ef`; primeiro recorte QA `664c88c8` preservado. A continuação reutiliza o plano reconciliado, o exercício, a oportunidade e os ajustamentos existentes. Não obriga a reintroduzir os montantes financeiros. Âmbito: projecção de Janeiro a Dezembro de 2026, MZN, sujeito residente no regime geral, com referência expressa de que o cenário cobre o sujeito passivo/exercício completo. Uma oportunidade parcial não se transforma automaticamente no total da empresa.
Cada linha do resultado exige qualificação ordinária e suporte: proveitos do exercício (18/20), custos remanescentes indispensáveis e documentados (22), sem outras exclusões/limites declarados. Os acréscimos 36(1)c reutilizam documentos e parcelas já registados. Seis grupos conservam a situação das variações patrimoniais positivas/negativas fora do resultado, outras correcções de rendimentos/custos, diferenças de periodização e operações especiais. **Valor conhecido (incluindo zero), ausência declarada com suporte e informação em falta são estados distintos.** Ausência não pode apagar uma origem financeira positiva ou descartar um montante já preenchido. Um valor conhecido não zero sem tratamento implementado permanece visível e impede apenas o fecho dependente, sem ser aplicado por presunção.
No caso ordinário delimitado, resultado financeiro + acréscimos fundamentados = lucro tributável simulado quando a conferência anual está completa e os outros efeitos são expressamente ausentes ou de valor conhecido zero. Exemplo sintético: 6480 + multa100 + juros compensatórios120 = 6700 MZN. Os 120 são um custo/pressuposto qualificado já incluído na origem; não são juros automaticamente calculados ou fiscalmente confirmados por L5. Falta de prova da variação patrimonial negativa mantém o lucro indeterminado, conservando resultado6480 e acréscimos220. Variação conhecida500, depreciação positiva ou juros financeiros remanescentes mantêm correspondência específica pendente. Sem acréscimos, uma conferência completa pode conservar o resultado financeiro; resultados negativos não são convertidos em zero nem em crédito/perda reportável.
Prova do delta: 9 testes novos; API privada 1 teste/38 verificações, criação → alteração com If-Match → recuperação, com rollback na QA isolada55441. Wayfinder gerou routes/actions; TypeScript e buildQA passaram. UI real: cálculo, gravação/recuperação local, valor conhecido zero, ausência, informação em falta, contradição e exportação HTML. Relatórios/dossiers dos casos conhecido e incompleto gerados a partir da recuperação efectiva da API. Versão2 adicional mantém o snapshot/resultado1 de664c88c8 legível e actual sem o recalcular; mudanças nas entradas desactualizam apenas o novo resultado e conservam histórico. Preservados33ficheiros anteriores de execução e31originais por hash;integrações anteriores de formulário/dossier não alteradas neste delta. Provas aceites L3/ISPC/câmbio/L5 reutilizadas, sem nova ronda manual.
**Preparação conjunta para entrega pelo Git:** primeiro recorte664c88c8 e continuação até lucro tributável, sobre7a11c4ef, com pacote/manifest e delta conferido. Não instalado nem integrado em main por esta preparação. Backup/restauro fresco e conferência do destino fazem parte da instalação posterior; não reutilizar como fresco o backup da entregaL5. Recibo `irpc-l6-taxable-profit-qa-20261025.json`; provas `outputs/irpc-l6-profit/` na QA isolada.
Matéria colectável, perdas reportadas, deduções, colecta, créditos de retenção e M20/M22 continuam fora deste percurso; L6 não está integralmente concluído. L5 permanece operacional no âmbito demonstrado; J1–J5/C1–C5 ficam para a AT e só limitam os casos efectivamente dependentes. Nenhuma nova pesquisa de taxas/CER de L5 foi feita.
## 25/10/2026 — entrega conjunta L6 até lucro tributável instalada:5e02c23a
Instalado pelo Git `5e02c23af863485f6881e409c8704ec7e7573cc9`, sobre `7a11c4ef`, incluindo o primeiro recorte664c88c8. Backup fresco de25/10/2026 19:38:10UTC,restauro isolado sem rede na porta55441:174tabelas conferidas por contagem/checksum. Conferidos6ficheiros do delta,33protegidos,31originais e369ficheiros/configuração persistentes. Schema,roles/grants e permissões iguais.172tabelas de negócio preservadas;cache/sessões reconciliadas com reinício da fila,throttle e sessões anónimas da verificação.7a11c4ef conservado como versão anterior. Arquivadas/verificadas dependências de4versões antigas para margem de espaço,sem eliminar fontes,dados ou backups nem modificar as versões actual/anterior.
Revisão/manifest servidos,10marcadores compilados,4assets e simuladorHTTP200 conferidos. Pipeline normal:1teste/3106asserções,59testes/317asserções,888testesfrontend,tipo/build;sem outra ronda manual das provas aceites. Recibo:`irpc-l6-profit-delivery-20261025.json`.
**Disponível no âmbito demonstrado:**resultado financeiro6480+acréscimos220=lucro tributável simulado6700MZN;estados conhecidos,ausência declarada e informação em falta preservados. **6700MZN não é imposto a pagar.** Matéria colectável,deduções/perdas e colecta não são concluídas por esta instalação. L6 permanece parcial;dúvidasL5J1–J5/C1–C5 só limitam casos efectivamente dependentes. Continuação independente emQA para matéria colectável,sem repetir pesquisa ou provas aceitesL5/L3/ISPC/câmbio.
## 25/10/2026 — L6 matéria colectável: perdas próprias e deduções delimitadas em QA
Base instalada `5e02c23a`, com lucro tributável simulado6700MZN; não é imposto a pagar. A continuação reutiliza esse resultado e a identidade fiscal já disponível na mesma oportunidade, mediante acção expressa que conserva edições. Recorte: sujeito residente no regime geral,2026,método declarativo/directo,perdas fiscais próprias em exercícios anuais ordinários. CIRPC15(1)a/15(2–4) e41(1–7),PDF5/p768(59) ePDF12/p768(66),conferidos nos originais aceites;cadeia de alterações existente reutilizada. Sem novos originais ou pesquisa dos pontosL5.
Livro de perdas por exercício e sujeito:montante fiscal apurado/corrigido,utilizações anteriores,saldo disponível e utilização proposta deste ano,com documentos e completude. Não usa perda contabilística como fiscal. Confere cinco exercícios ordinários posteriores,manutenção/alteração da actividade/objecto no termo do exercício,regime geral e saldo corrigido. Métodos indirectos,períodos especiais/curtos,transparência/isenção parcial,transferências/fusão41-A e correcções pendentes ficam fora do recorte. Expiração/exclusão conhecidas não são apagadas;pedido positivo contra perda excluída exige reconciliação. Utilização proposta é expressa,sem FIFO obrigatório,percentagem inventada ou saldo negativo;excesso sobre saldo/lucro mantém base indeterminada. Simular/gravar não consome o saldo oficial nem actualiza utilizações anteriores.
Exemplo sintético:lucro6700;perda2021apurada1000/utilizada200/saldo800/proposta800;perda2024apurada3000/utilizada500/saldo2500/proposta1500. Dedução2300,**matéria colectável simulada4400MZN**,saldos aritméticos0/1000. **Imposto a pagar permanece indeterminado.** Perda ordinária2020 expira após2025;2021pode ser usada em2026 no recorte demonstrado. Sem perdas/benefícios,ausência expressa e suportada pode conservar base6700;informação em falta não ézero. Benefício conhecido positivo é conservado com referência,mas não subtraído sem regra/condições/limite específicos. Deduções à base15(4) são distintas de efeitos já conferidos no lucro e de créditos à colecta/retenções. Resultado actual negativo permanece conhecido,sem basezero ou reporte automático neste recorte.
Prova do delta:10testes novos;APIprivada1teste/42verificações,criação→alteração comIf-Match→recuperação,rollback naQA55441. Routes/actions peloWayfinder,tipo/buildQA passaram. UI:cálculo4400,gravação/recuperação local,alteração expressa de utilização para700→base4500,repetição sem consumo,sobreutilização recusada,download,informação em falta e benefício positivo conservado sem subtracção. Dossier/HTML gerados da recuperação efectiva daAPI. Versão3 opcional conserva resultado2 actual e históricos1/2;alteração de entradas desactualiza apenas o novo resultado.37ficheiros anteriores de execução e31originais preservados por hash. Provas aceites reutilizadas,sem nova ronda manual. Recibo:`irpc-l6-taxable-base-qa-20261025.json`;QA isolada,sem instalação deste incremento.
L6 continua parcial. Colecta/imposto,créditos anuais,M20/M22,benefícios positivos e casos fora do recorte mantêm desenvolvimento próprio. As dúvidasL5J1–J5/C1–C5 só limitam casos efectivamente dependentes;nenhuma taxa de juros ou CER provisório foi promovido a confirmação fiscal.
## 25/10/2026 — L6 colecta normal demonstrada em QA; entrega conjunta com a matéria colectável
Portal mantém `5e02c23a`. A continuação parte da QA `b8d45796` e reutiliza a matéria colectável actual, sem reintroduzir montantes. No recorte de sujeito residente em regime normal/MZN, exercício anual de01/01/2026 a31/12/2026, o enquadramento explícito do artigo61(1) aplica a taxa geral32%. A fonte/versão, período, classificação e suporte/pressuposto do caso são guardados. Campo por identificar ou caso especial não recebe taxa geral por aproximação; a matéria colectável conhecida permanece disponível.
**Sequência demonstrada:**lucro tributável simulado6700 → matéria colectável simulada4400 → colecta simulada4400×32%=1408MZN → **saldo final a pagar ou recuperar indeterminado, âmbitoL8**. Retenções, pagamentos e créditos do fecho anual não são abatidos nem reconciliados nesta etapa. Colecta não é saldo final. O campo legado `tax` continua nulo e o novo modelo guarda `colecta` separadamente; `finalBalance` mantém pagar/recuperar nulos, não zero.
Taxa32% conferida no CIRPC Lei34/2007,PDF17/p768(71). Lei4/2012 altera61(2); Lei20/2022PDF1/p2731 mantém61(1) e delimita medidas temporárias61(2) até31/12/2025; Lei12/2025PDF18/20 não altera61(1) e distingue61-A. Taxas reduzidas, benefícios, tributação autónoma e mais-valias continuam com tratamento próprio, mesmo se uma percentagem coincidir. Nenhuma extensão temporal/benefício foi inferida. A aritmética é racional exacta; eventual fracção de cêntimo é conservada sem arredondamento fiscal inventado. Não preenche/submeteM20/M22.
Prova do delta:8testes novos;APIprivada1teste/40verificações com criação→alteraçãoIf-Match→recuperação e rollback naQA55441. Wayfinder gerou routes/actions;TypeScript e buildQA passaram. UI real:base reutilizada,colecta1408,taxa/período/enquadramento visíveis,sequência ordenada,gravação/recuperação local,download e casos especiais/informação em falta sem taxa presumida. Dossier/HTML dos casos conhecido e incompleto gerados da recuperação efectiva daAPI. Versão4 opcional conserva versões1/2/3 e o resultado3 actual sem recálculo;mudanças nas entradas desactualizam só o novo resultado e conservam histórico.39ficheiros anteriores daQA e37do portal preservados,31originais sem alteração. Provas aceites reutilizadas,sem outra ronda manual. Recibo:`irpc-l6-colecta-qa-20261025.json`.
**Preparação conjunta compatível:**matéria colectávelb8d45796 e colecta normal neste candidato,base5e02c23a,6ficheiros de execução no delta conjunto. PacoteGit/provas/manifest conferidos apóscommit;sem integração emmain ou instalação nesta preparação. Instalação futura mantém procedimento de destino autenticado,backup/restauro fresco e conferência do delta. L6 continua parcial. Benefícios e casos especiais permanecem explícitos;L8 conserva o fecho anual e as dúvidasL5 só limitam os casos efectivamente dependentes.
## 25/10/2026 — entrega conjunta matéria colectável/colecta instalada:2f684e59
Instalado pelo Git `2f684e59846187f3fb8a338d9d6f6a08cadb4d0d`, incluindo a matéria colectávelb8d45796, sobre `5e02c23a`, sem força, migrações ou importações. Backup fresco de25/10/2026 20:05:19UTC;restauro em base isolada sem rede/porta55441:174tabelas conferidas por contagem/checksum. Conferidos6ficheiros do delta,37protegidos,31originais e369ficheiros/configuração persistentes. Schema,roles/grants e permissões iguais;172tabelas de negócio preservadas. Cache/sessões reconciliadas com reinício da fila,throttle e sessões anónimas da verificação.5e02c23a permanece disponível como versão anterior. Arquivadas/verificadas dependências de4versões antigas para margem de espaço,sem eliminar fontes,dados ou backups nem modificar as versões actual/anterior.
Revisão/manifest públicos,11marcadores compilados,4assets e simuladorHTTP200 conferidos. Pipeline normal:1teste/3106asserções,59testes/317asserções,906testesfrontend,tipo/build. Provas aceites reutilizadas,sem outra ronda manual. Recibo:`irpc-l6-colecta-delivery-20261025.json`.
**Disponível no âmbito demonstrado:**lucro tributável simulado6700→matéria colectável4400→colecta normal32%/2026=1408MZN. **1408MZN não é saldo final a pagar.** A pagar/a recuperar continuam indeterminados emL8. Benefícios/casos especiais anuais sãoL7. O saldo concreto deL6 que justifica «parcial» fica discriminado na secção seguinte;esta actualização substitui,para o estado actual,as pendências genéricas de lucro/base/colecta anteriores já entregues,preservando-as apenas como histórico.
## 25/10/2026 — saldo concreto de L6 após a entrega 2f684e59
Esta discriminação actualiza **AUD-SIM-INT02 na mesma matriz**, com o âmbito L6/L7/L8 já registado no plano consolidado e a leitura do código de `2f684e59`. Não cria outro lote, matriz ou backlog. O estado «L6 parcial» decorre das lacunas funcionais abaixo; **não decorre de faltar o saldo anual de L8 ou os tratamentos de L7**. Os exemplos são casos de fronteira para desenvolvimento, não novos cálculos fiscais confirmados.
**Concluído no âmbito demonstrado e a preservar:** plano financeiro reconciliado → acréscimos36(1)c → lucro tributável6700 → perdas próprias ordinárias2300 → matéria colectável4400 → colecta normal32%/2026=1408MZN. Inclui conhecido/zero/ausência/falta de informação, limites de utilização, gravação/recuperação, histórico, relatório/exportação e indeterminação dos casos dependentes. Não repetir estas provas para fechar os pontos seguintes, excepto se o delta os afectar.
| Saldo que continua em L6 | Evidência concreta no código entregue | Exemplo do caso ainda não coberto | Critério concreto de fecho |
|---|---|---|---|
| Outros ajustamentos ordinários: admissibilidade de custos e correcções aos proveitos | `irpc-normal.ts`, `NormalAdjustment.rule` e `calculateNormal`: apenas multas não contratuais e juros compensatórios36(1)c; `other` fica fora do recorte. `irpc-normal-profit.ts` não aplica `incomeCorrections`/`expenseCorrections` conhecidos não zero. | Encargo de terceiro de250MZN com qualificação36(1)b, ou despesa não documentada36(1)g, incluído no resultado; a correcção não tem regra executável neste livro. A eventual tributação autónoma é outra operação, emL7. | Corresponder a regra geral e condições de cada categoria incluída, calcular acréscimo/dedução/exclusão com sinal e origem, evitar dupla contagem e demonstrar reflexo no lucro, base e colecta. A tributação autónoma que possa coexistir pertence aL7. |
| Dedutibilidade dos juros financeiros ordinários | `irpc-normal-profit.ts`, `closeNormalProfit`: qualquer remanescente não zero de `interest_expense` mantém pendência; só os compensatórios integralmente acrescidos estão cobertos. | Juros de financiamento comercial de120MZN, distintos de juros compensatórios, com finalidade/custo documentados. | Qualificar a parcela ordinária, dedutibilidade e correcção aplicável, conservar os montantes reconhecidos/pagos separados e fechar o lucro sem a equiparar a infracção. Relações especiais/benefícios e regras especiais seguemL7; taxa de juros compensatóriosL5 só é dependência se esse cálculo for efectivamente usado. |
| Reintegrações/amortizações fiscais e diferença face à contabilidade | `irpc-normal-profit.ts`: `depreciation` positivo bloqueia o fecho; não existe mapa fiscal de activos/quotas nesta família de módulos. | Depreciação contabilística120MZN com quota fiscal do activo ainda por corresponder. | Reutilizar activo, base e datas; corresponder método/taxa/limites e afectação ordinários, calcular quota fiscal e diferença para o resultado; manter mapas por activo/exercício e histórico. Incentivos, majorações e regimes especiais de activos seguemL7. |
| Variações patrimoniais e periodização ordinárias de montante não zero | `irpc-normal-profit.ts`, `profitTopics`/`closeNormalProfit`: `positivePatrimonial`, `negativePatrimonial` e `timing` conhecidos não zero conservam valor e impedem o fecho; ausência/zero suportados são o caminho demonstrado. | Variação500MZN fora do resultado, ou diferença temporal300MZN entre reconhecimento contabilístico e exercício fiscal, com natureza concreta documentada. | Corresponder natureza/ano/regra ordinária e decidir inclusão, exclusão ou ajustamento com sinal; impedir reaplicação em dois exercícios; demonstrar cálculo→gravação→recuperação→relatório. Operações especiais/benefícios do tópico `special` não são saldo deL6. |
| Resultado fiscal negativo do próprio exercício | `irpc-normal-base.ts`, `calculateNormalBase`: lucro negativo é conservado, mas a base fica indeterminada; o livro de perdas só admite exercícios anteriores ao de utilização. | Resultado fiscal actual−500MZN conhecido; não é uma perda anterior dedutível a si própria. | Tratar a situação da base/colecta nesse exercício e preparar a perda fiscal própria com origem/ano para utilização futura, conforme regra aplicável, sem confundir ausência de lucro, falta de informação, crédito ou consumo do saldo oficial. Perdas anteriores ordinárias já demonstradas continuam aceites. |
| Extensões do âmbito normal previstas no L6 original | `irpc-normal.ts` fixa12meses/ano civil2026/residente/MZN; `irpc-normal-base.ts` exige exercícios anuais ordinários; a entrada deL6 no plano original inclui exercício fiscal e residência/EP. | Caso de estabelecimento estável sob regime geral, ou período fiscal normal diferente do calendário/horizonte do plano; plano noutra moeda ainda sem reconciliação fiscal anualMZN. | Delimitar os casos normais a admitir, imputação de resultados ao sujeito/EP, datas/períodos e reconciliaçãoMZN usando o câmbio já entregue; demonstrar o percurso dependente. Não reimplementar câmbio, exigir pesquisa de todos os anos históricos ou aplicar automaticamente32% fora do período correspondido. Benefícios/convenções/regimes específicos pertencem aos lotes próprios. |
| Representação fiscal da colecta com fracção de cêntimo | `irpc-normal-assessment.ts` conserva o racional e assinala `centExact:false`; não aplica regra fiscal de arredondamento/transcrição. | Base0,01MZN×32%=0,0032MZN exactos; o caso1408MZN não tem esta ambiguidade e continua válido. | Identificar e executar a convenção aplicável à colecta/representação do formulário, mantendo o exacto e a rastreabilidade do valor transcrito. Não importar por analogia arredondamento de prestações/pagamentosL8 nem criar uma regra por defeito. |
| Correspondência dos dados de L6 aos exemplares M/20/M/22 | A família `irpc-normal*` produz mapaHTML/dossier e exclui expressamente correspondência/transcrição oficial; o âmbito original deL6 inclui M/20/M/22 e diferenças de ediçãoPDF/XLSX. | Resultado, correcções, perdas, base4400 e colecta1408 existem no mapa de trabalho; os respectivos campos/anexos aplicáveis dos exemplares não estão correspondidos no motor. | Cotejar os exemplares já inventariados e mapear apenas os dados deL6 aos campos/versões efectivamente aplicáveis, com prova de preenchimento/recuperação. Os campos de retenções,pagamentos,créditos e saldo final sãoL8. Submissão electrónica/aceitaçãoAT não são presumidas como parte desta correspondência. |
**Encaminhado a L7, sem manter L6 parcial por essa razão:** benefícios/isenções da determinação anual do IRPC, taxas reduzidas/cooperativas, tributação autónoma de despesas e mais-valias61-A, operações especiais, perdas transmitidas/fusão41-A e segregação de regimes especiais. Uma dedução positiva de benefício à base continua sem aplicação no recorte entregue, mas o trabalho substantivo desse benefício éL7, não uma dedução livre nem um novo saldo genérico deL6. A integração posterior usa as interfaces/versionamento já existentes e afecta só os casos dependentes.
**Encaminhado a L8, sem manter L6 parcial por essa razão:** retenções sofridas a imputar ao fecho anual, PPC/PEC e outros pagamentos, créditos/deduções à colecta, dupla tributação quando aplicável, limites/transportes respectivos, reconciliação e saldo final a pagar ou recuperar/calendário. **1408MZN é colecta; pagar e recuperar continuam indeterminados.** Não abater parcelas L5 nem promover os seus códigos/taxas provisórios ao fecho anual nesta entrega.
**Informação do caso, distinta de desenvolvimento em falta:** falta de documento, NUIT, completude anual, montante, prova de saldo ou qualificação dentro de uma regra já implementada mantém o caso indeterminado, mas não constitui por si só outra tarefa deL6. O mesmo vale para a ausência de uma nova prova de uma funcionalidade já aceite. Não exigir nova aprovação genérica das fontes oficiais, novo aprovador ou repetição deL3/ISPC/câmbio/L5. Anos não incluídos no recorte temporal não se tornam automaticamente um projecto de cobertura histórica integral.
**Ordem de continuação delimitada:** ajustamentos ordinários/juros financeiros e amortizações; depois variações/periodização e resultado negativo; ampliar apenas os casos normais concretamente abrangidos e concluir a representação/correspondência dos dados deL6. Cada fecho deve demonstrar o delta e substituir a pendência correspondente nesta mesma linha/nota. Não há estimativa nova nem declaração deL6 integralmente concluído nesta revisão documental.
## 25/10/2026 — L6: três conjuntos compatíveis em QA sobre 2f684e59
Actualização de **AUD-SIM-INT02**, na matriz existente. O percurso instalado em `2f684e59` permanece aceite: lucro6700 → perdas2300 → matéria colectável4400 → colecta1408MZN; saldo anual continua indeterminado emL8. Este incremento é **QA, sem instalação**. Não repete as provas de L3, ISPC, câmbio ou L5; conserva a fotografia4 e o histórico sem recalcular a aceitação anterior.
| Conjunto | Delta executável demonstrado | Efeito e prova nova | Pendência concreta que subsiste |
|---|---|---|---|
| 1 — ajustamentos, juros, variações e periodização | Acréscimos36(1)a/b/g com parcela incluída e origem reconciliada; juros financeiros22c de exploração documentados, sem capitalização/relações/limites especiais; entradas de capital21a e distribuições24c externas ao resultado sem efeito fiscal; variações positivas21 e negativas22/24 ordinárias; especialização18(1) de custo/proveito entre exercício corrente e seguinte. Documento/linha únicos entre mapas, sinal e soma bruta por tema conferidos. | Resultado financeiro6240 + acréscimos anteriores220 + imposto de terceiro250 + variação positiva200 − negativa50 + custo de2027 contabilizado em2026 de100 + diferença de amortização20 = lucro6980. Juros reconhecidos240, compensatórios acrescidos120, remanescente ordinário120; pagamentos continuam separados. Informação insuficiente mantém os efeitos independentes visíveis e impede somente os totais dependentes. | Correcções ordinárias ainda sem regra: encargos e limites36(1)e/f/h/i/n, provisões28/29, operações plurianuais19 e componentes de exercícios anteriores18(2). Juros capitalizáveis/relações especiais e limites exigem o tratamento próprio; não são aceites por simples selecção de juros ordinários. A tributação autónoma que possa coexistir pertence aL7. |
| 2 — amortizações e perda corrente | Decreto72/2013: quotas anuais constantes, custo/residual/acumulado, limite do saldo e vida útil; tabelaII/grupo3/item9 computadores25% e9.1 servidores20%, sem taxa específica da tabelaI prevalecente. Soma da depreciação contabilística por activo reconciliada com o plano; nenhum efeito de mapa incompleto aplicado. Perda corrente separada das perdas anteriores, sem auto-reporte. | Servidor500 ×20%=100 fiscal, depreciação contabilística120 → acréscimo20. Alterar quota/categoria, exceder vida útil ou não reconciliar a origem mantém o lucro dependente indeterminado. Outro exemplo: resultado fiscal−3820 → perda corrente3820 → base0/colecta0 apenas com suporte e conferência completos, sem dedução de perdas anteriores a si própria nem criação de saldo oficial. | Restante catálogo sectorial/genérico de activos, taxas reduzidas dentro dos limites, duodécimos, quotas decrescentes, bens usados/reavaliados, activos intangíveis e recuperação de quotas contabilizadas em anos anteriores. Não declarar toda a amortização fiscal concluída por estes dois itens. |
| 3 — âmbitos, representação e M20/M22 | EP no regime geral, resultado completo exclusivamente imputável ao estabelecimento; ano civil ou período anual diferente autorizado7(2)/comunicado7(3), correspondência dos12 meses e termo em2026/MZN. Valores racionais exactos, sem arredondamento fiscal inventado. M22 campos259/260,269/270,276/277/278 e300 conforme aplicação; M20A.1 quadro4 contas6.1.1/6.2/6.5/6.9 com valores contabilísticos próprios. |6980 − perdas2300 = base4680; ×32%=colecta1497,60MZN, não saldo a pagar. EP com período01/07/2025–30/06/2026 demonstrado; período curto incompatível fica pendente. API privada recupera os quatro casos calculado/falta/perda/EP e os relatórios respectivos. M20 inteiro e M22 ao cêntimo apenas quando a representação é exacta; fracções conservadas e marcadas sem transcrição pronta. | Períodos curtos/transição/liquidação e reconciliação fiscal anual de planos noutra moeda (motor cambial aceite preservado). Representação fiscal de fracções de unidade/cêntimo por corresponder. No M20 faltam discriminação vendas/serviços, fornecimentos/outros gastos, imposto e resultado líquido; no M22 faltam a reconciliação do campo200 e detalhe dos restantes ajustamentos. Divergência delimitada de edições: folha M20A.1 do XLSX remete ao campo201/quadro8 do M22; PDF inventariado utiliza200/quadro10. Bloqueia esse transporte, não os outros campos. |
**Provas apenas do delta:** 14 testes frontend; API privada1 teste/78 asserções com transacção revertida na base QA127.0.0.1:55441; geração de routes/actions pelo procedimento existente, TypeScript e build; interface real com edição, taxa/categoria incompatível, falta de juros, gravação/recuperação, download e perda corrente; relatórios/dossier construídos a partir dos dados recuperados. Recibo `docs/investmoz/simulations/irpc-l6-compatible-sets-qa-20261025.json`; pacote/bundle em `outputs/irpc-l6-sets`. Sem alteração de schema, API, configuração, permissões ou dependências.
**Âmbitos próprios preservados:** L7 conserva benefícios, isenções, taxas reduzidas, tributações autónomas e operações especiais; L8 conserva retenções, pagamentos, créditos e saldo final. M22 campo302 não é preenchido só com a parcela normal300, nem os campos309–316 são preenchidos com zeros presumidos. As dez dúvidas deL5 continuam na mesma matriz, sem nova pesquisa e bloqueando apenas dependências efectivas. L6 continua parcial exclusivamente pelas pendências concretas da tabela; nenhum desses pontos reabre o percurso instalado.
## 25/10/2026 — conjunto L6 a2de7259 entregue pelo Git
Instalado `a2de725901c308fb2ac2bc3d72181ab50ef46b7a` sobre `2f684e59`, pelo procedimento Git existente, sem força, migrações ou importações. Backup fresco `2026-10-25T20:34:03Z` e restauro isolado sem rede/porta55441: **174tabelas** conferidas por contagem/checksum; **369ficheiros/configuração** preservados. Conferidos **8ficheiros do delta,38protegidos e31originais**; schema,roles/grants e permissões iguais. Tabelas de negócio preservadas; cache/sessões reconciliadas com os eventos operacionais da entrega. `2f684e59` permanece como versão anterior. Dependências de5versões antigas arquivadas e verificadas para espaço, sem modificar as versões actual/anterior, fontes, dados ou backups.
Revisão/manifest público,10marcadores compilados e simuladorHTTP200 conferidos. Pipeline normal concluído; as provas QA aceites foram reutilizadas, sem nova ronda manual. **Disponível no âmbito demonstrado: lucro6980 → base4680 → colecta1497,60MZN. O saldo final a pagar/recuperar continua indeterminado emL8.** Também preservados o caso de perda corrente e as distinções conhecido/ausência/falta de informação, os períodos/EP demonstrados e a preparação parcialM20/M22. Recibo:`docs/investmoz/simulations/irpc-l6-sets-delivery-20261025.json`.
O estado «QA sem instalação» da nota anterior é histórico para este conjunto. **L6 continua parcial pelos seis grupos concretos da secção seguinte**, cada um com condição de resolução e bloqueio delimitado. L7 eL8 mantêm os seus âmbitos.
## 25/10/2026 — saldo curto de L6 após o conjunto a2de7259
Actualização de **AUD-SIM-INT02 na mesma matriz**, sem novo lote ou backlog. O percurso financeiro → ajustamentos documentados → lucro tributável → matéria colectável → colecta está demonstrado; no caso novo,6980 →4680 →1497,60MZN. A colecta não é saldo final a pagar. As pendências abaixo substituem a enumeração genérica anterior para o saldo actual deL6; não revogam as provas aceites.
| Caso ou correspondência pendente | Condição concreta de resolução | Limite do bloqueio |
|---|---|---|
| Custos com limites36(1)e/f/h/i/n, provisões28/29, obras plurianuais19 e componentes de exercícios anteriores18(2). | Implementar a regra de cada categoria a partir do diploma aplicável: parcela contabilizada, limite/base próprios, documentação e exercício de imputação; demonstrar o efeito com sinal nos totais. Nos exercícios anteriores, distinguir o que era imprevisível/manifestamente desconhecido no encerramento. | Só a categoria ou parcela ainda sem regra; os acréscimos36a/b/c/g, juros ordinários e periodização corrente/seguinte demonstrados permanecem utilizáveis. Eventual tributação autónoma pertence aL7. |
| Amortizações além dos itensII/3/9 e9.1: restantes tabelas, quotas inferiores, duodécimos, quotas decrescentes, bens usados/reavaliados/intangíveis e recuperação de quotas anteriormente tributadas. | Corresponder categoria/tabela prevalecente, método, entrada em uso, vida útil, base depreciável e quotas contabilizadas/fiscais acumuladas; implementar o cálculo e a reconciliação que impeçam dupla dedução. | Só os activos/métodos afectados. Computadores25% e servidores20% no recorte anual constante e a perda corrente já demonstrada não são reabertos. |
| Períodos curtos, transição/liquidação e reconciliação fiscal anual de plano noutra moeda. | Ligar os meses e factos de início/cessação/transição ao período fiscal; implementar os efeitos sobre quotas e contagem das perdas. Para outra moeda, identificar os eventos/datas e a regra de conversão anual aplicável, reutilizando o motor cambial aceite. | Só o período ou origem cambial sem reconciliação. Os períodos anuais emMZN e oEP com imputação documentada conservam o cálculo demonstrado. |
| Representação fiscal de fracções de unidade/cêntimo. | Identificar a instrução de representação/arredondamento da edição/campo aplicável ou obter esclarecimento específico daAT; então implementar essa regra conservando o valor racional original. O exemplarM20A.1 pede meticais sem centavos, mas isso não determina sozinho como arredondar uma fracção. | Só a transcrição do valor não exactamente representável. Os cálculos racionais e os valores exactamente representáveis permanecem disponíveis; não é necessária nova validação genérica das fontes. |
| M20A.1: discriminação de vendas/serviços, fornecimentos/outros gastos, imposto sobre o rendimento e resultado líquido; M22: campo200 e detalhe dos restantes ajustamentos. | Reutilizar a origem financeira, recolhendo apenas a classificação em falta e o imposto contabilizado; reconciliar resultado antes/depois de imposto e cada ajustamento com a edição aplicável. Não usar a colecta simulada como imposto contabilizado. Completar as correspondências por campo e demonstrar a recuperação/exportação. | Só os campos sem correspondência. M20A.1/Q4 contas6.1.1/6.2/6.5/6.9 e M22 campos259/260,269/270,276/277/278 e300 conservam a preparação parcial demonstrada. |
| Transporte de resultado entre ediçõesM20/M22: XLSXM20A.1 remete para201/quadro8; PDFM22 inventariado usa200/quadro10. | Identificar a edição do formulário de destino e corresponder explicitamente o resultado líquido a essa edição; registar a remissão corrigida sem substituir os exemplares ou reutilizar fórmulas antigas por aproximação. | Só esse transporte entre edições; não bloqueia os cálculos independentes nem os outros campos já correspondidos. |
**L6 continua parcial por estes casos concretos.** Documento ou parâmetro em falta dentro de regra implementada é uma pendência do caso, não outra tarefa genérica deL6. Juros capitalizáveis, relações especiais e tratamentos especiais conservam o enquadramento próprio, sem presumir que satisfazem o recorte de juros ordinários.
**L7** mantém benefícios, isenções, taxas reduzidas, tributações autónomas e operações especiais. **L8** mantém retenções, pagamentos, créditos e saldo final a pagar/recuperar. A ausência desses tratamentos não reabre o percurso normal entregue nem justifica, por si, «L6 parcial». A divergência documental não autoriza preencher M22 campo302 ou309–316 com zeros presumidos. As dez dúvidas deL5 permanecem válidas e bloqueiam apenas os casos efectivamente dependentes; sem nova pesquisa ou repetição das provas aceites.
## 26/10/2026 — L6: custos com limites, provisões e periodização em QA
Actualização de **AUD-SIM-INT02 na mesma matriz**, sobre o conjunto instalado `a2de7259`. **Novo incremento em QA, sem instalação.** O percurso e as provas já aceites deL6/L3/ISPC/câmbio/L5 foram reutilizados; não foram novamente executados os testes funcionais anteriores. A fotografia5 continua actual sem activar os novos campos; a fotografia6 guarda estes mapas e conserva o resultado anterior no histórico.
**Reutilização e resultado demonstrado:** resultado financeiro6240MZN, acréscimos anteriores220 e mapas anteriores520 conservados; novos ajustamentos de custos/provisões/periodização+350 e obra−600 → **lucro tributável6730MZN**. Dedução expressa das perdas anteriores2300 → **matéria colectável4430MZN**; taxa normal32% → **colecta1417,60MZN**. Não é saldo final a pagar. Nenhum saldo oficial de provisões/perdas é consumido, nem é alterada declaração ou história anterior.
| Categoria e condição no exercício anual com termo em2026 | Parcela aceite, limite e ajustamento demonstrados | Informação insuficiente ou caso separado |
|---|---|---|
| Ajudas de custo/deslocação em viatura própria36(1)e: parcelas facturadas e tributadas emIRPS identificadas sem sobreposição. Representação36(1)f/36(3) ordinária documentada. | Ajudas100:facturadas20,tributadas e não facturadas20;remanescente60 →30 acrescido/70 aceite. Representação50 →40 acrescido/10 aceite. Zero conhecido nos parâmetros é distinto de campo vazio. | Parcela facturada/tributada em falta impede a aceitação dependente; não presumir ausência deIRPS. Eventual tributação autónoma continuaL7. |
| Publicidade ordinária36(1)n,Lei20/2009: receita declarada reconciliada com vendas normais e completude anual das parcelas. | Um limite anual partilhado de1% de12000=120. Caso com duas parcelas100+100:aceites60+60,acréscimo80. A repartição proporcional é apenas aritmética de simulação, não uma ordem fiscal obrigatória. | Campanha de lançamento com horizonte superior a um ano não recebe este tratamento por aproximação: periodização36-A e articulação do limite permanecem por implementar. |
| Encargos com viaturas36(4), combustível36i e aluguer sem condutor36h, distinguindo categoria/serviço público/locação na actividade normal. | Outros encargos100 de passageiros sem excepção:aceite50/acréscimo50. Combustível50 não sujeito a36(4),com40 comprovados no activo/locação e consumo normal:aceite40/acréscimo10. Renda100 no caso documentado de excepção36(4),quota não aceite36h de20:aceite80/acréscimo20; a quota é reutilizada do suporte e não apurada automaticamente. | Se há simultaneamente parcela excluída porh/i e aplicação dos50% de36(4), a combinação fica pendente. Exemplo:fuel100,comprovado80,passageiro sem excepção; não somar nem repartir correcções por presunção. Resolver a regra de articulação dos trechos aplicáveis ou esclarecer esse exemplo especificamente comAT. Apuramento automático da quota36h permanece no saldo de amortizações; só bloqueia esse caso. |
| Provisão/perda por imparidade de créditos28a/29: regime ordinário identificado, créditos normais finais e provisão fiscal anterior conhecidos. | Base10000:limite anual1,5%=150,acumulado6%=600. Saldo anterior550 deixa50;provisão contabilística200 →50 aceite/150 acrescido. Duas parcelas100+100 partilham25+25; não repetem os limites nem consomem o saldo oficial. | Saldo anterior vazio não é zero; anterior superior ao tecto pede reconciliação/reversão28(2). Provisões sujeitas a supervisão financeira/seguradora28d ou reforços financeiros28(3) exigem correspondência própria, sem aplicar29 por aproximação. |
| Existências28b:perda efectivamente observada. Processo judicial28c:em curso e obrigação subjacente fiscalmente dedutível. | Existências:parcela60,perda total40,provisão anterior10 →30 aceite/30 acrescido. Judicial:parcela90,obrigação100,anterior20 →80 aceite/10 acrescido. Perda não observada ou processo que não esteja em curso são condições negativas conhecidas:acréscimo integral, sem zero presumido como dedução. | Falta de prova do evento,obrigação,perda ou saldo anterior fica indeterminada. Objecto/saldo repetido entre documentos impede reutilizar a cobertura; agregar/reconciliar as parcelas do mesmo objecto. |
| Reversões28(2) e provisões anteriormente tributadas:mesmo objecto e tratamento fiscal anterior comprovados. | Provisão antes deduzida:reversão50 já incluída no resultado não acrescenta novamente;omitida dos proveitos acrescenta50. Reversão contabilística50 de provisão antes tributada comprovada é excluída por50. | Não inferir o tratamento anterior do saldo contabilístico. Quantia superior à parcela fiscal demonstrada,evento que continua a subsistir ou objecto duplicado ficam pendentes. Sem alteração retrospectiva ou consumo do saldo oficial. |
| Componentes de exercícios anteriores18(2):conhecimento/imprevisibilidade no encerramento anterior documentados. | Custo80 conhecido no fecho2025,incluído no resultado actual →acréscimo80. Se imprevisível/manifestamente desconhecido à data daquele fecho →sem acréscimo por periodização. Proveito50 conhecido no fecho anterior →excluído do actual por50;se imprevisível/desconhecido →considerado no actual. | Conhecimento no fecho em falta impede apenas a imputação da parcela. Nenhuma rectificação de declaração anterior é executada. Periodizações específicas18(6–10) não passam a estar cobertas por este recorte18(2). |
| Obras plurianuais19 e perdas meramente estimadas36m:critério uniforme,preço,custo incorporado/custo total e acumulados fiscais anteriores documentados. | Percentagem:preço2000,custo total1000,incorrido500;proveito fiscal acumulado1000 menos anterior600=400 corrente;custo500 menos anterior300=200 corrente. Proveito contabilizado1000/custo200 →ajustamento−600. Encerramento tem caso separado;facturação parcial com acabamento correspondente/entregas fraccionadas impõem percentagem;95% com preço conhecido ou recepção provisória pública determina conclusão. Perda meramente estimada50 de obra em curso →acréscimo50. | Acumulados incoerentes ou método incompatível bloqueiam essa obra. Receita antecipada19(5) positiva e mudança de critério com autorização19(6) ficam por corresponder; o caso demonstrado declara expressamente zero de receita antecipada e método mantido, sem presumir essas condições. |
**Percurso demonstrado:** cálculo → gravação → recuperação pela API privada → relatório/dossier/exportação em cinco casos:conjunto calculado,informação insuficiente,categorias adicionais,limites partilhados e encerramento de obra. Só os novos casos foram testados: **22 testes frontend,1 testeAPI/83asserções**, transacção revertida na base QA127.0.0.1:55441; routes/actions gerados pelo procedimento existente,TypeScript/build e interface real passaram. Interface permite reutilizar a parcela livre da origem e o saldo financeiro de créditos quando conhecido; alterações às somas dos temas são revistas antes de aplicar e não apagam escolhas ou históricos. Fonte ausente ou saldo não acompanhado nunca cria zero. Valores racionais são conservados, apresentações decimais aproximadas são identificadas e uma perda inferior a um cêntimo não é truncada para zero.
**Preservação:**6ficheiros de runtime no delta,42protegidos e31originais conferidos; sem schema/API/configuração/permissões/dependências alterados, sem escrita no activo. Recibo:`docs/investmoz/simulations/irpc-l6-costs-provisions-timing-qa-20261026.json`;bundle/pacote em `outputs/irpc-l6-costs`. DivergênciaM20/M22 permanece limitada ao transporte201/quadro8 versus200/quadro10; não é uma condição destes cálculos. Não foram criadas correspondências oficiais de campos para estes novos ajustamentos por presunção.
**Saldo deL6 após estes casos QA:**combinação36h/i+36(4);quota36h automática e restantes amortizações;campanhas36-A e sua articulação com1%;provisões reguladas/reforços financeiros e periodizações específicas não cobertas;receita antecipada positiva/mudança autorizada do método de obra;períodos curtos/conversão fiscal anual;representação fiscal de fracções e restantes correspondênciasM20/M22. Cada pendência afecta o caso/campo dependente, não o conjunto independente demonstrado. Benefícios,isenções,taxas reduzidas e operações especiais mantêm âmbitoL7;retenções,pagamentos,créditos e saldo anual mantêm âmbitoL8. **L6 continua parcial.** As dez dúvidas deL5 não foram reabertas.
## 26/10/2026 — conjunto L6 043dd35d entregue pelo Git
Instalado `043dd35d8ee247123b3a32f1fc10fd2ede81e9f4` sobre `a2de7259`, pelo procedimento Git existente, sem força, migrações ou importações. Backup fresco `2026-10-26T06:35:29Z` e restauro isolado sem rede/porta55441: **174tabelas** conferidas por contagem/checksum; **369ficheiros/configuração** preservados. Conferidos **6ficheiros do delta,42protegidos e31originais**; schema,roles/grants e permissões iguais. Tabelas de negócio preservadas; cache/sessões reconciliadas com os eventos operacionais da entrega. `a2de7259` permanece como versão anterior. Dependências de4versões antigas arquivadas e verificadas para espaço, sem modificar as versões actual/anterior, fontes, dados ou backups.
Revisão/manifest público,11marcadores compilados e simuladorHTTP200 conferidos. Pipeline normal concluído; as provas QA aceites foram reutilizadas, sem nova ronda manual. **Disponível no âmbito demonstrado: lucro6730 → base4430 → colecta1417,60MZN. O saldo final a pagar/recuperar continua indeterminado emL8.** Também preservados o caso de perda corrente e as distinções conhecido/ausência/falta de informação, os períodos/EP demonstrados e a preparação parcialM20/M22. Recibo:`docs/investmoz/simulations/irpc-l6-costs-delivery-20261026.json`.
O estado «QA sem instalação» da nota anterior é histórico para este conjunto. **L6 continua parcial pelos seis grupos concretos da secção seguinte**, cada um com condição de resolução e bloqueio delimitado. L7 eL8 mantêm os seus âmbitos.
## 26/10/2026 — saldo de L6 após a entrega043dd35d
Mesma matriz AUD-SIM-INT02. Custos/provisões/periodização demonstrados entregues; trabalho seguinte:amortizações. Provas aceites reutilizadas.
| Caso ou correspondência pendente | Condição concreta de resolução | Limite do bloqueio |
|---|---|---|
| Combinação36h/i com36(4) | Corresponder a regra de articulação dos trechos aplicáveis ou esclarecer comAT o exemplo combustível100/comprovado80/passageiro sem excepção;sem somar ou repartir correcções por presunção. | Apenas o caso/campo dependente; cálculos independentes preservados. |
| Quota36h automática e amortizações restantes | Reconciliar tabela/método/entrada emuso/quotas contabilísticas e fiscais anteriores;prioridade seguinte deL6. A parcela36h documentada continua reutilizável nos casos independentes. | Apenas o caso/campo dependente; cálculos independentes preservados. |
| Campanhas plurianuais36-A e limite1% | Implementar a periodização por três exercícios e a sua articulação com36n; não tratar a campanha como publicidade ordinária. | Apenas o caso/campo dependente; cálculos independentes preservados. |
| Provisões reguladas28d e reforços financeiros28(3) | Corresponder a regra sectorial/supervisão ou o reforço financeiro e os saldos documentados; não usar os limites ordinários29 por aproximação. | Apenas o caso/campo dependente; cálculos independentes preservados. |
| Receita antecipada19(5) positiva e mudança autorizada19(6) | Corresponder os custos futuros/receita antecipada e o transporte entre exercícios ou a autorização da mudança de método;os casos zero conhecido/método mantido permanecem executáveis. | Apenas o caso/campo dependente; cálculos independentes preservados. |
| Outras periodizações,âmbitos eM20/M22 | Tratar apenas os casos específicos18(6–10),períodos curtos/conversão anual,representação fiscal e campos ainda sem correspondência,com os parâmetros da edição/caso;divergência201/Q8 versus200/Q10 só afecta o transporte indicado. | Apenas o caso/campo dependente; cálculos independentes preservados. |
L6 continua parcial. L7 mantém benefícios/casos especiais;L8 mantém retenções/pagamentos/créditos/saldo final. As dez dúvidasL5 não foram reabertas.
## 26/10/2026 — L6: amortizações em QA, sem instalação
O portal mantém `043dd35d` instalado: colecta demonstrada1417,60MZN, sem saldo finalL8. O novo conjunto optativo `IRPC-normal-adjustments/7` reutiliza os activos e o resultado financeiro já declarados. Versões1–6 e históricos permanecem intactos; activar o novo mapa substitui o efeito fiscal anterior das amortizações, sem o somar novamente. Ausência declarada de quotas anteriores é distinta de informação em falta e exige referência.
Cobertura delimitada ao exercício anual2026/MZN e bens novos ao custo histórico: tabelaII/3/9 computadores25%,3/9.1 servidores20%,3/23 segurança20%,3/22 máquinas não especificadas10%,5/7 mobiliário10%,1/2.2 edifícios comerciais/administrativos2%,4/9.2 veículos ligeiros/mistos25%,5/8 software25%; tabelaI/84.2/B decoração hoteleira20% e84.3/A máquinas de lavandaria12,5%. A tabelaI prevalece quando aplicável; não se presume que esta lista cobre todo o catálogo. Fonte: Decreto72/2013, artigos3–10/17 e tabelas, exemplar original anteriormente aceite e hash preservado; CIRPC27e para limite800000MZN de viaturas e exclusão de terrenos.
Método constante com taxa expressamente escolhida no recorte metade–máximo; degressivo apenas para bens elegíveis novos, factores máximos1,5/2/2,5 segundo vida útil. Opção8(2) demonstrada apenas em ano civil/início1Janeiro, com quotas anteriores completas documentadas. Duodécimos incluem mês de entrada e excluem mês de saída, respeitando vida máxima. Software exige direitos onerosos/exclusivos e duração limitada; art17 exige bem individual até20000 e opção documentada. Quotas anteriores recuperáveis têm prova contabilística/fiscal e são limitadas à parte elegível: quotas nunca contabilizadas ou permanentemente excluídas não se tornam dedutíveis. Nenhum saldo oficial é consumido.
| Novo caso | Efeito demonstrado em MZN: lucro → matéria colectável → colecta |
|---|---|
| Computador em uso desdeJulho: quota fiscal50, ajustamento70, substituindo anterior20 | 6780 →4480 →1433,60 |
| Mesmo activo, saída15Outubro:3meses/quota25 | Colecta1441,60; entrada/saída identificadas no relatório |
| Degressivo elegível: quota200, ajustamento40 | 6630 →4330 →1385,60 |
| Quota anterior documentada:20 recuperados,20 restantes; ajustamento−20 | 6730 →4430 →1417,60 |
| Máquina de lavandariaI/84.3/A: quota62,50, ajustamento57,50 | 6767,50 →4467,50 →1429,60 |
| Quota contabilística anterior em falta | Lucro/base/colecta indeterminados; ajustamentos independentes conhecidos continuam discriminados |
Cálculo → gravação → recuperação pela API privada → relatório/dossier demonstrado em cinco casos. **18novos testes frontend;1testeAPI/84asserções**, rollback na baseQA127.0.0.1:55441; routes/actions gerados, TypeScript/build e interface real passaram, incluindo edição, reutilização, ausência declarada, falta de informação, recuperação e exportação. Provas aceites reutilizadas. **7ficheiros de runtime no delta,43protegidos e31originais conferidos**; sem migração/API/configuração/permissões/dependências ou escrita no activo.
| Saldo concreto das amortizações | Condição de retoma |
|---|---|
| Outros códigos/taxas, por exemploII/3/3 ar condicionado12,5% | Acrescentar correspondência verificada, elegibilidade e prova apenas desse delta; sem aprovação genérica adicional |
| Bens usados, abertura de escrita, grandes reparações/benfeitorias7(2)/(4), reavaliações15 e transição anterior2014 | Documentar vida esperada, bases/quotas anteriores e implementar a regra específica aplicável |
| Uso intensivo11, concessões12, peças14, intangíveis específicos16 e eventos de transferência/relocação | Corresponder condições legais e histórico do evento; desenvolvimento/goodwill não herdam taxa do software |
| Mudança de método10, excepções, taxas fora do recorte, vida máxima anual terminada a meio do período e opção8(2) fora do caso demonstrado | Histórico concreto e regra/excepção correspondente; autorização apenas quando a norma a exigir |
| Restantes custos/provisões/periodizações da entrega043dd35d; períodos curtos, conversão anual, representação fiscal e correspondênciasM20/M22 | Mantêm os critérios concretos já registados na matriz; este incremento não os encerra |
A divergência201/quadro8 versus200/quadro10 bloqueia apenas o transporte afectado. Não foram presumidas correspondências oficiais para estes novos campos. **L6 continua parcial;L7 eL8 mantêm os seus âmbitos.** As dez dúvidasL5 não foram reabertas. Recibo: `docs/investmoz/simulations/irpc-l6-depreciation-qa-20261026.json`.
## 26/10/2026 — amortizações e9fe1022 entregues pelo Git
Instalado `e9fe102259c183a9d9bf7e39f246a8c3860839c6` sobre `043dd35d`, preservado como versão anterior. Backup fresco `2026-10-26T07:31:29Z` e restauro isolado sem rede/porta55441: **174tabelas** por contagem/checksum e **369ficheiros/configuração** conferidos. **7ficheiros do delta,43protegidos e31originais** verificados; schema,roles/grants e permissões iguais. As172tabelas de negócio mantêm os valores do backup. Cache:reinício da fila,contadores/timers e renovação da validade do mesmo valor de cache da página inicial. Sessões:expiração individual comprovada pelo prazo configurado120minutos,novas consultas da entrega e acessos anónimos correlacionados por agente/data no nginx;sem perda de dados de negócio. Dependências de5versões antigas arquivadas/verificadas para a margem do pipeline,preservando versões actual/anterior,fontes,dados e backups.
Revisão/manifest público,5marcadores compilados,4assets e simuladorHTTP200 conferidos. Pipeline normal concluído; provas QA18frontend/API1-84/UI/tipos/build reutilizadas,sem nova ronda manual. **Exemplo disponível: lucro6780 → matéria colectável4480 → colecta1433,60MZN. Saldo final a pagar/recuperar indeterminado emL8.** Históricos1–6 preservados; versão7 apenas por activação do novo mapa,substituindo o efeito anterior sem duplicação. Recibo:`docs/investmoz/simulations/irpc-l6-depreciation-delivery-20261026.json`.
O estado anterior «QA sem instalação» de e9fe1022 é histórico. Mantêm-se explícitos os outros códigos de tabela;usados/abertura de escrita/reparações/reavaliação/transição;uso intensivo/concessões/peças/intangíveis específicos/eventos;mudanças/excepções de método e opções fora do recorte. Retoma por correspondência da regra específica,base/vida/quotas e prova do delta,sem autorização genérica adicional. Períodos curtos e planos noutra moeda são o próximo incrementoQA,reutilizando o mecanismo cambial. Restantes custos/períodos/representação/camposM20-M22 conservam critérios próprios;divergência201/Q8 versus200/Q10 restringe apenas o transporte afectado. **L6 parcial;L7/L8 próprios;dez dúvidasL5 não reabertas.**
## 26/10/2026 — L6: períodos curtos e planos noutra moeda em QA
`e9fe1022` está instalado, com o âmbito de amortizações já demonstrado e os restantes casos de tabela/método explícitos acima. Este novo conjunto optativo `IRPC-normal-adjustments/8` está **emQA,sem instalação**. Reutiliza os meses e montantes do plano,os mapas fiscais emMZN e o mecanismo cambial entregue. Os históricos1–7 e o plano original não são reescritos.
Períodos de meses completos com termo em2026: início7(4)a,cessação7(4)b,início/fim de sujeição7(4)c e transição7(4)d,mediante identificação do evento/datas/suporte; plano com6meses ou selecção explícita de6dos12meses,sem anualizar receita,resultado,base ou taxa. Primeiro mês civil do plano é declarado,não inferido do mês orçamental. Anual diferente do ano civil conserva a correspondência do período autorizado/comunicado existente. Duodécimos ordinários do art9(3) do Decreto72/2013 aplicam o número de meses de utilização;art17 integral em período curto e restantes excepções não se tornam suportados por aproximação. Elemento conhecido como não amortizável mantém acréscimo integral,sem exigir método irrelevante.
Planos em outra moeda: cada mês seleccionado reutiliza ou confirma selecção cambial pelo procedimento existente,coluna/data/boletim/sentido e vínculo à origem. Moeda e valores originais permanecem no relatório. Não se adopta taxa actual,única ou de outro mês por defeito. **A conversão mensal para simulação exige pressuposto documentado;não confirma automaticamente uma regra fiscal de conversão anual.** Os mapas/activos/quotas/perdas existentes continuam emMZN e são reconciliados expressamente;nenhuma segunda conversão automática. Saldos patrimoniais de créditos em moeda estrangeira não são apresentados comoMZN pela conversão dos fluxos do plano;correspondência de saldo/data/taxa continua separada.
| Caso novo | Efeito demonstrado emMZN |
|---|---|
| Início1Julho–31Dezembro,meses7–12: resultado3120;quota fiscal50 e ajustamento10 | Lucro3130 → matéria colectável3130 → colecta1001,60,à taxa32%;ausência de perdas/benefícios declarada |
| Mesmo recorte emUSD,pressuposto sintético64MZN/USD identificado em cada mês;mapasMZN reconciliados | Resultado199680;ajustamento640;lucro/base200320 → colecta64102,40. Taxa64 é pressupostoQA,não boletimBM real ou parâmetro fiscal confirmado |
| Anual emUSD;plano de6meses iniciado emJulho;cessação e sujeição no mesmo ano | Novos testes próprios;respectivamente colecta128204,80 e1001,60nos casos correspondidos,sem anualização do semestre |
| Falta de selecção de um mês,moeda incompatível ou taxa editada sem confirmação | Valores originais e conversões independentes visíveis;resultado/lucro/base/colecta dependentes indeterminados |
| Perdas reportadas propostas num período curto | Lucro3130conhecido;dedução/base/colecta pendentes da sequência de períodos. Art41(5) exclui da contagem o período de transição7(4)d inferior a6meses;não autoriza agregar todos os períodos curtos |
Cálculo → gravação → recuperaçãoAPI → relatório/dossier demonstrado em4casos. **13testes novos frontend,API1teste/58asserções**, rollback na baseQA127.0.0.1:55441;routes/actions pelo procedimento existente,TypeScript/build e interface real passaram. Interface demonstrou alteração de datas e taxa,confirmação cambial,recuperação e exportação. Mudança na origem cambial invalida a actualidade do novo resultado,conservando o histórico. Provas aceites reutilizadas,sem repetição manual. Delta:**9ficheiros de runtime,43protegidos e31originais**;sem API/schema/configuração/permissões/dependências ou escrita no activo.
| Pendência concreta | Condição de retoma e bloqueio |
|---|---|
| Datas parciais,períodos superiores a12meses/liquidação e curtos fora do recorte2026 | Corresponder datas/evento,parcelas de dias e regra aplicável;apenas esse período depende da implementação |
| Dedução de perdas em sequência com períodos curtos/transição | Declarar sequência efectiva de períodos posteriores e aplicar41(5) ao caso7(4)d inferior a6meses;sem prazo presumido só por ano civil. Lucro independente continua calculável |
| Limites anuais de publicidade e provisão de créditos em período curto | Corresponder expressamente a base/limite do período e regra de proporcionalização,se aplicável;sem anualização ou rateio presumidos. Outros custos e períodos anuais não bloqueados |
| Quota integral art17 em período curto,opções/métodos/tabelas e casos de amortização ainda não suportados | Implementar combinação específica e provar só o novo efeito;condições restantes do conjuntoe9fe1022 continuam válidas |
| Conversão fiscal anual confirmada,saldos em moeda estrangeira e fracções de cêntimo da conversão | Identificar regra fiscal/data/base,taxa e âmbito;para saldos,conversão própria em vez de somar fluxos;para fracções,regra de representação. Até lá,pressupostos de simulação explícitos e total indeterminado quando não representável neste recorte |
| Restantes custos/periodizações e correspondênciasM20/M22 | Mantêm os critérios já registados. Divergência201/Q8 versus200/Q10 limita só o transporte afectado |
Fontes primárias reutilizadas: CIRPC Lei34/2007 PDF4/p768(58),art7(4)/(7),ePDF12/p768(66),art41(5);Decreto72/2013 PDF3/p1074(7),art9(3). Exemplar e originais/hash preservados;sem importação/publicação documental. **L6 continua parcial. Colecta não é saldo final a pagar;L7 eL8 mantêm âmbitos próprios.** As dez dúvidasL5 não foram reabertas. Recibo:`docs/investmoz/simulations/irpc-l6-periods-fx-qa-20261026.json`.
## 26/10/2026 — períodos curtos e planos noutra moeda56475acb entregues pelo Git
Instalado `56475acb2f39e58cb51664913f7fb499f58eb7ab` sobre `e9fe1022`,preservado como versão anterior. Backup fresco `2026-10-26T08:17:39Z` e restauro isolado sem rede/porta55441: **174tabelas** por contagem/checksum e **369ficheiros/configuração** conferidos. **9ficheiros do delta,43protegidos e31originais** verificados;schema,roles/grants e permissões iguais. As172tabelas de negócio mantêm os valores do backup. Cache/sessões reconciliadas com os eventos operacionais e acessos anónimos registados;expiração,quando aplicável,comprovada individualmente pelo prazo configurado. Dependências de5versões antigas arquivadas/verificadas,preservando versões actual/anterior,fontes,dados e backups.
Revisão/manifest público,6marcadores compilados,4assets e simuladorHTTP200 conferidos. Pipeline normal concluído;provasQA13frontend/API1-58/UI/tipos/build reutilizadas,sem nova ronda manual. **Semestre demonstrado: lucro3130 → matéria colectável3130 → colecta1001,60MZN.** PlanoUSD:pressuposto sintético64MZN/USD por mês identificado,originais conservados e mapasMZN reconciliados;lucro/base200320 → colecta64102,40MZN. **Não confirma regra fiscal de conversão anual nem boletimBM real. Saldo final a pagar/recuperar continua indeterminado emL8.** Históricos1–7 preservados;versão8 optativa,sem anualizar resultados ou usar taxa actual por defeito. Recibo:`docs/investmoz/simulations/irpc-l6-periods-fx-delivery-20261026.json`.
O estado anterior «QA sem instalação» de56475acb é histórico. Permanecem explícitos os casos de datas parciais/liquidação,sequência de perdas41(5),limites anuais em período curto,art17 curto/restantes amortizações,conversão fiscal anual/saldos em outra moeda/fracções e demais custos/periodizações. Condições de retoma continuam na mesma matriz. Próximo incrementoQA:representação de valores e camposM20/M22 por corresponder;divergência201/Q8 versus200/Q10 limitada ao transporte do resultado afectado,sem reabrir cálculos demonstrados. **L6 parcial;L7/L8 próprios;dez dúvidasL5 não reabertas.**
## 26/10/2026 — L6: representação dos valores e campos M20/M22 em QA
`56475acb` está instalado. Este novo conjunto optativo `IRPC-normal-adjustments/9` está **em QA, sem instalação** e acrescenta preparação dos valores/campos, sem alterar fórmulas de lucro tributável, matéria colectável ou colecta. Históricos1–8, plano original, pressupostos cambiais e demais livros preservados. A falta de uma correspondência documental afecta o campo e a sua reconciliação, mantendo os totais fiscais existentes.
**Representação:** valor racional exacto conservado, apresentação aproximada identificada por«≈» e fracção original; zero conhecido, informação em falta e campo sem aplicação distintos. M20A.1/quadro4/M12 pede meticais sem centavos: valores inteiros são representáveis, fracções ficam por corresponder, sem arredondamento/truncagem. Preparação M22 já aceite com valores exactos ao cêntimo preservada; fracções de cêntimo continuam explícitas e pendentes da regra fiscal aplicável. Resultado líquido negativo M20 é apresentado entre parêntesis; M22 separa campo de lucro do de prejuízo, sem colocar perda no lucro ou criar matéria colectável negativa.
**M20:** reutiliza as quatro correspondências directas de custos das vendas,pessoal,depreciação e juros. Discrimina as receitas e despesas operacionais por conta com suporte e reconciliação exacta ao plano do período/moeda. Demonstra prestação de serviços7.2,fornecimentos/serviços6.3,outros gastos6.8 e imposto contabilizado8.5, além das contas directas6.1.1/6.2/6.5/6.9. Rótulos das demais contas são estrutura disponível; não constituem novas regras fiscais nem provam a qualificação de uma parcela. Uma origem incompleta não apaga as contas directas independentes.
O imposto contabilizado tem valor/ausência e suporte próprios, e localização já incluída ou exterior ao plano. Colecta não é despesa contabilística presumida. Valor já incluído não é subtraído novamente; contradição com o mapa de imposto próprio ou coexistência das duas localizações fica identificada. O resultado líquido é apurado para preparação; o transporte automático entre edições continua impedido só no resultado afectado.
**M22 PDF:** correspondências de variações patrimoniais201/202,resultado203,amortizações não aceites206,provisões/imparidade209,impostos de outrem213,multas/juros compensatórios215,ajudas219,representação220,publicidade221,despesas não documentadas223,aluguer224,combustíveis225,viaturas226 e reposição de provisões tributadas239. Reutiliza os ajustamentos demonstrados; não reaplica as percentagens impressas. A representação já calculada usa80%,compatível com220. Campo213 é apenas de outrem: imposto próprio36(1)a continua **sem campo presumido**. Efeitos positivos de amortização vão a206; recuperações negativas de quotas anteriores ficam separadas até correspondência própria, sem compensação no mesmo campo.
Somas238/258 e lucro reconstruído apenas quando todas as parcelas têm correspondência e reconciliam; campos259/260/269/270/276/277/278/300 reutilizam o cálculo existente, mesmo havendo uma parcela sem campo. Colecta total302 só é preparada com ausência de parcela de taxa reduzida declarada com suporte;caso conhecido mantém âmbitoL7 e não apaga300. Campos309–316/saldo final permanecem emL8.
| Caso novo | Resultado e limite de aplicação |
|---|---|
| Correspondência no semestre demonstrado, ausência de imposto contabilizado e taxa reduzida declaradas | Resultado líquido3120;203=3120;206=10;238=3130;258=0;lucro/base3130;colecta normal300 e total302=1001,60MZN. Reconciliação aritmética exacta, sem transporte automático entre edições |
| Fornecimentos300,50 e outros gastos299,50, origem600 | Parcela300,50 conserva601/2;M20 em meticais inteiros pendente só nas parcelas fraccionárias;resultado e colecta1001,60inalterados |
| Imposto contabilizado em falta | Resultado líquido/campo200 e somas dependentes indeterminados;lucro/base3130 e colecta1001,60mantidos |
| Recuperação de quota anterior:ajustamento−26 | Efeito fiscal e colecta1001,60preservados;sem código de dedução inventado,somas238/258 pendentes;260/278/300 conhecidos |
| Imposto próprio320 contabilizado exterior ao plano | Resultado líquido2800 conhecido;campo de acréscimo próprio por corresponder,sem usar213 de outrem;lucro/base3130 e colecta1001,60preservados |
Percurso cálculo → gravação → recuperação privada → relatório/dossier demonstrado em **5casos**. **15testes novos frontend;API1teste/97asserções**, transacção revertida na baseQA127.0.0.1:55441;routes/actions gerados pelo procedimento existente,TypeScript/build e interface real passaram. Interface demonstrou edição de parcelas,imposto em falta sem apagar valor anterior,recuperação/exportação e pendências apenas dependentes. Provas aceites reutilizadas;sem repetir suites anteriores. **4ficheiros de runtime no delta,50protegidos e31originais** conferidos;sem API/schema/configuração/permissões/dependências ou escrita no activo.
Fontes: PDF M22 SHA2564b61bd83d1fbcfd3b7b5c5523cea5923f7d0f65dc4c004eff58e5db38f763c88,3páginas já aceites reutilizadas;M20A.1 SHA2561ceca6f4c6d77853c1b2b445876599b42093175fa89eecf40590180956d83a9e,M12/D13–D35. Inventariados os20ficheiros acessíveis deModelos/Notas,incluindo temporários;originais/hash preservados. Só rótulos genéricos necessários extraídos do XLSX;sem valores privados,fórmulas/cache do exemplar,importação ou publicação documental.
| Saldo concreto da preparação M20/M22 | Condição de retoma e alcance |
|---|---|
| Transporte do resultado M20A.1/D35→M22 | Exemplar compatível ou instrução que resolva201/quadro8 versus200/quadro10. Só esse transporte fica impedido;valor líquido próprio e demais campos continuam visíveis |
| Imposto próprio36(1)a,quota anterior recuperada e restantes efeitos de periodização/obras/reversões sem campo | Corresponder rótulo,edição/período e regra específica do campo. Efeito/valor conservados sem código provisório;apenas somas/campos dependentes aguardam |
| Fracções M20 e subcentavos M22 | Identificar regra de representação do caso;preservar fracção e apresentar aproximação identificada até então. InteirosM20 e cêntimos exactosM22 não bloqueados |
| Imposto contabilizado simultaneamente incluído e exterior ao plano | Discriminar ambas as componentes/referências e conciliar8.5/acréscimo próprio sem repetir gasto;sem inferir o valor da colecta |
| Contas/quadros e anexos restantes fora das seis linhas financeiras demonstradas | Reutilizar dados existentes,classificar componentes com suporte e acrescentar correspondência específica;sem tomar campos preenchidos do exemplar como dados do investidor |
L7 mantém benefícios/casos especiais/taxas reduzidas eL8 mantém retenções,pagamentos,créditos e saldo final. Restantes regras deL6 e as dez dúvidasL5 conservam o saldo e as condições já documentadas. **L6 continua parcial;colecta não é saldo final a pagar.** Recibo:`docs/investmoz/simulations/irpc-l6-values-forms-qa-20261026.json`.
## 26/10/2026 — representação dos valores e campos M20/M22 5aaf1a56 entregues pelo Git
Instalado `5aaf1a56f9d928331364fcc8b0d1528e51dba327` sobre `56475acb`,preservado como versão anterior. Backup fresco `2026-10-26T08:57:09Z` e restauro isolado sem rede/porta55441: **174tabelas** por contagem/checksum e **369ficheiros/configuração** conferidos. **4ficheiros do delta,50protegidos e31originais** verificados;schema,roles/grants e permissões iguais. As172tabelas de negócio mantêm os valores do backup;cache/sessões reconciliadas com eventos operacionais/acessos anónimos,sem alteração de dados de negócio. Revisão/manifest público,7marcadores compilados,4assets e simuladorHTTP200 conferidos. Sem migrações,importações ou escrita privada sintética no activo.
Pipeline normal concluído;provasQA15frontend/API1-97/UI/tipos/build reutilizadas,sem nova ronda manual. **Disponível no âmbito demonstrado: resultado líquido3120 + ajustamento10 → lucro/base3130 → colecta1001,60MZN.** Representação exacta,ausência/informação em falta/campo sem aplicação e valores ainda sem correspondência conservados. M20 mantém fracções sem arredondamento presumido;M22 mantém preparação exacta ao cêntimo já aceite. Imposto próprio320 exterior produz resultado líquido2800,mas campo de acréscimo próprio continua pendente,sem usar213 de outrem. Divergência201/Q8 versus200/Q10 só limita o transporte afectado. Históricos e cálculos anteriores,pressupostos cambiais e âmbitosL3/ISPC/câmbio/L5 preservados. **Colecta não é saldo finalL8.** Recibo:`docs/investmoz/simulations/irpc-l6-values-forms-delivery-20261026.json`.
O estado anterior «QA sem instalação» de5aaf1a56 é histórico. O saldo seguinte separa desenvolvimento de esclarecimento documental,com exemplo e condição de retoma,para decidir o fecho operacional delimitado. **L6 não está integralmente concluído;L7 eL8 mantêm os seus âmbitos.** Não foi executada pesquisa nova nem repetição dos testes aceites para esta consolidação.
## 26/10/2026 — saldo consolidado de L6 para decisão de fecho operacional delimitado
Referência actual após a entrega `5aaf1a56`: percurso normal demonstrado até à **colecta**, com períodos/moedas/ajustamentos e preparação parcialM20/M22 documentados. Colecta não é saldo final a pagar ou recuperar;L8 conserva esse fecho. Esta lista consolida o saldo das notas anteriores,sem reabrir o que já foi demonstrado. Os pormenores e exemplares continuam nas mesmas secções/recibos;nenhuma nova matriz ou backlog é criado.
**Código ainda por implementar.** São extensões não demonstradas;as fontes já aceites permitem iniciar os casos correspondidos. Dados de um investidor em falta dentro de regra já implementada são uma pendência desse caso, não outra tarefa genérica deL6.
| Trabalho | Exemplo | Condição de retoma / alcance |
|---|---|---|
| Amortizações e quota de aluguer36h restantes | Ar condicionadoII/3/3,12,5%,fora dos10códigos implementados;bem usado com vida esperada e quotas anteriores documentadas. | Acrescentar catálogo e variantes previstas nas fontes aceites:usados/abertura/reparações/reavaliação,uso intensivo/concessões/peças/intangíveis,transição e excepções de método/vida útil,art17 em período curto e quota36h automática. Implementar só o caso escolhido e provar o delta;sem aguardar validação genérica daAT. Só activo,método ou quota ainda não suportados;amortizações demonstradas preservadas. |
| Custos e periodizações específicos | Campanha de lançamento300 com imputação por3exercícios;obra com receita antecipada positiva em vez do zero demonstrado. | Implementar36-A e articulação com36n,reforços financeiros28(3),19(5)/19(6) e18(6–10),com saldos/condições do caso. Autorização de mudança de método apenas quando a disposição aplicável a exigir. Provisões sectoriais dependem primeiro da norma específica indicada abaixo. Só campanha,obra ou periodização específica;limites/provisões ordinários e casos já demonstrados mantidos. |
| Períodos e sequência de perdas | Transição de4meses seguida dos períodos posteriores:aplicar a exclusão de contagem de41(5) ao período7(4)d,sem contar apenas anos civis. | Representar a sequência efectiva de períodos/perdas e acrescentar datas parciais,liquidação/períodos superiores a12meses e outros exercícios com regra/taxa aplicável. Não há nova pesquisa necessária para repetir o recorte de meses completos2026 já entregue. Só período ou utilização de perda dependente;lucro independente e semestres demonstrados preservados. |
| Desdobramentos contabilísticos e quadros/anexos M20/M22 restantes | Imposto próprio200 já incluído no plano e320 exterior:discriminar as duas componentes sem duplicar gasto;contas fora das6linhas financeiras ainda não transportadas. | Acrescentar o desdobramento e as correspondências dos quadros/anexos escolhidos,reutilizando dados existentes. Campos sem correspondência aguardam a referência concreta abaixo;os outros componentes podem ser implementados/provados separadamente. Só componente/conta/campo ainda não suportado;valores e campos correspondidos preservados. |
| Saldos em moeda estrangeira | Crédito final100USD não é soma das receitas convertidas por mês. | Implementar reconciliação de saldo e conversão pela data/regra que vier identificada,usando o motor cambial já entregue. A selecção mensal para simulação continua disponível;esta tarefa não cria outro mecanismo cambial. Só saldo/conversão fiscal dependente da regra;plano e pressupostos mensais permanecem disponíveis. |
**Esclarecimentos documentais aguardados.** Cada ponto abaixo exige apenas a referência/resposta específica indicada. A ausência dessa informação não significa revogação das fontes aceites,nem autoriza transformar a dúvida numa validação genérica deL6. Não se presume que um pedido já tenha sido enviado àAT;estes são pontos delimitados para o esclarecimento aplicável.
| Informação em falta | Exemplo da dúvida | Condição de retoma / alcance |
|---|---|---|
| Edição e campos M20/M22 | M20A.1/D35 remete201/quadro8;PDF M22 usa200/quadro10. Imposto próprio320 não pertence ao213 de outrem;quota recuperada−26 não tem campo de dedução confirmado. | Obter exemplar compatível ou instrução que identifique edição/período,campo e sentido do transporte. Para periodização/obras/reversões ainda sem campo,identificar a correspondência específica. Até informação nova,manter valores/efeitos sem código presumido e não repetir pesquisa. Só transporte,campo e somas dependentes;resultado líquido próprio,260/278/300 e demais campos conhecidos mantidos. |
| Representação fiscal de fracções | M20:300,50=601/2MZN,num exemplar que pede meticais sem centavos;M22:1/300MZN não é um número exacto de cêntimos. | Identificar instrução de representação/arredondamento da edição/campo ou esclarecimento específico. Conservar a fracção até lá;não deduzir regra de arredondamento apenas do rótulo «sem centavos». Só transcrição não exactamente representável;inteirosM20,cêntimos exactosM22 e cálculo racional preservados. |
| Articulação de limites em combinações não demonstradas | Combustível100,comprovado80,viatura de passageiros sem excepção:36h/i com36(4). Provisão de créditos200 num período curto de3meses:limite anual por corresponder. | Esclarecer especificamente a articulação h/i/36(4) e a base/limite dos períodos curtos de publicidade/créditos,se houver proporcionalização aplicável. Não somar exclusões,anualizar ou repartir por presunção. Retomar só perante referência/resposta concreta para o exemplo. Só combinação ou limite do período;casos independentes com regra já aplicada mantidos. |
| Regra fiscal de conversão anual | PlanoUSD com64MZN/USD por mês é pressuposto sintético de simulação,não confirmação da data/taxa fiscal anual ou da cotação do saldo final. | Identificar disposição/âmbito,data,base e taxa/boletim aplicáveis ao resultado e,quando necessário,ao saldo. Reutilizar o motor existente e demonstrar só a correspondência nova;sem taxa actual por defeito ou nova ronda da pesquisa anterior. Só confirmação fiscal anual e saldo dependente;conversões mensais documentadas de simulação mantidas com os avisos. |
| Norma sectorial de provisões reguladas | Provisão200 de uma entidade financeira sujeita ao28d não herda os1,5%/6% do regime ordinário29. | Identificar sector,regulador,norma de supervisão aplicável e saldos/condições necessários,antes da implementação específica. A fonte oficial fornecida é aceite;falta a regra concreta do caso,não certificação genérica da fonte. Só provisão regulada respectiva;provisões ordinárias demonstradas preservadas. |
**Base da decisão operacional:** o âmbito demonstrado e as suas limitações permanecem disponíveis na interface e nas exportações;as provas aceites mantêm validade. Um fecho operacional delimitado pode referir esse âmbito,com estas extensões/documentos fora da cobertura e retoma por caso. Esta consolidação **não declara L6 integralmente concluído nem regista uma decisão de fecho ainda não tomada**. Permite preparar o avanço paraL7 sem condicionar os casos independentes à resolução de todo este saldo. Benefícios/isenções/taxas reduzidas/tributações autónomas e operações especiais mantêm âmbitoL7;retenções,pagamentos,créditos e saldo anual mantêm âmbitoL8. As dez dúvidasL5 só afectam dependências efectivas e não foram pesquisadas novamente.
@@ -78,3 +78,6 @@
"Cópia privada ou derivado";"C:\laragon\www\portal-investidor\storage\app\private\portal-documents\b0ea969a-30ec-477b-8b8b-b7af82a11bfe";"b0ea969a-30ec-477b-8b8b-b7af82a11bfe";"67067";"5C69B6F189A1D3F5307E0CF7DD8224554705158A682637D3105AFAD615DB26E2";"b0ea969a-30ec-477b-8b8b-b7af82a11bfe";"C:\laragon\www\portal-investidor\storage\app\private\geo-ine-review-20260928\original.pdf + C:\laragon\www\portal-investidor\storage\app\private\geo-ine-review-20260928-v2\original.pdf + C:\laragon\www\portal-investidor\storage\app\private\portal-documents\b0ea969a-30ec-477b-8b8b-b7af82a11bfe";"Private stored copy already represented by its document record";"Acessível em armazenamento privado";"Inventariado por caminho, tamanho e SHA-256; não publicado nem aberto nesta revisão."
"Formulario fornecido Tempo";"\\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\portal do investidor\Notas\Novo Modelo A.docx";"Novo Modelo A.docx";"532008";"62C198E90D8C6792F7D5CCEFC6386DF2E4B6089573067D3A6E1EAE7FC2B9572B";"IVA Modelo A - exemplar Tempo";"";"Original privado na biblioteca QA; sem publicacao ou activacao";"Acessivel / importado QA / privado / scan limpo";"Imagem incorporada lida visualmente; edicao/vigencia nao certificada. Correspondencia na reconciliacao Modelo A, AUD-SIM-INT02. Variante de bytes preservada, nao duplicado por nome."
"Formulario fornecido Tempo";"\\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\portal do investidor\Notas\Novo Modelo A v1.docx";"Novo Modelo A v1.docx";"532100";"63D45FA80DB17A60B43619D55A25813229D670D14C758273F86316285DB8E02B";"IVA Modelo A - exemplar Tempo";"";"Original privado na biblioteca QA; sem publicacao ou activacao";"Acessivel / importado QA / privado / scan limpo";"Imagem incorporada lida visualmente; edicao/vigencia nao certificada. Correspondencia na reconciliacao Modelo A, AUD-SIM-INT02. Variante de bytes preservada, nao duplicado por nome."
"Documento oficial localizado para consultaQA";"C:\laragon\www\portal-investidor\outputs\iva-l1-g5d-offer-drafts-20261024\BR-11-I-2010-03-17-despacho-modelos.pdf";"BR-11-I-2010-03-17-despacho-modelos.pdf";"376928";"384fb46354e1888df43f72288dfed7933e30c7534211e0dcb6994f43b10e0059";"BR11/I Série17/03/2010,DespachoMF06/01/2010,ModelosRCBFDecreto56/2009";"";"Preservar original e origem;sem publicação/importação/activação de regra";"Acessível";"PDF1–5 lidos;ModeloI.1versoPDF3 localizado;âmbito ligação14(3)/alterações por conferir,sem nova autenticação da fonte oficial"
"Fonte oficial localizada para cotejoQA";"C:\laragon\www\portal-investidor\outputs\iva-l1-g6e-supplies-20261024\Decreto56-2009-BR40.pdf";"Decreto56-2009-BR40.pdf";"422005";"6ea1b8d93daed48c6d590481d874010fa1708211d8f27c319dc9a31328456017";"Decreto56/2009/CBFLei4/2009 — originalBR40 ecompilaçãoMIREME";"";"Preservar original/origem;sem publicação ou activação de cálculo";"Acessível";"CotejoModeloI.1;âmbitoCBF não demonstra remissãoCIVA14(3);não autenticação adicional"
"Fonte oficial localizada para cotejoQA";"C:\laragon\www\portal-investidor\outputs\iva-l1-g6e-supplies-20261024\MIREME-legislacao-investimentos.pdf";"MIREME-legislacao-investimentos.pdf";"1674566";"df50f6a489ffb35a4252fddec0ffa1f9c58d7b8cb4e54c9f25b7904bd39218b7";"Decreto56/2009/CBFLei4/2009 — originalBR40 ecompilaçãoMIREME";"";"Preservar original/origem;sem publicação ou activação de cálculo";"Acessível";"CotejoModeloI.1;âmbitoCBF não demonstra remissãoCIVA14(3);não autenticação adicional"
1 RecordType Path FileName SizeBytes SHA256 TitleOrSubject DuplicateGroup Disposition Status Notes
78 Cópia privada ou derivado C:\laragon\www\portal-investidor\storage\app\private\portal-documents\b0ea969a-30ec-477b-8b8b-b7af82a11bfe b0ea969a-30ec-477b-8b8b-b7af82a11bfe 67067 5C69B6F189A1D3F5307E0CF7DD8224554705158A682637D3105AFAD615DB26E2 b0ea969a-30ec-477b-8b8b-b7af82a11bfe C:\laragon\www\portal-investidor\storage\app\private\geo-ine-review-20260928\original.pdf + C:\laragon\www\portal-investidor\storage\app\private\geo-ine-review-20260928-v2\original.pdf + C:\laragon\www\portal-investidor\storage\app\private\portal-documents\b0ea969a-30ec-477b-8b8b-b7af82a11bfe Private stored copy already represented by its document record Acessível em armazenamento privado Inventariado por caminho, tamanho e SHA-256; não publicado nem aberto nesta revisão.
79 Formulario fornecido Tempo \\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\portal do investidor\Notas\Novo Modelo A.docx Novo Modelo A.docx 532008 62C198E90D8C6792F7D5CCEFC6386DF2E4B6089573067D3A6E1EAE7FC2B9572B IVA Modelo A - exemplar Tempo Original privado na biblioteca QA; sem publicacao ou activacao Acessivel / importado QA / privado / scan limpo Imagem incorporada lida visualmente; edicao/vigencia nao certificada. Correspondencia na reconciliacao Modelo A, AUD-SIM-INT02. Variante de bytes preservada, nao duplicado por nome.
80 Formulario fornecido Tempo \\Mac\Home\Documents\TEMPO\Portal Tempo\Servicos Tempo\portal do investidor\Notas\Novo Modelo A v1.docx Novo Modelo A v1.docx 532100 63D45FA80DB17A60B43619D55A25813229D670D14C758273F86316285DB8E02B IVA Modelo A - exemplar Tempo Original privado na biblioteca QA; sem publicacao ou activacao Acessivel / importado QA / privado / scan limpo Imagem incorporada lida visualmente; edicao/vigencia nao certificada. Correspondencia na reconciliacao Modelo A, AUD-SIM-INT02. Variante de bytes preservada, nao duplicado por nome.
81 Documento oficial localizado para consultaQA C:\laragon\www\portal-investidor\outputs\iva-l1-g5d-offer-drafts-20261024\BR-11-I-2010-03-17-despacho-modelos.pdf BR-11-I-2010-03-17-despacho-modelos.pdf 376928 384fb46354e1888df43f72288dfed7933e30c7534211e0dcb6994f43b10e0059 BR11/I Série17/03/2010,DespachoMF06/01/2010,ModelosRCBFDecreto56/2009 Preservar original e origem;sem publicação/importação/activação de regra Acessível PDF1–5 lidos;ModeloI.1versoPDF3 localizado;âmbito ligação14(3)/alterações por conferir,sem nova autenticação da fonte oficial
82 Fonte oficial localizada para cotejoQA C:\laragon\www\portal-investidor\outputs\iva-l1-g6e-supplies-20261024\Decreto56-2009-BR40.pdf Decreto56-2009-BR40.pdf 422005 6ea1b8d93daed48c6d590481d874010fa1708211d8f27c319dc9a31328456017 Decreto56/2009/CBFLei4/2009 — originalBR40 ecompilaçãoMIREME Preservar original/origem;sem publicação ou activação de cálculo Acessível CotejoModeloI.1;âmbitoCBF não demonstra remissãoCIVA14(3);não autenticação adicional
83 Fonte oficial localizada para cotejoQA C:\laragon\www\portal-investidor\outputs\iva-l1-g6e-supplies-20261024\MIREME-legislacao-investimentos.pdf MIREME-legislacao-investimentos.pdf 1674566 df50f6a489ffb35a4252fddec0ffa1f9c58d7b8cb4e54c9f25b7904bd39218b7 Decreto56/2009/CBFLei4/2009 — originalBR40 ecompilaçãoMIREME Preservar original/origem;sem publicação ou activação de cálculo Acessível CotejoModeloI.1;âmbitoCBF não demonstra remissãoCIVA14(3);não autenticação adicional
@@ -24,3 +24,6 @@
"docs/investmoz/simulations/official-source-register.md";"sumário oficial INM do BR 134/2024";"https://www.inm.gov.mz/pt-br/content/sum%C3%A1rio-br-n%C2%BA-134-de-110724-boletim-da-rep%C3%BAblica-i-serie-p%C3%A1g-2827";"Não identificado por esta referência; URL registada";"Referência de pesquisa/documentação; não conta como ficheiro importado";"Manter como fonte externa a obter/conferir; não activa regra fiscal"
"docs/investmoz/simulations/official-source-register.md";"ficha oficial INM do aviso";"https://www.inm.gov.mz/pt-br/content/assembleia-da-rep%C3%BAblica-br-n%C2%BA-89-de-080617-boletim-da-rep%C3%BAblica-i-serie-p%C3%A1g-569";"Não identificado por esta referência; URL registada";"Referência de pesquisa/documentação; não conta como ficheiro importado";"Manter como fonte externa a obter/conferir; não activa regra fiscal"
"docs/investmoz/simulations/official-source-register.md";"reprodução integral de terceiro, auxiliar";"https://www.lexlink.eu/FileGet.aspx?FileId=2999523";"Não identificado por esta referência; URL registada";"Referência de pesquisa/documentação; não conta como ficheiro importado";"Manter como fonte externa a obter/conferir; não activa regra fiscal"
"docs/investmoz/simulations/iva-l1-p084-p085-draft-preparation-qa-20261024.json";"BR11/2010,DespachoMF06/01/2010,ModeloI.1versoPDF3";"https://www.cipmoz.org/wp-content/uploads/2023/parcerias-publico-privadas/9PP%29%20Despacho_Mecanismos%20Implementacao%20do%20Regulamento%20do%20Codigo%20dos%20Beneficios%20Fiscais.pdf";"C:\laragon\www\portal-investidor\outputs\iva-l1-g5d-offer-drafts-20261024\BR-11-I-2010-03-17-despacho-modelos.pdf";"Original oficialBR obtido/hash;âmbito específico ainda por conferir";"Consulta autorizada;sem publicação ou activação fiscal"
"docs/investmoz/simulations/iva-l1-p084-p085-model-i1-cotejo-20261024.json";"Decreto56/2009/RegCBFLei4/2009,origemModeloI.1";"https://fracessoriasa.co.mz/wp-content/uploads/2021/03/10-Decreto-n_56.2009-REGULAMENTO-DOS-BENEFICIOS-FISCAIS.pdf";"C:\laragon\www\portal-investidor\outputs\iva-l1-g6e-supplies-20261024\Decreto56-2009-BR40.pdf";"OriginalBR ecompilaçãooficial obtidos/hash,âmbito cotejado";"Sem correspondênciaCIVA14(3)demonstrada;sem publicação ou activação fiscal"
"docs/investmoz/simulations/iva-l1-p084-p085-model-i1-cotejo-20261024.json";"Decreto56/2009/RegCBFLei4/2009,origemModeloI.1";"https://mireme.gov.mz/wp-content/uploads/2022/03/Lei-e-Regualamento-das-zonas-francas-industriais-investimentos.pdf";"C:\laragon\www\portal-investidor\outputs\iva-l1-g6e-supplies-20261024\MIREME-legislacao-investimentos.pdf";"OriginalBR ecompilaçãooficial obtidos/hash,âmbito cotejado";"Sem correspondênciaCIVA14(3)demonstrada;sem publicação ou activação fiscal"
1 SourceRegister Label URL LocalBinary State Disposition
24 docs/investmoz/simulations/official-source-register.md sumário oficial INM do BR 134/2024 https://www.inm.gov.mz/pt-br/content/sum%C3%A1rio-br-n%C2%BA-134-de-110724-boletim-da-rep%C3%BAblica-i-serie-p%C3%A1g-2827 Não identificado por esta referência; URL registada Referência de pesquisa/documentação; não conta como ficheiro importado Manter como fonte externa a obter/conferir; não activa regra fiscal
25 docs/investmoz/simulations/official-source-register.md ficha oficial INM do aviso https://www.inm.gov.mz/pt-br/content/assembleia-da-rep%C3%BAblica-br-n%C2%BA-89-de-080617-boletim-da-rep%C3%BAblica-i-serie-p%C3%A1g-569 Não identificado por esta referência; URL registada Referência de pesquisa/documentação; não conta como ficheiro importado Manter como fonte externa a obter/conferir; não activa regra fiscal
26 docs/investmoz/simulations/official-source-register.md reprodução integral de terceiro, auxiliar https://www.lexlink.eu/FileGet.aspx?FileId=2999523 Não identificado por esta referência; URL registada Referência de pesquisa/documentação; não conta como ficheiro importado Manter como fonte externa a obter/conferir; não activa regra fiscal
27 docs/investmoz/simulations/iva-l1-p084-p085-draft-preparation-qa-20261024.json BR11/2010,DespachoMF06/01/2010,ModeloI.1versoPDF3 https://www.cipmoz.org/wp-content/uploads/2023/parcerias-publico-privadas/9PP%29%20Despacho_Mecanismos%20Implementacao%20do%20Regulamento%20do%20Codigo%20dos%20Beneficios%20Fiscais.pdf C:\laragon\www\portal-investidor\outputs\iva-l1-g5d-offer-drafts-20261024\BR-11-I-2010-03-17-despacho-modelos.pdf Original oficialBR obtido/hash;âmbito específico ainda por conferir Consulta autorizada;sem publicação ou activação fiscal
28 docs/investmoz/simulations/iva-l1-p084-p085-model-i1-cotejo-20261024.json Decreto56/2009/RegCBFLei4/2009,origemModeloI.1 https://fracessoriasa.co.mz/wp-content/uploads/2021/03/10-Decreto-n_56.2009-REGULAMENTO-DOS-BENEFICIOS-FISCAIS.pdf C:\laragon\www\portal-investidor\outputs\iva-l1-g6e-supplies-20261024\Decreto56-2009-BR40.pdf OriginalBR ecompilaçãooficial obtidos/hash,âmbito cotejado Sem correspondênciaCIVA14(3)demonstrada;sem publicação ou activação fiscal
29 docs/investmoz/simulations/iva-l1-p084-p085-model-i1-cotejo-20261024.json Decreto56/2009/RegCBFLei4/2009,origemModeloI.1 https://mireme.gov.mz/wp-content/uploads/2022/03/Lei-e-Regualamento-das-zonas-francas-industriais-investimentos.pdf C:\laragon\www\portal-investidor\outputs\iva-l1-g6e-supplies-20261024\MIREME-legislacao-investimentos.pdf OriginalBR ecompilaçãooficial obtidos/hash,âmbito cotejado Sem correspondênciaCIVA14(3)demonstrada;sem publicação ou activação fiscal
@@ -0,0 +1,211 @@
# Levantamento funcional, entidades e eventos — InvestMoz
**Data do levantamento:** 9 de Outubro de 2026
**Âmbito:** aplicação Laravel/React presente neste repositório.
**Base de evidência:** README, rotas, controladores, modelos, migrations e documentação em `docs/investmoz/`. A existência de uma tabela, rota ou documento não prova que a função esteja activa em produção.
## 1. Resumo executivo
O projecto é uma plataforma de investimento com área pública e área autenticada. Abrange descoberta de oportunidades e negócios, manifestações de interesse, gestão de candidaturas e carteira, CRM local, geografia e zonas de investimento, simulador e governação fiscal, catálogo documental, educação, assistência de terra, parcerias, balcão virtual, IA com fontes e integrações preparadas.
O README apresenta a base inicial do portal (sectores, oportunidades e manifestações). O código actual e os documentos de domínio registam a extensão funcional posterior. Para o inventário detalhado dos fluxos, consultar [casos-de-uso-aplicacao-actual.md](casos-de-uso-aplicacao-actual.md), que identifica 24 casos de uso. Este documento complementa-o com uma visão de domínio, um diagrama resumido de relações e a frequência observável dos eventos.
## 2. Âmbito e método
Foi feito inventário dos caminhos acessíveis no repositório: **981 ficheiros** por `rg --files`, excluindo dependências geradas `vendor` e `node_modules`. Dentro da aplicação foram consultados, em particular, `routes/`, `app/Models/`, `app/Http/Controllers/`, `database/migrations/`, `database/seeders/` e `docs/investmoz/`. O número é uma contagem do inventário local nessa data, não um inventário de anexos externos ou de dados de produção.
Classificação usada:
- **Implementado no código:** rota, controlador, job, comando ou schema identificável.
- **Documentado/planeado:** descrito em documentação, sem prova suficiente de execução integrada.
- **Frequência de negócio desconhecida:** não há amostra de eventos de produção nem telemetria para calcular volume por hora/dia/mês.
- **Cadência técnica explícita:** periodicidade configurada no scheduler ou no mecanismo de fila.
## 3. Actores e sistemas
| Actor | Objectivo principal | Áreas usadas |
|---|---|---|
| Visitante | Consultar conteúdos públicos e iniciar pedidos | Portal, oportunidades, negócios, zonas, documentos, simulador |
| Investidor/utilizador | Manter perfil, favoritos, rascunhos, submissões, documentos e mensagens | Espaço do investidor, carteira, assistência, parcerias |
| Gestor de portal/CRM | Rever interesses, gerir leads, tarefas, catálogo e publicação | CRM local, gestão de portal |
| Gestor territorial | Manter projectos, clusters, corredores, relações, geografia e zonas | Catálogo territorial, GIS, zonas |
| Revisor documental | Conferir proveniência, versão, hash, autorização e análise antimalware | Biblioteca documental |
| Gestor fiscal | Rever fontes, parâmetros e versões das regras fiscais | Governação fiscal, simulador |
| Gestor de educação | Manter competências, necessidades, cursos, capacidades e propostas | Educação |
| Gestor/agente de assistência | Tratar pedidos de terra e pedidos do balcão virtual | Assistência de terra, balcão |
| Parceiro institucional | Participar em oportunidades/parcerias e colaborar em salas | Parcerias |
| Administrador | Gerir autenticação, segurança, configurações e permissões | Administração |
| Sistema externo/worker | Receber/enviar mensagens ou executar trabalho assíncrono | Outbox/inbox, filas, integrações |
Papéis são uma leitura funcional dos fluxos. A autorização efectiva depende das policies, middleware e permissões implementadas, não apenas desta tabela.
## 4. Catálogo de casos de uso
O documento [Casos de uso da aplicação actual](casos-de-uso-aplicacao-actual.md) detalha pré-condições, fluxos e dados para cada caso. Índice consolidado:
| ID | Caso de uso | Actor principal | Resultado |
|---|---|---|---|
| UC-01 | Consultar página inicial e serviços | Visitante | Entrada no serviço público autorizado |
| UC-02 | Pesquisar sectores e oportunidades | Visitante/investidor | Lista/detalhe e possível favorito/interesse |
| UC-03 | Consultar negócio existente | Visitante/investidor | Consulta da oferta divulgável |
| UC-04 | Criar conta, autenticar e recuperar acesso | Utilizador | Sessão autenticada/verificada |
| UC-05 | Manifestar interesse numa oportunidade | Visitante/investidor | Pedido recebido para tratamento |
| UC-06 | Manifestar interesse num negócio existente | Investidor | Pedido ligado ao negócio e consentimento |
| UC-07 | Guardar oportunidade e manter espaço do investidor | Utilizador | Favorito, dossier ou item na carteira |
| UC-08 | Criar e manter submissão de investimento | Investidor | Submissão em rascunho com histórico |
| UC-09 | Submeter candidatura | Investidor | Entrada em fila de tratamento |
| UC-10 | Gerir negócio existente | Proprietário/gestor | Registo revisto e eventualmente publicável |
| UC-11 | Tratar interesses no CRM | Gestor | Qualificação, lead, tarefa e seguimento |
| UC-12 | Gerir catálogo territorial | Gestor territorial | Projectos, clusters, corredores e relações |
| UC-13 | Gerir zonas de investimento | Gestor territorial/revisor | Zona validada, publicada ou suspensa |
| UC-14 | Carregar, verificar e publicar documento | Revisor documental | Documento preservado com estados independentes |
| UC-15 | Criar/retomar rascunho de simulação | Visitante/utilizador | Rascunho recuperável, sem cálculo implícito |
| UC-16 | Executar simulação | Visitante/utilizador | Resultado, obrigações, fontes e relatório |
| UC-17 | Gerir regra fiscal | Gestor fiscal | Versão de regra passa por revisão/aprovação |
| UC-18 | Gerir educação e competências | Gestor de educação | Catálogo, análise de lacunas e proposta |
| UC-19 | Abrir/tratar assistência de terra | Investidor/gestor | Caso acompanhado até encaminhamento/fecho |
| UC-20 | Criar e gerir parceria | Investidor/parceiro | Interesse, sala, mensagens, documentos e marcos |
| UC-21 | Usar balcão virtual | Utilizador/agente | Pedido de serviço acompanhado até resolução |
| UC-22 | Usar IA com evidência | Gestor autorizado | Execução rastreável ligada a fontes e feedback |
| UC-23 | Sincronizar sistemas externos | Worker/sistema externo | Eventos recebidos/enviados e divergências registadas |
| UC-24 | Auditar alterações | Sistema/gestor/auditor | Histórico e correlação para operações relevantes |
## 5. Diagrama de entidades e relações
Diagrama lógico resumido por domínios. As cardinalidades representam a estrutura documentada; algumas relações polimórficas, opcionais ou em tabelas de junção estão simplificadas. Para o ERD de schema detalhado, consultar [erd.mmd](erd.mmd), [data-dictionary.csv](data-dictionary.csv) e [table-catalog.csv](table-catalog.csv).
```mermaid
erDiagram
USER ||--o{ INVESTOR : possui
USER ||--o{ SUBMISSION : cria
USER ||--o{ SIMULATION : executa
USER ||--o{ AUDIT_EVENT : origina
SECTOR ||--o{ OPPORTUNITY : classifica
OPPORTUNITY ||--o{ INTEREST_REQUEST : recebe
EXISTING_BUSINESS ||--o{ INTEREST_REQUEST : recebe
INVESTOR ||--o{ INTEREST_REQUEST : manifesta
INTEREST_REQUEST ||--o| LEAD : converte
LEAD ||--o{ CRM_TASK : acompanha
OPPORTUNITY ||--o{ SUBMISSION : referencia
SUBMISSION ||--o{ SUBMISSION_REVISION : versiona
SUBMISSION ||--o{ SUBMISSION_EVENT : regista
SUBMISSION ||--o{ DOCUMENT_LINK : anexa
PROJECT }o--o{ ECONOMIC_CLUSTER : associa
PROJECT }o--o{ DEVELOPMENT_CORRIDOR : associa
PROJECT ||--o{ INVESTMENT_GAP : identifica
INVESTMENT_ZONE ||--o{ ZONE_REVISION : versiona
INVESTMENT_ZONE ||--o{ ZONE_RELATION : liga
INVESTMENT_ZONE ||--o{ ZONE_ATTACHMENT : documenta
DOCUMENT ||--o{ DOCUMENT_VERSION : versiona
DOCUMENT ||--o{ MALWARE_SCAN : analisa
DOCUMENT }o--o{ PORTAL_RESOURCE : disponibiliza
SIMULATION ||--o{ SIMULATION_SCENARIO : contém
SIMULATION_SCENARIO ||--o{ SIMULATION_RESULT : produz
SIMULATION_RESULT ||--o{ SIMULATION_OBLIGATION : discrimina
SIMULATION_RESULT ||--o{ RESULT_SOURCE : fundamenta
TAX_RULE_VERSION }o--o{ LEGAL_SOURCE : fundamenta
PROJECT ||--o{ TRAINING_NEED : requer
SKILL }o--o{ OCCUPATION : relacionada
TRAINING_PROVIDER ||--o{ COURSE : oferece
USER ||--o{ LAND_ASSISTANCE_CASE : requer
PARTNERSHIP ||--o{ PARTNERSHIP_INTEREST : recebe
PARTNERSHIP ||--o| PARTNERSHIP_ROOM : abre
PARTNERSHIP_ROOM ||--o{ PARTNERSHIP_MESSAGE : contém
DESK_CASE ||--o{ DESK_EVENT : regista
AI_SOURCE ||--o{ AI_CHUNK : divide
AI_SOURCE ||--o{ AI_RUN : suporta
OUTBOX_EVENT }o..|| SYNC_RUN : processa
SYNC_RUN ||--o{ RECONCILIATION_ISSUE : detecta
```
### 5.1 Domínios e entidades nucleares
| Domínio | Entidades nucleares | Relações principais |
|---|---|---|
| Identidade e acesso | `users`, `passkeys`, sessões, organizações, memberships | Utilizador possui perfil e inicia operações protegidas |
| Catálogo público | `sectors`, `opportunities`, catálogos de referência, recursos do portal | Sector classifica oportunidades; publicação controla exposição |
| Negócios existentes | `existing_businesses`, objectos, locais, revisões, mandatos | Negócio tem objectos/locais/documentos e workflow próprio |
| Investidor e CRM | `investors`, `interest_requests`, `leads`, `contacts`, oportunidades CRM, tarefas | Interesse pode converter-se em lead e gerar tarefas/actividades |
| Carteira e submissões | dossiers, `investment_submissions`, necessidades, revisões, eventos, mensagens, anexos | Submissão pertence a utilizador e liga-se a oportunidade/negócio |
| Território e GIS | `projects`, `economic_clusters`, `development_corridors`, `geo_locations`, `value_chains`, `investment_gaps` | Relações muitos-para-muitos documentam associação territorial/económica |
| Zonas de investimento | `investment_zones`, fontes legais, geometrias, relações, anexos, revisões | Zona tem localização, evidência, relações e estado de validação/publicação |
| Documentos | `documents`, versões, scans, associações por domínio, recursos do portal | Documento pode ser associado a várias entidades; disponibilidade, estado documental e uso em cálculo são independentes |
| Simulação e fiscalidade | rascunhos, `simulations`, cenários, resultados, obrigações, fontes, regras versionadas | Execução usa versões/parâmetros elegíveis e preserva as fontes do resultado |
| Educação | skills, occupations, providers, courses, training needs/capacity, propostas | Projectos expressam necessidades relacionadas com competências e formação |
| Serviços e colaboração | casos de terra, balcão virtual, parcerias, salas, mensagens, documentos, marcos | Casos e salas mantêm eventos e participantes próprios |
| IA e governação | controlos, fontes/chunks, execuções, feedback, auditoria | Execução de IA deve poder ser rastreada às fontes e ao actor |
| Integrações | `outbox_events`, `inbox_events`, `sync_runs`, reconciliações | Eventos são idempotentes/correlacionáveis; desenho de schema não prova integração activa |
## 6. Eventos e frequência
### 6.1 Frequência explicitamente configurada
| Evento/processo | Gatilho | Frequência/cadência no código | Natureza e observação |
|---|---|---|---|
| Escalar tarefas vencidas (`investmoz:escalate-overdue-tasks`) | Scheduler Laravel | **A cada 15 minutos**, com `withoutOverlapping()` | Única periodicidade de scheduler encontrada em `routes/console.php`; execução real requer scheduler/cron activo |
| Executar simulação (`RunSimulation`) | Pedido de cálculo aceite | Por submissão, via fila, `afterCommit` | Assíncrono; frequência depende da procura e de workers activos |
| Analisar documento (`ScanDocumentForMalware`) | Upload/solicitação de scan em fluxos suportados | Por documento, via fila, `afterCommit`; job único por identidade configurada | Cadência sob procura; requer worker e scanner configurados. Upload/publicação não confirma scan limpo |
| Comparar compatibilidade MNE (`CompareMneBusiness`) | Alteração de negócio que agenda comparação | Por alteração aplicável, em fila específica e `afterCommit` | Trabalho assíncrono/sombra; volume real desconhecido |
| Notificar recepção de interesse (`NotifyInterestReceived`) | Disparo esperado após recepção de interesse | Job existe, mas não foi localizada chamada a `dispatch()` no código consultado; frequência de execução não confirmada | Tratar como capacidade prevista até localizar/activar o disparo; entrega efectiva também depende de configuração e worker |
| Auditoria, revisões e eventos de domínio | Acção de utilizador/sistema | No momento da operação que os gera | Orientado a evento; não há taxa histórica neste levantamento |
| Outbox/inbox e sincronização externa | Evento de domínio ou mensagem externa | Sem periodicidade operacional confirmada neste código/documentação consultada | Estrutura preparada; documentação aponta sincronização externa real como pendente/não activada |
### 6.2 Frequência por categoria de actividade
| Categoria | Frequência funcional esperada | O que é possível afirmar |
|---|---|---|
| Leituras públicas (home, catálogo, oportunidade, negócio, mapas/referências) | Sob procura do visitante | Há endpoints/páginas; sem logs ou analytics não se quantificam consultas |
| Escritas de investidor (interesses, favoritos, submissões, mensagens, perfil) | Sob acção do utilizador | São iniciadas por pedido explícito; não há volume observado disponível |
| Gestão (revisão, publicação, CRM, regras, zonas, catálogo) | Sob trabalho de gestores autorizados | Fluxos e protecções documentados; frequência por papel não medida |
| Simulação e rascunhos | Sob utilização do simulador; rascunhos podem ser actualizados/retomados | Rota e jobs encontrados; não assumir execução periódica nem cálculo fiscal por guardar rascunho |
| Uploads e análise documental | Sob envio/reanálise de documento | Job de scan é disparado por fluxos suportados; scan e publicação são estados distintos |
| Auditoria | Sob operações auditadas | A frequência acompanha as operações instrumentadas; cobertura total precisa de confirmação por fluxo |
| Regras fiscais e fontes | Sob processo de revisão/aprovação e alteração normativa | Não há calendário fixo; fonte publicada não activa automaticamente cálculo |
| Integrações externas | Não determinável/activação pendente | Tabelas de integração e documentação não são prova de entrega ou sincronização real |
### 6.3 Frequência observada versus frequência de execução
Não foram disponibilizados logs, contagens de `audit_events`, filas, analytics, pedidos HTTP ou exportação da base activa. Por isso, **não é possível apresentar eventos por hora/dia/mês, sazonalidade, taxa de falhas ou utilizadores activos**. A cadência de 15 minutos é apenas o intervalo configurado para o comando agendado. Para apurar frequência real, recolher métricas autorizadas por tipo de evento, intervalo temporal e resultado, sem expor dados pessoais; documentar período da amostra, filtros, retenção e origem. Não inferir métricas a partir de seeders, testes, screenshots ou schema.
## 7. Sequência de alto nível
```text
Visita pública
-> pesquisa catálogo/oportunidades/negócios/território
-> interesse, candidatura, assistência ou simulação
-> autenticação e consentimento quando exigidos
-> gravação do pedido/rascunho e histórico
-> trabalho assíncrono quando aplicável (scan, cálculo, notificação)
-> revisão por responsável autorizado
-> decisão, comunicação ou publicação com autorização
-> auditoria e eventual integração externa homologada
```
## 8. Regras transversais que afectam os fluxos
- Disponibilidade para consulta, situação jurídica/documental e uso em regra/cálculo são estados independentes.
- Importar ou publicar documento não activa regra nem cálculo fiscal.
- Relações sem citação/evidência verificada devem ficar pendentes e identificadas.
- Guardar um rascunho não equivale a submeter ou aprovar.
- A divulgação obedece à autorização registada e ao seu âmbito.
- Documento original, proveniência, identificador, edição/data, hash e histórico devem ser preservados; não marcar autenticidade, vigência, direitos ou scan como confirmados sem evidência.
- Integração desenhada (outbox/inbox) não equivale a sincronização activa.
- Alterações a dados activos exigem confirmação de backup/restauro e acção autenticada necessária; testes/migrações devem usar exclusivamente base QA isolada, conforme `AGENTS.md`.
## 9. Limitações e pontos para validação
1. A cobertura implementada de cada UC varia; alguns documentos descrevem trabalho parcial, proposto ou bloqueado. Consultar `docs/investmoz/validation.md`, `completion-audit-2026-10-04.md`, `delivery-gaps.md` e os README de cada domínio antes de declarar operação concluída.
2. O ERD resumido não substitui constraints/FKs, cardinalidades exactas, escopos de acesso ou estados enumerados no schema e OpenAPI.
3. A frequência real de utilização e dos eventos de negócio permanece **indeterminada** sem telemetria operacional.
4. Execução do scheduler, workers, ClamAV, notificações, SuiteCRM e restantes conectores depende de configuração e operação externa verificável.
5. O inventário desta tarefa é do repositório, não dos ficheiros/anexos em armazenamento externo nem da base de dados de produção.
## 10. Fontes locais principais
- [README do projecto](../../README.md)
- [Casos de uso detalhados](casos-de-uso-aplicacao-actual.md)
- [ERD do schema reconciliado](erd.mmd)
- [Arquitectura e migrations](architecture-and-migrations.md)
- [Validação](validation.md) e [auditoria de conclusão](completion-audit-2026-10-04.md)
- Rotas: `routes/web.php`, `routes/api.php`, `routes/investment.php`, `routes/partnerships.php`, `routes/land-assistance.php`, `routes/investment-zones.php`, `routes/territorial-registry.php`
- Cadência: `routes/console.php`; trabalhos assíncronos em `app/Jobs/`
@@ -0,0 +1,710 @@
{
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: aplicar o anexo de identidade visual aos cinco cartões de Encontre o contexto do seu investimento.",
"instructionSource": {
"path": "C:\\Users\\jorge\\.codex\\attachments\\637b878f-1f58-490d-bd07-d5cd10ae2377\\Pasted text.txt",
"sha256": "fcc24dcce4b5df3f10e29add48052808d48ddcf674d052287854e11910e01d69"
},
"source": {
"type": "AI-generated photorealistic illustrative images",
"tool": "image_gen, built-in mode",
"skill": "C:/Users/jorge/.codex/skills/.system/imagegen/SKILL.md",
"externalPhotographsUsed": false,
"namedRealLocationsDepicted": false,
"note": "Cenas ilustrativas plausíveis, sem atribuição a instalações, pessoas, instituições ou projectos reais."
},
"analysisAndPlan": "docs/investmoz/public-portal-sections.md#fotografias-nos-cartões-de-contexto-do-investimento--23102026",
"filesChanged": [
"resources/js/pages/PortalInvestidor.tsx",
"resources/js/components/investment-context-cards.tsx",
"tools/portal-context-cards-qa.mjs",
"docs/investmoz/public-portal-sections.md",
"docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv",
"docs/investmoz/public-portal-context-images.json"
],
"images": [
{
"key": "clusters-agroindustria",
"prompt": "Use case: photorealistic-natural. Asset type: an individual navigation card photograph for a professional investment portal. Generate ONE clean, realistic editorial photograph in horizontal 16:9 composition. Natural daylight, realistic restrained colours, excellent photographic detail, balanced uncluttered framing, one clear subject readable at a small thumbnail size. Contemporary setting plausible in Mozambique in southern Africa. This is a generic illustrative scene, NOT a depiction or claim about any named real facility, project, landmark or institution. No text, lettering, titles, captions, logos, brands, watermarks, flags, official emblems, maps, diagrams, graphical overlays, UI elements, collages, artificial colour filters, futuristic architecture or advertising poster treatment. Realistic people, hands, equipment and perspective; dignified candid activity instead of posed stock photography. Subject: a modest, well maintained agro-processing packing facility linking commercial agriculture to local industry. Wide three-quarter view into an airy open-sided processing shed with pale walls and a few orderly wooden or reusable produce crates, stainless processing/sorting benches and an unobtrusive commercial agricultural field visible beyond. Two Black southern African workers in clean practical workwear sorting harvested vegetables naturally, faces not prominent. Show production and transformation together in ONE genuine-looking continuous scene, no montage. Clear simple geometry, warm-neutral sunlight, subtle vegetation.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-f72e66b0-d788-4476-8b20-c39b22d5d6dc.png",
"original": "outputs/investment-context-20261023/originals/clusters-agroindustria.png",
"originalSha256": "75e04a694081ab757831fc9b37323949d09806e622c83d07588fc47c423c9033",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-context/clusters-agroindustria.webp",
"width": 960,
"height": 540,
"bytes": 116796,
"sha256": "12494b31ab551cffb79f81c7d1519c0c4a2d4236e7f129bec1ce32251b39d847"
},
{
"file": "public/images/investment-context/clusters-agroindustria-480.webp",
"width": 480,
"height": 270,
"bytes": 42060,
"sha256": "76e3152c99ed188f748542dcf0464787307dbdc1c6299e7264dfd1bd86ad75e3"
},
{
"file": "public/images/investment-context/clusters-agroindustria-fallback.webp",
"width": 240,
"height": 135,
"bytes": 9596,
"sha256": "9f668da50f7d64955b31940d239b420ac18dbb76a8120c8bedab3f2c04710288"
}
]
},
{
"key": "corredores-logisticos",
"prompt": "Use case: photorealistic-natural. Asset type: an individual navigation card photograph for a professional investment portal. Generate ONE clean, realistic editorial photograph in horizontal 16:9 composition. Natural daylight, realistic restrained colours, excellent photographic detail, balanced uncluttered framing, one clear subject readable at a small thumbnail size. Contemporary setting plausible in Mozambique in southern Africa. This is a generic illustrative scene, NOT a depiction or claim about any named real facility, project, landmark or institution. No text, lettering, titles, captions, logos, brands, watermarks, flags, official emblems, maps, diagrams, graphical overlays, UI elements, collages, artificial colour filters, futuristic architecture or advertising poster treatment. Realistic people, hands, equipment and perspective; dignified candid activity instead of posed stock photography. Subject: a commercial freight terminal serving a southern African logistics corridor. Elevated medium-wide viewpoint showing an orderly short line of unbranded freight containers, one realistic container-handling crane and a freight truck on a paved lane, with a calm strip of water and low coastal industrial vegetation in the distance. Infrastructure of credible modest contemporary scale, generic and unidentifiable; do not reproduce or name Maputo, Beira, Nacala or any real port. Spatially coherent containers, road and handling equipment; clean clear subject with no excessive machinery.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-0363da23-f9cb-413b-bb64-024539085c4b.png",
"original": "outputs/investment-context-20261023/originals/corredores-logisticos-v2.png",
"originalSha256": "2151d1a59265c6f7151d18af6ef6ad78f9fc6e0cd58ac9cc5c64b50a25c5058e",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-context/corredores-logisticos-v2.webp",
"width": 960,
"height": 540,
"bytes": 85184,
"sha256": "1939c26df297588b6c3e5ea08b700d4cda5d1183cf3e5faed06a1ca060d2475e"
},
{
"file": "public/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 480,
"height": 270,
"bytes": 26222,
"sha256": "06dc0e7126cb2c13eb3f9a98f6ee58f5d64f9d07c28620975f744f263744fe15"
},
{
"file": "public/images/investment-context/corredores-logisticos-v2-fallback.webp",
"width": 240,
"height": 135,
"bytes": 5334,
"sha256": "f9fd6e6c3a2d4654df1a8fdb287e122f1889b5d318c104c4816ee393c793e242"
}
],
"selectedSource": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-c2cff7da-d602-4191-9aca-380918a09619.png",
"editPrompt": "Edit the provided photograph: REMOVE THE ENTIRE FOREGROUND TRUCK, including cab, wheels, long trailer and the red freight container on that trailer. The big truck at lower left/centre must be completely gone. Replace the removed truck's area with a continuous empty realistic paved road surface matching the surrounding pavement and road markings. Leave the stacked stationary freight containers along the quay, the water, the large port crane, the lifted container and workers. All remaining equipment and containers should have plain surfaces without readable lettering, logos, numbers or brands. No new truck, vehicle, symbol, text or overlay. Keep a single clean editorial photograph, natural lighting and horizontal 16:9 framing. Generic commercial port scene, not a named real facility."
},
{
"key": "projectos-ancora",
"prompt": "Use case: photorealistic-natural. Asset type: an individual navigation card photograph for a professional investment portal. Generate ONE clean, realistic editorial photograph in horizontal 16:9 composition. Natural daylight, realistic restrained colours, excellent photographic detail, balanced uncluttered framing, one clear subject readable at a small thumbnail size. Contemporary setting plausible in Mozambique in southern Africa. This is a generic illustrative scene, NOT a depiction or claim about any named real facility, project, landmark or institution. No text, lettering, titles, captions, logos, brands, watermarks, flags, official emblems, maps, diagrams, graphical overlays, UI elements, collages, artificial colour filters, futuristic architecture or advertising poster treatment. Realistic people, hands, equipment and perspective; dignified candid activity instead of posed stock photography. Subject: a small team of two Black southern African engineering professionals, one woman and one man, in realistic hard hats and restrained protective workwear, seen candidly from a three-quarter rear angle reviewing an unmarked folded technical plan at a utility-scale solar installation. Low rows of realistic blue solar panels and a simple low service building recede into a dry green southern African landscape. No readable drawing or numbers on the plan. Focus on credible engineering and investment project scale; clean composition, quiet professional atmosphere, no landmark or company identifiers.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-19fcd882-542b-43c9-81e7-593fd75083f6.png",
"original": "outputs/investment-context-20261023/originals/projectos-ancora.png",
"originalSha256": "f23cf6e64307a280f3aa58741454a23480ac28fcae01a0810adf134b783a3a74",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-context/projectos-ancora.webp",
"width": 960,
"height": 540,
"bytes": 77114,
"sha256": "de0b59774246fee982761de59618b3e7707c3fe30f2b1bcbb6017d4dce53c4dc"
},
{
"file": "public/images/investment-context/projectos-ancora-480.webp",
"width": 480,
"height": 270,
"bytes": 29484,
"sha256": "268e405112ed341fce3c9792c3caa47053984100cd4a204453e31bbe5db6e890"
},
{
"file": "public/images/investment-context/projectos-ancora-fallback.webp",
"width": 240,
"height": 135,
"bytes": 6750,
"sha256": "db7e4b4382e09eb6b4f9f2a4603ccac4b4eacc53ba0f6776429e33dbf5131954"
}
]
},
{
"key": "educacao-formacao",
"prompt": "Use case: photorealistic-natural. Asset type: an individual navigation card photograph for a professional investment portal. Generate ONE clean, realistic editorial photograph in horizontal 16:9 composition. Natural daylight, realistic restrained colours, excellent photographic detail, balanced uncluttered framing, one clear subject readable at a small thumbnail size. Contemporary setting plausible in Mozambique in southern Africa. This is a generic illustrative scene, NOT a depiction or claim about any named real facility, project, landmark or institution. No text, lettering, titles, captions, logos, brands, watermarks, flags, official emblems, maps, diagrams, graphical overlays, UI elements, collages, artificial colour filters, futuristic architecture or advertising poster treatment. Realistic people, hands, equipment and perspective; dignified candid activity instead of posed stock photography. Subject: a candid technical training classroom with three Black southern African young adult students of different genders and one instructor working together at a practical electronics and computing workbench. Bright modest well maintained vocational classroom, natural window light, simple laboratory equipment and unbranded closed or angled laptops whose screens have no visible interface or text. Focus on two students engaged in a realistic small hands-on electronics exercise with normal anatomy and correct equipment proportions. Dignified contemporary clothing, natural concentration, professional skills and human capital investment, no posed smiles or stereotypes.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-d21314d7-c726-41ad-862c-3c8b64df6b53.png",
"original": "outputs/investment-context-20261023/originals/educacao-formacao.png",
"originalSha256": "e59ec599e8c64ab84195d0cb37871d3102df178a13275806ca3b7f98e6bfa895",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-context/educacao-formacao.webp",
"width": 960,
"height": 540,
"bytes": 68224,
"sha256": "e3e5dbd292cac555a45bcbd94a0fa6b60e6b710debc0c827c68603f40bfb8a28"
},
{
"file": "public/images/investment-context/educacao-formacao-480.webp",
"width": 480,
"height": 270,
"bytes": 27384,
"sha256": "d3b743fbba7a8cb40e45999ee8c345cbfc0332cf85f5c5c2d6a5cf1240a395e4"
},
{
"file": "public/images/investment-context/educacao-formacao-fallback.webp",
"width": 240,
"height": 135,
"bytes": 7156,
"sha256": "0b2a12898043c57cf4354b54ebcba8adec8d41b3886bc574584ccc12af7b1e4c"
}
]
},
{
"key": "documentos-formularios",
"prompt": "Use case: photorealistic-natural. Asset type: an individual navigation card photograph for a professional investment portal. Generate ONE clean, realistic editorial photograph in horizontal 16:9 composition. Natural daylight, realistic restrained colours, excellent photographic detail, balanced uncluttered framing, one clear subject readable at a small thumbnail size. Contemporary setting plausible in Mozambique in southern Africa. This is a generic illustrative scene, NOT a depiction or claim about any named real facility, project, landmark or institution. No text, lettering, titles, captions, logos, brands, watermarks, flags, official emblems, maps, diagrams, graphical overlays, UI elements, collages, artificial colour filters, futuristic architecture or advertising poster treatment. Realistic people, hands, equipment and perspective; dignified candid activity instead of posed stock photography. Subject: a close-medium editorial photograph of a tidy modern administrative office desk where a Black southern African professional in a plain light blue shirt is naturally reviewing organised business documentation. Frame hands, desk and partial torso, no prominent portrait. Neat neutral folders, a few sheets with only faint out-of-focus non-readable printing, a pen and an unbranded laptop angled away with no visible UI. Soft window light, white and pale neutral surfaces with subtle blue accents. Absolutely no readable personal data, invented official seals or highlighted fake text; realistic fingers and documents, calm minimal composition.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-f1c8e22e-6885-4578-ac7d-02692c5cc071.png",
"original": "outputs/investment-context-20261023/originals/documentos-formularios.png",
"originalSha256": "cfbd38a9cc9b9acf35f38220f5bd9c1ab1feafe411bc1d4bbdb3658de557e052",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-context/documentos-formularios.webp",
"width": 960,
"height": 540,
"bytes": 43002,
"sha256": "70ddea3256e6a8d981b1fae5ee7b4de6c910d757137b79a59306c268c278402f"
},
{
"file": "public/images/investment-context/documentos-formularios-480.webp",
"width": 480,
"height": 270,
"bytes": 17996,
"sha256": "436865c948acbb7b6e9e482bef8f5bd626c6960f2f155608e40dfcd0e76b84cb"
},
{
"file": "public/images/investment-context/documentos-formularios-fallback.webp",
"width": 240,
"height": 135,
"bytes": 4958,
"sha256": "fad6a6ab825a82ec2541d2e0c6de9d85486e4bbca159b912f87bec9cc0aeeba5"
}
]
}
],
"primaryImagesBytesTotal": 390320,
"responsive480ImagesBytesTotal": 143146,
"implementation": {
"gridColumns": [
1,
2,
4
],
"aspectRatio": "16:9",
"responsiveImages": true,
"lazyLoading": true,
"altLanguage": "pt",
"fallback": "Derivado pequeno da própria imagem; se também falhar, estado acessível Imagem indisponível, com dimensão reservada e link mantido.",
"globalCSSChanged": false,
"businessLogicChanged": false,
"databaseChanged": false,
"heroChanged": false
},
"visualReview": "Cinco composições individuais distintas, cores naturais e luz editorial; sem títulos/colagens ou mapas. A composição de Corredores foi revista para remover o camião com marca. Capturas em computador e telemóvel inspeccionadas.",
"verification": {
"browser": {
"results": [
{
"width": 320,
"dpr": 1,
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 320,
"height": 180
}
],
"status": "passed"
},
{
"width": 390,
"dpr": 2,
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios.webp",
"width": 389,
"height": 219
}
],
"status": "passed"
},
{
"width": 768,
"dpr": 1,
"columns": 2,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 384,
"height": 216
}
],
"status": "passed"
},
{
"width": 1024,
"dpr": 1,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 256,
"height": 144
}
],
"status": "passed"
},
{
"width": 1440,
"dpr": 2,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios.webp",
"width": 266,
"height": 149
}
],
"status": "passed"
},
{
"width": 1920,
"dpr": 1,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 266,
"height": 149
}
],
"status": "passed"
},
{
"fail": "primary",
"status": "passed"
},
{
"fail": "all",
"status": "passed"
}
],
"errors": [],
"navigation": [
"/clusters",
"/corredores",
"/projectos-ancora",
"/educacao",
"/documentos"
],
"databaseAccess": false
},
"script": "tools/portal-context-cards-qa.mjs",
"screenshots": [
"outputs/investment-context-20261023/cards-1024-dpr1.png",
"outputs/investment-context-20261023/cards-1440-dpr2.png",
"outputs/investment-context-20261023/cards-1920-dpr1.png",
"outputs/investment-context-20261023/cards-320-dpr1.png",
"outputs/investment-context-20261023/cards-390-dpr2.png",
"outputs/investment-context-20261023/cards-768-dpr1.png",
"outputs/investment-context-20261023/fallback-all.png",
"outputs/investment-context-20261023/fallback-primary.png"
],
"types": {
"command": "npm run types:check",
"exitCode": 0
},
"lint": {
"files": [
"resources/js/components/investment-context-cards.tsx",
"resources/js/pages/PortalInvestidor.tsx",
"tools/portal-context-cards-qa.mjs"
],
"exitCode": 0
},
"build": {
"command": "npm run build",
"exitCode": 0,
"pageAsset": "assets/PortalInvestidor-fh5VZanx.js",
"log": "outputs/investment-context-20261023/build-local.log"
}
},
"scope": "Aplicado no código e pacote locais. API e navegação simuladas na verificação visual; sem dados activos ou publicação externa.",
"matrixReferences": [
"MASTER-efd550fd-0104",
"MASTER-55050f60-0001"
],
"acceptanceLimit": "Prova restrita à apresentação e navegação dos cinco cartões; não encerra critérios funcionais mais amplos da matriz.",
"layoutRevision": {
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: título a vermelho e menos espaço em branco dentro dos cartões.",
"changes": "Título no vermelho #ed1c24; removidas alturas mínimas de título e descrição; preenchimento 20→16 px, intervalo 8→6 px e entrelinhas 28/24→24/20 px. Mantidos imagens, conteúdos, links e alinhamento por linha da grelha.",
"browser": {
"results": [
{
"width": 320,
"dpr": 1,
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 320,
"height": 180
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 320,
"height": 180
}
],
"status": "passed"
},
{
"width": 390,
"dpr": 2,
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao.webp",
"width": 389,
"height": 219
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios.webp",
"width": 389,
"height": 219
}
],
"status": "passed"
},
{
"width": 768,
"dpr": 1,
"columns": 2,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 384,
"height": 216
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 384,
"height": 216
}
],
"status": "passed"
},
{
"width": 1024,
"dpr": 1,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 256,
"height": 144
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 256,
"height": 144
}
],
"status": "passed"
},
{
"width": 1440,
"dpr": 2,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios.webp",
"width": 266,
"height": 149
}
],
"status": "passed"
},
{
"width": 1920,
"dpr": 1,
"columns": 4,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-context/clusters-agroindustria-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/corredores-logisticos-v2-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/projectos-ancora-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/educacao-formacao-480.webp",
"width": 266,
"height": 149
},
{
"src": "http://127.0.0.1:5174/images/investment-context/documentos-formularios-480.webp",
"width": 266,
"height": 149
}
],
"status": "passed"
},
{
"fail": "primary",
"status": "passed"
},
{
"fail": "all",
"status": "passed"
}
],
"errors": [],
"navigation": [
"/clusters",
"/corredores",
"/projectos-ancora",
"/educacao",
"/documentos"
],
"databaseAccess": false
},
"lintExitCode": 0,
"buildExitCode": 0,
"pageAsset": "assets/PortalInvestidor-CYCMhSzW.js",
"screenshots": [
"outputs/investment-context-compact-20261023/cards-1024-dpr1.png",
"outputs/investment-context-compact-20261023/cards-1440-dpr2.png",
"outputs/investment-context-compact-20261023/cards-1920-dpr1.png",
"outputs/investment-context-compact-20261023/cards-320-dpr1.png",
"outputs/investment-context-compact-20261023/cards-390-dpr2.png",
"outputs/investment-context-compact-20261023/cards-768-dpr1.png"
],
"databaseChanged": false
}
}
@@ -0,0 +1,355 @@
{
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: adaptar hero, imagens e pesquisa da referência, preservando a informação e os comportamentos equivalentes do V2.",
"sourceProject": "D:/Projects/Tempo_Investidor/investidor",
"targetProject": "D:/Projects/Tempo_Investidor/Investidor-V2",
"planAndAnalysis": "docs/investmoz/public-portal-sections.md#adequação-do-hero--23102026",
"implementation": [
"resources/js/components/portal-hero.tsx",
"resources/js/pages/PortalInvestidor.tsx"
],
"assets": [
{
"source": "D:\\Projects\\Tempo_Investidor\\investidor\\public\\images\\hero\\hero-1.png",
"original": "public\\images\\hero\\hero-1.png",
"sha256": "3c9246169025b9b1b4d1d10fb51c1f644123984bde56c6c2d9bf869d851024fc",
"bytes": 2315768,
"webpBytes": 94012,
"mobileBytes": 38804
},
{
"source": "D:\\Projects\\Tempo_Investidor\\investidor\\public\\images\\hero\\hero-3.jpg",
"original": "public\\images\\hero\\hero-3.jpg",
"sha256": "91377213b6286aca7ee4af90860a7dc7a75fa08a165ef7b3192081db43f92dff",
"bytes": 9875137,
"webpBytes": 140342,
"mobileBytes": 32998
}
],
"desktopBytesTotal": 234354,
"mobileBytesTotal": 71802,
"originalBytesTotal": 12190905,
"verification": {
"browser": {
"results": [
{
"width": 320,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 390,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 768,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1920,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "no-preference",
"status": "passed"
}
],
"errors": [],
"requests": [
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=",
"/oportunidades",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique"
],
"databaseAccess": false
},
"browserScript": "tools/portal-hero-qa.mjs",
"screenshots": [
"outputs/portal-hero-20261023/after-1440-no-preference.png",
"outputs/portal-hero-20261023/after-1440-reduce.png",
"outputs/portal-hero-20261023/after-1440-second-image.png",
"outputs/portal-hero-20261023/after-1920-reduce.png",
"outputs/portal-hero-20261023/after-320-reduce.png",
"outputs/portal-hero-20261023/after-390-reduce.png",
"outputs/portal-hero-20261023/after-768-reduce.png",
"outputs/portal-hero-20261023/before-1440-reduce.png",
"outputs/portal-hero-20261023/before-390-reduce.png"
],
"additionalCases": [
"pesquisa por Enter e botão",
"ordem do teclado: campo → botão",
"query acentuada e pontuação preservadas",
"remoção de espaços exteriores",
"pesquisa vazia abre catálogo",
"CTA abre oportunidades",
"API indisponível mantém indicadores indeterminados",
"contagens zero preservadas",
"duas imagens carregadas",
"selecção manual",
"pausa e retoma explícitas",
"foco pausa rotação",
"rotação automática após perda de foco",
"movimento reduzido",
"entrada documental e cabeçalho preservados"
],
"existingFrontendTests": {
"command": "node --test tests/frontend/portal-api.test.mjs tests/frontend/portal-navigation.test.mjs",
"passed": 20
},
"typecheck": {
"command": "npm run types:check",
"exitCode": 0
},
"lint": {
"files": [
"resources/js/components/portal-hero.tsx",
"resources/js/pages/PortalInvestidor.tsx",
"tools/portal-hero-qa.mjs"
],
"exitCode": 0
},
"qaBuild": {
"command": "INVESTMOZ_QA_BUILD=1 npm run build",
"exitCode": 0
},
"localBuild": {
"command": "npm run build",
"exitCode": 0,
"pageAsset": "assets/PortalInvestidor-MsUeKoJQ.js"
}
},
"matrix": {
"file": "docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv",
"referencesAdded": [
"MASTER-9dee08d0-0016",
"MASTER-efd550fd-0104",
"MASTER-55050f60-0001"
],
"rowCount": 3422,
"criteriaAndStatesPreserved": true
},
"scope": {
"appliedToLocalCodeAndBuild": true,
"activeDatabaseChanged": false,
"migrationsRun": false,
"externalDeploymentPerformed": false,
"backendSearchReimplemented": false
},
"limits": "Verificação visual com dados sintéticos; pesquisa continua limitada ao catálogo de oportunidades. Os critérios mais amplos da matriz permanecem no estado anterior.",
"latestRevision": {
"id": "hero-no-controls-20261023",
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: remover do hero as duas bolinhas e o botão de pausa das imagens.",
"implementation": "Removidos grupo de controlos, ícones Pause/Play e estado de pausa manual. Preservadas troca automática, escrita dinâmica, pesquisa e preferência de movimento reduzido.",
"browser": {
"results": [
{
"width": 320,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 390,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 768,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1920,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 390,
"reducedMotion": "no-preference",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "no-preference",
"status": "passed"
}
],
"errors": [],
"requests": [
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=",
"/oportunidades",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=",
"/oportunidades",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique"
],
"databaseAccess": false
},
"screenshots": [
"outputs/portal-hero-no-controls-20261023/after-1440-no-preference.png",
"outputs/portal-hero-no-controls-20261023/after-1440-reduce.png",
"outputs/portal-hero-no-controls-20261023/after-1920-reduce.png",
"outputs/portal-hero-no-controls-20261023/after-320-reduce.png",
"outputs/portal-hero-no-controls-20261023/after-390-no-preference.png",
"outputs/portal-hero-no-controls-20261023/after-390-reduce.png",
"outputs/portal-hero-no-controls-20261023/after-768-reduce.png",
"outputs/portal-hero-no-controls-20261023/second-image-1440.png",
"outputs/portal-hero-no-controls-20261023/second-image-390.png",
"outputs/portal-hero-no-controls-20261023/typed-1440.png",
"outputs/portal-hero-no-controls-20261023/typed-390.png"
],
"checks": {
"lintExitCode": 0,
"buildExitCode": 0,
"pageAsset": "assets/PortalInvestidor-T0B6aoV_.js"
},
"scope": {
"appliedLocally": true,
"databaseAccess": false,
"externalDeployment": false
}
},
"revisionHistory": [
{
"id": "hero-typing-20261023",
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: título e frase dinâmicos como na referência; remover Termos de uso do hero.",
"plan": [
"Analisar a sequência de escrita da referência.",
"Animar o título e depois a frase, mantendo os textos do V2 e reservando a dimensão final.",
"Reiniciar a escrita na troca de imagem e integrar pausa/retoma e preferência de movimento reduzido.",
"Remover o link e o ícone jurídico do hero.",
"Demonstrar comportamento em computador e telemóvel e compilar o pacote local."
],
"files": [
"resources/js/components/portal-hero.tsx",
"resources/css/app.css",
"tools/portal-hero-qa.mjs"
],
"browser": {
"results": [
{
"width": 320,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 390,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 768,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 1920,
"reducedMotion": "reduce",
"status": "passed"
},
{
"width": 390,
"reducedMotion": "no-preference",
"status": "passed"
},
{
"width": 1440,
"reducedMotion": "no-preference",
"status": "passed"
}
],
"errors": [],
"requests": [
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=",
"/oportunidades",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique",
"/oportunidades?q=",
"/oportunidades",
"/oportunidades?q=energia%20%26%20Nampula%20%2F%20Mo%C3%A7ambique"
],
"databaseAccess": false
},
"screenshots": [
"outputs/portal-hero-typing-20261023/after-1440-no-preference.png",
"outputs/portal-hero-typing-20261023/after-1440-reduce.png",
"outputs/portal-hero-typing-20261023/after-1440-second-image.png",
"outputs/portal-hero-typing-20261023/after-1920-reduce.png",
"outputs/portal-hero-typing-20261023/after-320-reduce.png",
"outputs/portal-hero-typing-20261023/after-390-no-preference.png",
"outputs/portal-hero-typing-20261023/after-390-reduce.png",
"outputs/portal-hero-typing-20261023/after-768-reduce.png",
"outputs/portal-hero-typing-20261023/typed-1440.png",
"outputs/portal-hero-typing-20261023/typed-390.png",
"outputs/portal-hero-typing-20261023/typing-1440.png",
"outputs/portal-hero-typing-20261023/typing-390.png"
],
"demonstrated": [
"escrita progressiva",
"título antes da frase",
"texto completo no modo de movimento reduzido",
"nome acessível completo durante a escrita",
"pesquisa sem deslocamento durante a escrita",
"reinício na selecção manual e automática de imagem",
"pausa e retoma da escrita",
"cursor com pausa",
"Termos de uso ausente do hero",
"pesquisa, teclado, CTA, API indisponível e contagens zero preservados"
],
"checks": {
"types": {
"command": "npm run types:check",
"exitCode": 0
},
"lint": {
"command": "vp lint resources/js/components/portal-hero.tsx tools/portal-hero-qa.mjs",
"exitCode": 0
},
"build": {
"command": "npm run build",
"exitCode": 0,
"pageAsset": "assets/PortalInvestidor-BbVHeTeI.js",
"log": "outputs/portal-hero-typing-20261023/build-local.log"
}
},
"scope": {
"appliedLocally": true,
"databaseAccess": false,
"externalDeployment": false
}
}
]
}
+88
View File
@@ -48,3 +48,91 @@ Edge headless: 11 páginas públicas/autenticação verificadas a 390×844, com
Página inicial também verificada a 1440×1000. Cenário fiscal exercitado no navegador: base 1.000 × taxa 10% × (1 − redução 50%) = 50. Resultados em `public-portal-browser-validation.json`.
Antes da migration local foi criado e restaurado o backup de 74 tabelas em `storage/app/private/portal-services-backup-20260927-090641/`. O backup completo anterior permanece em `C:/laragon/backups/portal-investidor-20260927-101224/` e representa o estado anterior a esta entrega.
## Adequação do hero — 23/10/2026
Origem: pedido expresso da Tempo nesta sessão para aproveitar o hero, as imagens e a barra de pesquisa de `D:/Projects/Tempo_Investidor/investidor`, usando a informação existente no V2. Aplicam-se as orientações permanentes do `AGENTS.md`, incluindo a distinção entre decisão da Tempo e escolha técnica, a preservação de dados e a separação de QA e activo.
Análise prévia: a página de entrada real do V2 é `PortalInvestidor.tsx`, servida por `PortalServicesController::home`. A referência é `domains/investor-portal/components/homepage/homepage-hero.tsx`, montada em `InstitutionalHomepage`. A referência usa Inertia 2, Framer Motion, tradução e navegação diferentes; o V2 usa Inertia 3 e pesquisa de oportunidades. Copiar essas dependências e `/pesquisa` ou `/aviso-legal` directamente criaria incompatibilidades e destinos inexistentes.
Plano executado:
1. Registar a apresentação anterior em computador e telemóvel, com os componentes reais e dados sintéticos.
2. Copiar os dois originais efectivamente usados pela referência (`hero-1.png` e `hero-3.jpg`), conferir SHA-256 e gerar derivados WebP para computador e telemóvel. `hero-2.png` não faz parte da rotação da referência.
3. Extrair `components/portal-hero.tsx` e aplicar fotografias em rotação, texto centrado e pesquisa branca com botão vermelho. Preservar os textos do V2, contagens da API, sectores, documentos, apoio, cabeçalho e rodapé.
4. Manter a pesquisa de oportunidades em `/oportunidades?q=`, incluindo pesquisa vazia e caracteres acentuados. Conservar “Consultar oportunidades” e “Planear finanças”. A primeira iteração acrescentou o acesso jurídico `/termos-de-uso` ao hero; foi removido na revisão expressamente pedida pela Tempo abaixo.
5. Verificar apresentação, teclado, imagens, rotação, pausa, movimento reduzido, falha da API, contagens zero, TypeScript, lint e compilação. Compilar primeiro o pacote QA e depois os assets locais em `public/build`.
Escolhas técnicas desta adaptação: React e transições CSS existentes, sem novas dependências; rotação de oito segundos, pausa por controlo explícito, foco, ponteiro ou separador oculto; apresentação estática quando o utilizador pede movimento reduzido. A primeira iteração apresentou o texto estático; a revisão abaixo introduz a escrita dinâmica pedida pela Tempo. O campo indica pesquisa de oportunidades e conserva exemplos que o catálogo suporta; esta alteração não implementa uma pesquisa global de legislação/licenciamento.
Evidência reproduzível: `tools/portal-hero-qa.mjs`, com Vite local e Playwright configurável por `HERO_QA_PLAYWRIGHT`/`HERO_QA_CHROMIUM`. Fixtures e capturas em `outputs/portal-hero-20261023/`; síntese persistente em `public-portal-hero-validation.json`. Os testes de interface interceptam a API e a navegação Inertia, sem acesso a Laravel, base de dados ou serviços externos. A compilação local aplica os assets desta pasta; não representa publicação noutro servidor.
Referências na matriz existente: `MASTER-efd550fd-0104` (composição da página), `MASTER-9dee08d0-0016` (contexto da pesquisa) e `MASTER-55050f60-0001` (entrada documental preservada). Esta prova cobre a adaptação visual e os percursos exercitados; não encerra os critérios funcionais mais amplos dessas linhas.
### Revisão: escrita dinâmica e remoção do acesso jurídico no hero
Decisão expressa da Tempo na continuação da sessão de 23/10/2026: animar “INVISTA EM MOÇAMBIQUE” e “Transforme informação em decisões e ideias em negócios reais.” como na página de referência, e remover “Termos de uso” do hero. A anterior apresentação estática e a inclusão desse link eram escolhas de implementação, agora substituídas pelo pedido do proprietário.
Análise e plano executado: reproduzir a sequência da referência (espera inicial de 250 ms, título a 50 ms por carácter, intervalo de 150 ms e frase a 28 ms por carácter); reiniciar ao trocar de imagem; acrescentar o cursor intermitente; reservar a dimensão final de ambas as linhas para manter a pesquisa imóvel; remover o link e o ícone jurídico do hero; verificar em computador e telemóvel e compilar o pacote local.
Implementação em `portal-hero.tsx`, com React existente e CSS do cursor em `app.css`, sem dependências novas. A pausa explícita suspende também a escrita, retomando do mesmo ponto. Quando o separador fica oculto a escrita pára; a preferência de movimento reduzido apresenta os dois textos completos. Leitores de ecrã recebem o texto completo uma única vez, independentemente do número de caracteres visíveis. Os temporizadores são limpos ao mudar de imagem ou desmontar o componente.
O script `tools/portal-hero-qa.mjs` demonstra a escrita progressiva, a ordem título→frase, o reinício manual/automático, a pausa/retoma, a posição estável da pesquisa, o modo sem movimento e a ausência de “Termos de uso” no hero. As capturas e resultados desta revisão ficam em `outputs/portal-hero-typing-20261023/`, preservando a evidência anterior. Síntese e compilação final registadas na revisão de `public-portal-hero-validation.json`; referência acrescentada à linha existente `MASTER-efd550fd-0104`, sem encerrar o seu critério mais amplo.
### Revisão: remoção dos controlos visíveis das imagens
Pedido expresso da Tempo na continuação de 23/10/2026: remover do hero o grupo com o botão de pausa e as duas bolinhas de selecção de imagem. Removidos o grupo, os ícones e o estado de pausa manual. A troca automática de imagens e a escrita dinâmica permanecem; conservam-se a pausa da rotação por foco/ponteiro, a suspensão em separador oculto e a preferência de movimento reduzido. Esta decisão substitui os controlos visíveis introduzidos como escolha de implementação nas revisões anteriores.
O script existente de interface foi adaptado para demonstrar a ausência dos controlos e a continuação da rotação automática, escrita e pesquisa, com capturas em `outputs/portal-hero-no-controls-20261023/`. Evidência e pacote local registados em `public-portal-hero-validation.json`, mantendo o histórico das revisões e os estados dos requisitos da matriz.
## Fotografias nas etapas de Como Investir — 23/10/2026
Origem: pedido expresso da Tempo para analisar e ilustrar exclusivamente os cartões “1. Explorar”, “2. Preparar” e “3. Acompanhar”. Aplicam-se as orientações permanentes de `AGENTS.md` de 12/10 e 22/10/2026; componentes e optimização de recursos são escolhas técnicas, sem novas regras operacionais.
Análise e plano: os cartões existentes são âncoras estáticas na home React/Inertia, numa grelha de três colunas a partir de 768 px. Explorar liga a `/oportunidades` e representa a identificação de sector, território e oportunidade; Preparar liga a `/como-investir` e representa percurso/documentação; Acompanhar liga a `/balcao-virtual` e representa envio/consulta de pedido e protocolo. Os recursos locais existentes ilustram outras secções; preparar três fotografias distintas para evitar repetição. Gerar cenas editoriais plausíveis com `imagegen`, rever composição, guardar originais e versões WebP locais, integrar imagens 16:9 com dimensões reservadas e carregamento diferido, manter textos/destinos/título vermelho, verificar comportamento responsivo, navegação e falhas de imagem, compilar. Âmbito exclusivamente visual, sem alterações em dados, autenticação, apoio ou rodapé. Referência documental na linha existente `MASTER-efd550fd-0104`, sem criar outra matriz nem encerrar o critério mais amplo.
Implementação: `components/investment-steps.tsx` reúne os três cartões, preservando títulos, descrições e âncoras. Fotografias individuais geradas com a ferramenta integrada `image_gen`, sem local ou projecto real atribuído: avaliação de oportunidade num parque empresarial genérico, preparação documental numa reunião e consulta de pedido no computador. Originais em `outputs/investment-steps-20261023/originals/`; recursos locais em `public/images/investment-steps/` com WebP 960×540, 480×270 e alternativa própria 240×135. Os cartões usam `srcset`, `sizes`, `loading="lazy"`, dimensões reservadas, corte 16:9, alt em português, foco visível e texto compacto com 16 px de preenchimento. Se também falhar a alternativa pequena, o cartão mantém a área reservada, descrição acessível e destino utilizável.
Verificação desta secção: componentes reais com API sintética e sem base de dados, seis larguras de 320 a 1920 px, duas densidades de ecrã, três imagens distintas, texto/destinos conservados, navegação por teclado, ausência de transbordo e deslocamento no carregamento, falhas dos recursos principais e de todos os recursos. Oito cenários sem erros JavaScript. Fotografias, prompts, hashes, capturas, relatório de browser e compilação documentados em `public-portal-steps-images.json` e `outputs/investment-steps-20261023/`. Ajuste restrito a esta secção; apoio, acesso à gestão e rodapé mantidos.
## Fotografias nos cartões de contexto do investimento — 23/10/2026
Origem: pedido expresso da Tempo para aplicar o anexo “Melhorar as imagens e a identidade visual do Portal do Investidor de Moçambique” exclusivamente à secção “Encontre o contexto do seu investimento”. O anexo define estética fotográfica editorial, imagens individuais contextualizadas, recursos locais, acessibilidade, desempenho e preservação dos cinco destinos e conteúdos. Aplicam-se as orientações permanentes de `AGENTS.md` de 12/10 e 22/10/2026; os pormenores de implementação abaixo são escolhas técnicas.
Análise prévia: Laravel/Inertia 3 e React, com Tailwind existente; os cinco cartões estavam embutidos em `pages/PortalInvestidor.tsx`. `EducationalArticleCard` destina-se a artigos com acções e metadados diferentes, pelo que não foi alterado. A secção foi extraída para `components/investment-context-cards.tsx`, mantendo o título, descrições, âncoras e grelha de uma/duas/quatro colunas. Não foram alteradas as páginas de destino, dados, APIs ou estilos globais.
Foram geradas cinco imagens distintas com a ferramenta integrada `image_gen`, segundo a skill `imagegen`: agro-indústria, terminal logístico, acompanhamento de instalação solar, formação técnica e análise documental. São imagens fotográficas ilustrativas geradas, sem localização ou instituição real atribuída, e não fotografias documentais de projectos cadastrados. A imagem do terminal foi revista para remover o camião com marca visível. Não foram usadas fotografias externas nem URLs de serviços de imagens. Originais seleccionados, prompts e hashes estão registados no manifesto `public-portal-context-images.json`; os originais foram preservados dentro do workspace.
Recursos finais em `public/images/investment-context/`: `clusters-agroindustria`, `corredores-logisticos-v2`, `projectos-ancora`, `educacao-formacao` e `documentos-formularios`, em WebP 960×540, com variantes 480×270 e alternativas 240×135. As imagens mantêm 16:9, `object-cover`, textos alternativos em português, dimensões reservadas, `srcset`, `sizes`, `loading="lazy"` e descodificação assíncrona. Cada cartão conserva o seu título e descrição; o foco usa o azul e os tons neutros pedidos no anexo.
Se um recurso principal falhar, o cartão usa a sua própria variante pequena, evitando repetir a fotografia de outra secção. Se também essa falhar, apresenta “Imagem indisponível” no mesmo espaço reservado, com descrição acessível e link operacional. Este é apenas um estado de erro; os cinco cartões usam imagens fotográficas na apresentação normal.
Verificação reproduzível: `tools/portal-context-cards-qa.mjs`, com o portal e cabeçalho reais, API sintética e acesso exclusivo aos recursos locais. Exercita seis larguras de ecrã, ecrãs de alta densidade, os cinco destinos por teclado, imagens carregadas e distintas, alinhamento, dimensões, ausência de deslocamento no carregamento e dois cenários de falha. Capturas e resultados em `outputs/investment-context-20261023/`; síntese, fontes/prompts e compilação em `public-portal-context-images.json`. Referências acrescentadas às linhas existentes `MASTER-efd550fd-0104` e `MASTER-55050f60-0001`, sem encerrar os respectivos critérios mais amplos.
Revisão expressa da Tempo de 23/10/2026: título da secção no vermelho da identidade existente (`#ed1c24`) e cartões mais compactos. Removidas as alturas mínimas de 56 e 72 px do título/descrição; reduzidos o preenchimento de 20 para 16 px, o intervalo de 8 para 6 px e as entrelinhas. As alturas passam a acompanhar o conteúdo, com alinhamento por linha da grelha, conservando imagens, textos e destinos. A reserva das dimensões das imagens mantém-se. Evidência desta revisão em `outputs/investment-context-compact-20261023/` e no campo `layoutRevision` do manifesto existente.
## Sectores da home e catálogo completo — 23/10/2026
Origem: pedido expresso da Tempo para adaptar a estrutura de “Áreas de Investimento” do projecto `D:/Projects/Tempo_Investidor/tempo-dashboard`, incluindo cartões, botão para mais sectores e respectiva página, e uniformizar a vermelho os títulos das secções da home. Aplicadas as orientações permanentes `AGENTS.md` de 12/10 e 22/10/2026: as decisões de produto são da Tempo; as escolhas técnicas abaixo não criam requisitos organizacionais.
Análise prévia: a referência usa `components/investor-portal/homepage/homepage-sectors.tsx` e `pages/investor-portal/sectors/index.tsx`. Mostra cinco cartões com fotografia e título sobreposto, resumo, “Saiba mais” e ligação central arredondada para o catálogo. O V2 já dispunha de `/sectores`, fichas `/sectores/{slug}`, especialização Fintech e dados de `SectorOrganization`. Foram reutilizados esses contratos e percursos, sem importar Framer Motion, traduções ou rotas exclusivas da referência.
Implementação: `components/public-sector-cards.tsx` partilha os cartões entre a home e o catálogo. A home mostra os primeiros cinco sectores, na ordem recebida da API, com “Ler mais” para a ficha existente e “Ver mais sectores” para `/sectores`. A página existente apresenta todos os sectores publicados, na mesma estrutura visual, e “Voltar ao início”. Mantêm-se nomes, descrições, contagens, valores zero, especializações e URLs canónicos recebidos. Descrições ausentes não são preenchidas com dados da referência. Fintech permanece ligado à ficha própria, sem âncoras HTML aninhadas.
Foram inventariados os onze JPG disponíveis em `storage/app/public/investor-portal/sectors` na referência, copiados os originais para evidência e preparados derivados locais WebP 960×540/480×270 em `public/images/sectors/`. O mapeamento visual por slug é de apresentação e não altera a taxonomia. Para Imobiliário e sectores sem imagem específica usa-se a vista empresarial genérica disponível na referência; para Bens de Consumo e Franquias usa-se a imagem de actividade industrial. A variante genérica também serve como alternativa em caso de erro; se ambas falharem, o título e as ligações continuam visíveis num fundo neutro. Não se atribui aos ficheiros uma origem oficial, licença externa ou localização documental não comprovada.
Os seis títulos de secção da home — contexto do investimento, sectores, Como Investir, oportunidades em destaque, documentos essenciais e apoio — usam `HOME_SECTION_HEADING` em `lib/portal-presentation.ts`: vermelho `#ed1c24`, 24 px, entrelinha de 32 px e peso 700. O cartão de Apoio passou a superfície clara para manter contraste com o título vermelho. O título principal animado do hero mantém a sua hierarquia própria. `PORTAL_MORE_LINK` centraliza o botão arredondado, contorno vermelho e estado de foco, seguindo a referência.
Verificação: `tools/portal-home-sectors-qa.mjs` carrega os componentes reais com dez sectores sintéticos, descrições nulas e especialização Fintech, sem base de dados. Exercita seis larguras, prévia de cinco/cartálogo de dez, estilos dos seis títulos, percurso por teclado, dez fichas, Fintech, regresso à home, catálogo vazio e dois cenários de indisponibilidade de imagens. Capturas, inventário, hashes e resultados em `outputs/home-sectors-20261023/`; resumo persistente em `public-portal-sectors-validation.json`. Referências na matriz existente: `MASTER-efd550fd-0104` e `MASTER-9f5719c8-0077`. Esta adaptação não encerra critérios mais amplos nem altera dados, permissões, regras operacionais ou publicação noutro servidor.
Pedido expresso da Tempo, 23/10/2026 — botão “Contactar Apoio ao Investidor”: em `layouts/portal-navigation.tsx`, a faixa de largura total foi substituída por um botão centrado, com largura ajustada ao texto, altura mínima de 44 px, preenchimento reduzido, sombra discreta e vermelho `#ed1c24`, conservando `/apoio` e o foco visível. Verificado a 320, 390 e 1440 px: cerca de 223×44 px, sem transbordo ou erros JavaScript. Evidência em `outputs/support-button-20261023/qa-results.json` e capturas; compilação local no mesmo directório. Ajuste de apresentação por decisão do proprietário, sem nova regra operacional nem alteração de dados.
Revisão anterior de 23/10/2026, superada pela correcção de âmbito abaixo: o Codex interpretou o pedido de abreviação como aplicável à zona inferior inteira e alterou indevidamente o botão de apoio e o rodapé partilhado. Essa interpretação não foi uma decisão da Tempo. A revisão removeu o bloco interno, abreviou o botão para “Apoio” e recolheu contactos/ligações em “Informações” num rodapé claro; estas alterações fora do bloco indicado foram revertidas após a clarificação expressa do proprietário. O registo desta revisão é histórico e não descreve a apresentação actual.
Evidência histórica da revisão superada: `outputs/footer-compact-20261023/qa-results.json`, capturas e `check.mjs`. Não constitui aceitação do âmbito pelo proprietário.
Correcção expressa da Tempo, 23/10/2026: o pedido abrange exclusivamente o bloco “INVESTE Moçambique / Portal do Investidor — conheça as oportunidades… / Acesso à gestão”. Em `pages/PortalInvestidor.tsx`, esse bloco fica abreviado num ícone de acesso à gestão, com nome acessível e descrição “Acesso à gestão”, destino `/acesso-gestao`, área de interacção de 44 px e fundo branco, sem o título e parágrafo anteriores. O botão de apoio foi restaurado exactamente à apresentação anterior à abreviação: “Contactar Apoio ao Investidor”, compacto, vermelho e sem ícone. `components/tempo-footer.tsx` e os estilos `.tempo-footer` foram integralmente restaurados ao estado anterior, incluindo contactos e ligações visíveis e o fundo original do rodapé geral. Não se altera autenticação nem dados. Esta correcção substitui a interpretação indevida acima e mantém as restantes alterações previamente pedidas.
Evidência da correcção: `outputs/footer-scope-correction-20261023/check.mjs`, `qa-results.json`, capturas e `build-local.log`; componentes reais com API sintética a 320, 390 e 1440 px, ícone de gestão focável, bloco específico claro sem parágrafo, botão de apoio completo/vermelho, rodapé geral restaurado, contactos e ligações legais visíveis, sem transbordo ou erros JavaScript. Lint dos componentes alterados e compilação local. Referência na linha existente `MASTER-efd550fd-0104`, sem encerramento do critério amplo nem alteração dos seus estados.
Continuação expressa da Tempo, 23/10/2026: acrescentado o título visível “Acesso à gestão” ao lado do ícone nesse mesmo bloco, para tornar o destino compreensível. O acesso mantém-se compacto, vermelho e com fundo claro, conservando `/acesso-gestao`. Ajuste restrito a essa ligação; apoio e rodapé geral conservam a apresentação restaurada. Referência: `MASTER-efd550fd-0104` e a evidência da revisão anterior acima. Verificado a 320, 390 e 1440 px, sem transbordo ou erros JavaScript; lint e compilação aprovados. Evidência em `outputs/management-label-20261023/qa-results.json`, capturas e `build-local.log`. No pedido seguinte, a Tempo determinou o alinhamento desse acesso à esquerda; aplicado `justify-start` apenas no seu contentor.
@@ -0,0 +1,748 @@
{
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: adaptar Áreas de Investimento do tempo-dashboard aos sectores da home e ao catálogo completo, copiar a estrutura dos botões e uniformizar a vermelho os títulos de secção da home.",
"reference": {
"project": "D:/Projects/Tempo_Investidor/tempo-dashboard",
"files": [
"resources/js/components/investor-portal/homepage/homepage-sectors.tsx",
"resources/js/pages/investor-portal/sectors/index.tsx"
],
"structure": "Cinco cartões com fotografia, título sobreposto, resumo e acção de leitura; botão central arredondado/contorno vermelho para o catálogo."
},
"analysisAndPlan": "docs/investmoz/public-portal-sections.md#sectores-da-home-e-catálogo-completo--23102026",
"filesChanged": [
"resources/js/components/public-sector-cards.tsx",
"resources/js/lib/portal-presentation.ts",
"resources/js/components/investment-context-cards.tsx",
"resources/js/lib/portal-api.ts",
"resources/js/pages/PortalInvestidor.tsx",
"resources/js/pages/portal/services.tsx",
"tools/portal-home-sectors-qa.mjs",
"docs/investmoz/public-portal-sections.md",
"docs/investmoz/v2/auditoria-portal/matriz-requisitos.csv"
],
"behaviour": {
"homePreview": 5,
"previewOrder": "Ordem recebida da API, sem novos filtros de publicação.",
"readMore": "Ler mais, para a URL recebida ou ficha existente /sectores/{slug}.",
"moreSectors": "Ver mais sectores, botão arredondado para /sectores.",
"catalogue": "Todos os sectores publicados devolvidos pelo cadastro existente; Voltar ao início para /.",
"specializations": "Fintech conservado como ligação própria; sem âncoras aninhadas.",
"countsAndDescriptions": "Preservados dados recebidos, incluindo zero e descrições ausentes; não importados textos ou registos do outro projecto.",
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"supportCard": "Superfície clara para contraste com o título vermelho."
},
"assets": [
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\agronegocio.jpg",
"sourceBytes": 444057,
"original": "outputs/home-sectors-20261023/originals/agronegocio.jpg",
"sha256": "7337b689a6ad8b0b4c8d716ea356db14e22bd2982089825bb2382121ed3482f6",
"derivatives": [
{
"file": "public/images/sectors/agronegocio.webp",
"width": 960,
"height": 540,
"bytes": 110310,
"sha256": "3e9d3be22556300f880be39837f86e764e3d05433beff1da6694ef6cee1d5c34"
},
{
"file": "public/images/sectors/agronegocio-480.webp",
"width": 480,
"height": 270,
"bytes": 31592,
"sha256": "fd1f7624f7fd9224fc1c7bd11746806e419c645ba43c257b1edd9ba250cd47f1"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\economia-azul.jpg",
"sourceBytes": 456892,
"original": "outputs/home-sectors-20261023/originals/economia-azul.jpg",
"sha256": "1a2c04d0d9ed4a26129553daefd2ee18f6d820026ab1203acf3bcf91b0550f69",
"derivatives": [
{
"file": "public/images/sectors/economia-azul.webp",
"width": 960,
"height": 540,
"bytes": 107626,
"sha256": "bf3751e66839c1b3c585c91ffe65d32b9ee79ebd7d08e5e2c95c6cd581b04f8f"
},
{
"file": "public/images/sectors/economia-azul-480.webp",
"width": 480,
"height": 270,
"bytes": 29350,
"sha256": "aaf8ee66709d8e15c4304690dd03830b4368d14468a597d5617ccdb71d614331"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\energia.jpg",
"sourceBytes": 386678,
"original": "outputs/home-sectors-20261023/originals/energia.jpg",
"sha256": "a164e2c8ef155a6a198ae400feca132e79ba75e022473893ec48ebfa0557f679",
"derivatives": [
{
"file": "public/images/sectors/energia.webp",
"width": 960,
"height": 540,
"bytes": 81236,
"sha256": "b5605d9bb8645c5042baa511aaf39fcb187080a48d8e067b130fc974c4c9196d"
},
{
"file": "public/images/sectors/energia-480.webp",
"width": 480,
"height": 270,
"bytes": 21926,
"sha256": "7e53977fc6ce11755455f8092ac3f8c7126f54d909a3935e522f8dae0ab834be"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\industria.jpg",
"sourceBytes": 357131,
"original": "outputs/home-sectors-20261023/originals/industria.jpg",
"sha256": "d70c4257ac58a4b5e9f8b8b1a4cf6d98c0514043442c3ce46f5c98399038527f",
"derivatives": [
{
"file": "public/images/sectors/industria.webp",
"width": 960,
"height": 540,
"bytes": 80422,
"sha256": "ca8ddd2d65647f1ed7a9906271fa2ea3d027f310b89434fd7781a37a3d18322d"
},
{
"file": "public/images/sectors/industria-480.webp",
"width": 480,
"height": 270,
"bytes": 25194,
"sha256": "8bd695231209c0042b94e68b0e2095fa7202297708dabff0f78b337500b8c9b7"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\infraestruturas.jpg",
"sourceBytes": 395383,
"original": "outputs/home-sectors-20261023/originals/infraestruturas.jpg",
"sha256": "ac6cde89507af68991faebee19540f955146724d3be901839b85a4098fe1674b",
"derivatives": [
{
"file": "public/images/sectors/infraestruturas.webp",
"width": 960,
"height": 540,
"bytes": 86654,
"sha256": "14754a59477e5c62a62c190be812c89d9616608b3c98acb6100ad70d94d34df0"
},
{
"file": "public/images/sectors/infraestruturas-480.webp",
"width": 480,
"height": 270,
"bytes": 25772,
"sha256": "eca58096087d05dae3eea2b4d063c103f9fc85b0ea20fc5051313cf9bfa1020f"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\logistica-transportes.jpg",
"sourceBytes": 413702,
"original": "outputs/home-sectors-20261023/originals/logistica-transportes.jpg",
"sha256": "5976ead23da0d4e7d5debf875262f0229d389826aaeb7e7be4ebbac3f5129a9e",
"derivatives": [
{
"file": "public/images/sectors/logistica-transportes.webp",
"width": 960,
"height": 540,
"bytes": 96254,
"sha256": "0d235e7bbd160cccd3f97daa3337d6b27fde49db9782ad2ba0599c6a83022b6c"
},
{
"file": "public/images/sectors/logistica-transportes-480.webp",
"width": 480,
"height": 270,
"bytes": 28816,
"sha256": "32f5137e0a7f6a7894b186edb2ca38f12cdfdca04dda3588de3969fb3d2e333a"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\mineracao.jpg",
"sourceBytes": 415161,
"original": "outputs/home-sectors-20261023/originals/mineracao.jpg",
"sha256": "7e6d1e5a17d434456ad937680a6c5501bd33bd624d2cc7ebf4b643185a9440aa",
"derivatives": [
{
"file": "public/images/sectors/mineracao.webp",
"width": 960,
"height": 540,
"bytes": 96642,
"sha256": "12c93df378f54108b13260c10d29789564af7844cc84bcd9281d2be917d83354"
},
{
"file": "public/images/sectors/mineracao-480.webp",
"width": 480,
"height": 270,
"bytes": 26034,
"sha256": "be3e7763fb8cd2e02f576204269821c40d93a7c155d8088a5084064b7269e4d6"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\outros-sectores.jpg",
"sourceBytes": 328152,
"original": "outputs/home-sectors-20261023/originals/outros-sectores.jpg",
"sha256": "4aaac0869dc7e61c4c7a87e1af95beb108aa9be0da082702f6f70722e62b1e7a",
"derivatives": [
{
"file": "public/images/sectors/outros-sectores.webp",
"width": 960,
"height": 540,
"bytes": 75414,
"sha256": "f47b3d0da5b0cd5153d393c6f779484ba89043e50195e968338108e893a88077"
},
{
"file": "public/images/sectors/outros-sectores-480.webp",
"width": 480,
"height": 270,
"bytes": 24936,
"sha256": "a4fc00551d75c96a1648ad4f81d759d4d6ecd7e6fc5689689216a96934bd1ea2"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\servicos-financeiros.jpg",
"sourceBytes": 348386,
"original": "outputs/home-sectors-20261023/originals/servicos-financeiros.jpg",
"sha256": "f932a56248d5544bff92aa30f4af3a5a63044c311969d4370d06f157b097d570",
"derivatives": [
{
"file": "public/images/sectors/servicos-financeiros.webp",
"width": 960,
"height": 540,
"bytes": 72144,
"sha256": "15379485db7de7b2efebe8bdbd4cbd8e911eb34ab8a23b3dd114c849bb4ae65c"
},
{
"file": "public/images/sectors/servicos-financeiros-480.webp",
"width": 480,
"height": 270,
"bytes": 20698,
"sha256": "c21949201e35e63625d3d2e7520e10912fe65be1186954142b2784f6efca51ed"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\tic-economia-digital.jpg",
"sourceBytes": 417398,
"original": "outputs/home-sectors-20261023/originals/tic-economia-digital.jpg",
"sha256": "b09703bd079f55fb5a8ec3167ce96e1fdb1e5090813a81c817b9a33909427d94",
"derivatives": [
{
"file": "public/images/sectors/tic-economia-digital.webp",
"width": 960,
"height": 540,
"bytes": 97892,
"sha256": "b1d79c1a941085582d6a72799140bafed1bf38ec0201a4dfe5f6faf54ea55ae8"
},
{
"file": "public/images/sectors/tic-economia-digital-480.webp",
"width": 480,
"height": 270,
"bytes": 28242,
"sha256": "c4279a27ed402ca2feb62f11a8a954cbcae993912d3c8c27a2d9644fdf922114"
}
]
},
{
"source": "D:\\Projects\\Tempo_Investidor\\tempo-dashboard\\storage\\app\\public\\investor-portal\\sectors\\turismo.jpg",
"sourceBytes": 393339,
"original": "outputs/home-sectors-20261023/originals/turismo.jpg",
"sha256": "1a76db252bc8c1a9dc1f3c650bd95e55337c36a6f604753d61cad96c19b1875f",
"derivatives": [
{
"file": "public/images/sectors/turismo.webp",
"width": 960,
"height": 540,
"bytes": 93234,
"sha256": "de46707dfdd8b98c48ec88d19f3df0b1d6c130adfcbd97d5a7c2e6fa2db62bef"
},
{
"file": "public/images/sectors/turismo-480.webp",
"width": 480,
"height": 270,
"bytes": 27012,
"sha256": "4d3d9a04b9426474dca9ba8895021b48fffbe7e4d4a4551272b8c832cf83488e"
}
]
}
],
"assetMapping": {
"agronegocio": "agronegocio",
"turismo": "turismo",
"infraestruturas": "infraestruturas",
"economia-azul": "economia-azul",
"mercado-financeiro": "servicos-financeiros",
"mineracao": "mineracao",
"energia-especifica": "energia",
"imobiliario": "outros-sectores",
"bens-de-consumo-e-franquias": "industria",
"tecnologias-de-informacao": "tic-economia-digital"
},
"assetSource": "JPG locais do projecto de referência indicado pelo proprietário, inventariados e copiados sem alteração; WebP derivados para apresentação. Sem alegação adicional de licença externa, origem oficial ou localização documental. Imagem genérica reutilizada como alternativa funcional e para sectores sem imagem específica.",
"assetBytes960": 997828,
"assetBytes480": 289572,
"verification": {
"browser": {
"results": [
{
"width": 320,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 2,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"width": 390,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 2,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"width": 768,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 3,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"width": 1024,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 5,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"width": 1440,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 5,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"width": 1920,
"homeSectors": 5,
"catalogueSectors": 10,
"homeColumns": 5,
"headings": [
{
"title": "Encontre o contexto do seu investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Sectores de investimento",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Como Investir",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Oportunidades em destaque",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Documentos essenciais",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
},
{
"title": "Apoio ao Investidor",
"size": "24px",
"weight": "700",
"color": "rgb(237, 28, 36)",
"lineHeight": "32px"
}
],
"status": "passed"
},
{
"fail": "primary",
"status": "passed"
},
{
"fail": "all",
"status": "passed"
},
{
"emptyCatalogue": true,
"status": "passed"
}
],
"errors": [],
"navigation": [
"/sectores",
"/sectores",
"/sectores",
"/sectores",
"/sectores",
"/sectores/agronegocio",
"/sectores",
"/sectores/turismo",
"/sectores",
"/sectores/infraestruturas",
"/sectores",
"/sectores/economia-azul",
"/sectores",
"/sectores/mercado-financeiro",
"/sectores",
"/sectores/mineracao",
"/sectores",
"/sectores/energia-especifica",
"/sectores",
"/sectores/imobiliario",
"/sectores",
"/sectores/bens-de-consumo-e-franquias",
"/sectores",
"/sectores/tecnologias-de-informacao",
"/sectores",
"/sectores/mercado-financeiro/fintech",
"/sectores",
"/",
"/sectores",
"/sectores"
],
"databaseAccess": false
},
"script": "tools/portal-home-sectors-qa.mjs",
"screenshots": [
"outputs/home-sectors-20261023/catalogue-1024.png",
"outputs/home-sectors-20261023/catalogue-1440.png",
"outputs/home-sectors-20261023/catalogue-1920.png",
"outputs/home-sectors-20261023/catalogue-320.png",
"outputs/home-sectors-20261023/catalogue-390.png",
"outputs/home-sectors-20261023/catalogue-768.png",
"outputs/home-sectors-20261023/fallback-all.png",
"outputs/home-sectors-20261023/fallback-primary.png",
"outputs/home-sectors-20261023/home-sectors-1024.png",
"outputs/home-sectors-20261023/home-sectors-1440.png",
"outputs/home-sectors-20261023/home-sectors-1920.png",
"outputs/home-sectors-20261023/home-sectors-320.png",
"outputs/home-sectors-20261023/home-sectors-390.png",
"outputs/home-sectors-20261023/home-sectors-768.png",
"outputs/home-sectors-20261023/homepage-1440.png"
],
"existingFrontendTests": {
"command": "node --test tests/frontend/portal-api.test.mjs tests/frontend/portal-navigation.test.mjs",
"passed": 20
},
"types": {
"command": "npm run types:check",
"exitCode": 0
},
"lint": {
"exitCode": 0
},
"build": {
"command": "npm run build",
"exitCode": 0,
"assets": {
"resources/js/pages/PortalInvestidor.tsx": "assets/PortalInvestidor-Q1OJxvfZ.js",
"resources/js/pages/portal/services.tsx": "assets/services-DiuG4Zkv.js"
},
"log": "outputs/home-sectors-20261023/build-local.log"
}
},
"scope": {
"appliedLocally": true,
"databaseChanged": false,
"migrationsRun": false,
"businessRulesChanged": false,
"routesChanged": false,
"sourceProjectChanged": false,
"newDependencies": false,
"externalDeployment": false
},
"limits": "Interface e navegação exercitadas com API e páginas públicas em fixtures; não equivale a demonstração integral dos workflows operacionais ou de critérios mais amplos da matriz.",
"matrixReferences": [
"MASTER-efd550fd-0104",
"MASTER-9f5719c8-0077"
]
}
@@ -0,0 +1,406 @@
{
"date": "2026-10-23",
"decision": "Pedido expresso da Tempo: analisar e acrescentar imagens adequadas exclusivamente aos três cartões de Como Investir.",
"analysisAndPlan": "docs/investmoz/public-portal-sections.md#fotografias-nas-etapas-de-como-investir--23102026",
"source": {
"type": "Fotografias ilustrativas geradas por IA, sem atribuição a pessoas, instituições, locais ou projectos reais.",
"tool": "image_gen, modo integrado",
"skill": "C:/Users/jorge/.codex/skills/.system/imagegen/SKILL.md",
"externalPhotographsUsed": false
},
"images": [
{
"key": "explorar",
"prompt": "Use case: photorealistic-natural. Asset for a small navigation card on a Mozambique investor portal. Create one individual photorealistic editorial photograph, horizontal 16:9, professional restrained style, natural soft daylight, realistic skin and materials, neutral colors, documentary composition readable at 350px wide. Illustration of a plausible setting, no identifiable named project or official building. No text, lettering, logos, watermarks, flags, maps, diagrams, graphic overlays, montage, or advertisement styling. Keep main subject inside the central 80% for responsive crop. Stage 1 EXPLORE opportunities, sector and territory: two Mozambican business professionals, a woman and man in smart casual clothing, standing outdoors by a quiet access road at a modest business park, naturally discussing a tablet held by the woman. Generic unbranded low warehouse buildings and green productive land visible in background, credible southern African environment. Eye-level medium-wide candid composition, both people three-quarter view, looking at tablet and surroundings rather than camera. Business evaluation and discovery, no construction work or hard hats.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-42eb9338-4350-40bf-9098-858c12994189.png",
"original": "outputs/investment-steps-20261023/originals/explorar.png",
"originalSha256": "a3c4ec1a0d2deaf87e0c8e765616c74ab70067eade9a862effce9e6befbbccb6",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-steps/explorar.webp",
"width": 960,
"height": 540,
"bytes": 52266,
"sha256": "c3e151ae649ce3cb66f5babc39978fa5803d320cacc95a27e798db4ec2d45a4c"
},
{
"file": "public/images/investment-steps/explorar-480.webp",
"width": 480,
"height": 270,
"bytes": 19312,
"sha256": "d3f383d9a58b23fada37472ea853f985aca8c3146123747d777b27704d32c7e0"
},
{
"file": "public/images/investment-steps/explorar-fallback.webp",
"width": 240,
"height": 135,
"bytes": 5300,
"sha256": "ba12ac4d2e81ac8a2c2e681667ccb08a3abfdba24de39e6e942d6378b700f2a9"
}
]
},
{
"key": "preparar",
"prompt": "Use case: photorealistic-natural. Asset for a small navigation card on a Mozambique investor portal. Create one individual photorealistic editorial photograph, horizontal 16:9, professional restrained style, natural soft daylight, realistic skin and materials, neutral colors, documentary composition readable at 350px wide. Illustration of a plausible setting, no identifiable named project or official building. No text, lettering, logos, watermarks, flags, maps, diagrams, graphic overlays, montage, or advertisement styling. Keep main subject inside the central 80% for responsive crop. Stage 2 PREPARE investment and organize documents: a Mozambican woman entrepreneur and a male business adviser seated at a light wood office desk, calmly reviewing and sorting a small tidy set of document folders and loose sheets beside a closed laptop. One points to a page while the other organizes a folder. No visible readable writing or personal data; papers at an angle. Bright modest professional meeting room, view from slightly above table height, hands and folders clear in foreground, natural candid interaction, realistic anatomy.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-5f07618a-1e86-42d9-aaf8-3acd0abf2164.png",
"original": "outputs/investment-steps-20261023/originals/preparar.png",
"originalSha256": "679a6875bb3ec79a9b71c27c9d785334376746be2bb305f461db9e19b0a0b7ea",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-steps/preparar.webp",
"width": 960,
"height": 540,
"bytes": 57942,
"sha256": "6de28042d3abce238a3680fb878779682f3672c3feb97b7e42b72e9a0a0ffbac"
},
{
"file": "public/images/investment-steps/preparar-480.webp",
"width": 480,
"height": 270,
"bytes": 19950,
"sha256": "671ba0fc207f85833b91027d3f6dad91599e95702cfea439e558906f92a2bfac"
},
{
"file": "public/images/investment-steps/preparar-fallback.webp",
"width": 240,
"height": 135,
"bytes": 6008,
"sha256": "645b34cd60b31fdc8e6586dedb71061c08add9ff985ce90909333b0bd1e0aa3e"
}
]
},
{
"key": "acompanhar",
"prompt": "Use case: photorealistic-natural. Asset for a small navigation card on a Mozambique investor portal. Create one individual photorealistic editorial photograph, horizontal 16:9, professional restrained style, natural soft daylight, realistic skin and materials, neutral colors, documentary composition readable at 350px wide. Illustration of a plausible setting, no identifiable named project or official building. No text, lettering, logos, watermarks, flags, maps, diagrams, graphic overlays, montage, or advertisement styling. Keep main subject inside the central 80% for responsive crop. Stage 3 FOLLOW UP submitted request and protocol: a Mozambican male entrepreneur seated at a tidy desk using a laptop to check an online application, one hand naturally on trackpad, a small closed document folder nearby. Three-quarter side view showing focused face and laptop, warm daylight from side window, modest contemporary office with soft greenery out of focus. Laptop screen is oblique and softly out of focus with only indistinct neutral interface rows, no readable text, official seal, logo or invented dashboard details. Convey calm digital self-service and progress checking, not a call centre or signing documents.",
"source": "C:\\Users\\jorge\\.codex\\generated_images\\01a167bd-3f26-71a0-8ec3-3f17519d2bfd\\exec-f896c5f8-19a0-49b0-af8e-0d12bfe4c7aa.png",
"original": "outputs/investment-steps-20261023/originals/acompanhar.png",
"originalSha256": "17d453445f2afb4c7641909950d2ecfb8276c433a4e28eeee94d0a57d1bdad46",
"originalDimensions": {
"width": 1672,
"height": 941
},
"derivatives": [
{
"file": "public/images/investment-steps/acompanhar.webp",
"width": 960,
"height": 540,
"bytes": 43722,
"sha256": "fe764c8161de36ee597f856face5341260670d1a28ab482bd01a0f5120ad0588"
},
{
"file": "public/images/investment-steps/acompanhar-480.webp",
"width": 480,
"height": 270,
"bytes": 16176,
"sha256": "79ceaecb0ef23c6729e43d04b7e91493d6784ea9f658d540dda3550702dc3623"
},
{
"file": "public/images/investment-steps/acompanhar-fallback.webp",
"width": 240,
"height": 135,
"bytes": 5298,
"sha256": "cd4530cfef4f19f23f640ceae59cfd73d0ee269643118b458f2a4748f5845fc6"
}
]
}
],
"cards": [
{
"title": "1. Explorar",
"description": "Identifique o sector, território e oportunidade.",
"href": "/oportunidades",
"image": "explorar"
},
{
"title": "2. Preparar",
"description": "Conheça o percurso e organize os documentos.",
"href": "/como-investir",
"image": "preparar"
},
{
"title": "3. Acompanhar",
"description": "Envie o pedido e acompanhe o protocolo.",
"href": "/balcao-virtual",
"image": "acompanhar"
}
],
"presentation": {
"component": "resources/js/components/investment-steps.tsx",
"homeIntegration": "resources/js/pages/PortalInvestidor.tsx",
"aspectRatio": "16:9",
"responsiveImages": [
960,
480
],
"fallback": "Variante própria de 240 px; se também falhar, espaço reservado com descrição acessível e Imagem indisponível.",
"columns": "Uma coluna abaixo de 768 px, três a partir de 768 px.",
"compactText": "16 px de preenchimento, sem altura mínima de texto.",
"accessibility": "Alt em português, nomes e descrições das âncoras, foco visível, dimensões reservadas e loading lazy.",
"headings": "Título vermelho partilhado da home preservado."
},
"verification": {
"browser": {
"results": [
{
"width": 320,
"dpr": 1,
"fail": "none",
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar-480.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.7820512820512822
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar-480.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.7820512820512822
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar-480.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.7820512820512822
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 390,
"dpr": 2,
"fail": "none",
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.7755102040816326
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.7755102040816326
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.7755102040816326
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 768,
"dpr": 1,
"fail": "none",
"columns": 3,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar-480.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.7734375
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar-480.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.7734375
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar-480.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.7734375
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 1024,
"dpr": 1,
"fail": "none",
"columns": 3,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar-480.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.7784090909090908
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar-480.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.7784090909090908
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar-480.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.7784090909090908
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 1440,
"dpr": 2,
"fail": "none",
"columns": 3,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.775
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.775
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.775
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 1920,
"dpr": 1,
"fail": "none",
"columns": 3,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar-480.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.775
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar-480.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.775
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar-480.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.775
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 390,
"dpr": 2,
"fail": "primary",
"columns": 1,
"photos": [
{
"src": "http://127.0.0.1:5174/images/investment-steps/explorar-fallback.webp",
"alt": "Dois profissionais avaliam uma oportunidade de investimento no terreno com apoio de um tablet.",
"lazy": "lazy",
"ratio": 1.7755102040816326
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/preparar-fallback.webp",
"alt": "Empreendedora e consultor analisam documentos e organizam pastas numa reunião de preparação.",
"lazy": "lazy",
"ratio": 1.7755102040816326
},
{
"src": "http://127.0.0.1:5174/images/investment-steps/acompanhar-fallback.webp",
"alt": "Empreendedor consulta um pedido no computador portátil numa secretária de escritório.",
"lazy": "lazy",
"ratio": 1.7755102040816326
}
],
"layoutShift": false,
"overflow": false
},
{
"width": 390,
"dpr": 2,
"fail": "all",
"columns": 1,
"photos": [],
"layoutShift": false,
"overflow": false
}
],
"errors": [],
"navigation": [
"/oportunidades",
"/como-investir",
"/balcao-virtual"
],
"databaseAccess": false
},
"script": "outputs/investment-steps-20261023/check.mjs",
"screenshots": [
"outputs/investment-steps-20261023/cards-1024-none.png",
"outputs/investment-steps-20261023/cards-1440-none.png",
"outputs/investment-steps-20261023/cards-1920-none.png",
"outputs/investment-steps-20261023/cards-320-none.png",
"outputs/investment-steps-20261023/cards-390-all.png",
"outputs/investment-steps-20261023/cards-390-none.png",
"outputs/investment-steps-20261023/cards-390-primary.png",
"outputs/investment-steps-20261023/cards-768-none.png"
],
"lint": {
"exitCode": 0
},
"types": {
"command": "npm run types:check",
"exitCode": 0,
"log": "outputs/investment-steps-20261023/types.log"
},
"build": {
"command": "npm run build",
"exitCode": 0,
"homeAsset": "assets/PortalInvestidor-C1QTZ3-t.js",
"log": "outputs/investment-steps-20261023/build-local.log"
}
},
"scope": {
"appliedLocally": true,
"otherSectionsChanged": false,
"supportAndFooterChanged": false,
"databaseAccess": false,
"businessRulesChanged": false,
"routesChanged": false,
"newDependencies": false,
"externalDeployment": false
},
"matrixReferences": [
"MASTER-efd550fd-0104"
],
"limits": "Componentes reais com API sintética e destinos interceptados para verificar a navegação; não demonstra os workflows operacionais completos nem encerra o critério mais amplo da matriz."
}
@@ -74,3 +74,30 @@ Novas execucoes identificam-se como `portal-arithmetic-v1`, para nao sugerir que
- Snapshot `business-plan-v17`: adds `openingPayablesInstallments`, an optional schedule with month and percent of the original opening payable balance. Declared percentages sum to at most 100%; cent rounding is capped at the unpaid balance. Scheduled settlements reduce cash and opening payables, not profit or period expenses. Any unpaid amount remains a closing payable; an absent schedule assumes no settlement and leaves the full opening amount outstanding. Snapshots v1-v16 remain readable with an empty schedule; explicit resave produces v17.
- Execuções API concluídas só são aceites pelo consumidor se `result_snapshot` for um envelope `contract_version: 1` válido (incluindo consistência entre `result.value` e `indicative_total`) ou um snapshot legado legível com montante decimal. Estados concluídos sem snapshot, com snapshot malformado ou com versão v1 inválida são rejeitados na fronteira da API; estados não concluídos podem manter snapshot ausente/nulo. Snapshots históricos legíveis continuam compatíveis.
## IRPC normal — conferência anual opcional, versão de cálculo 2
O envelope de livros mantém `version:1`; `irpcNormal[opportunity]` aceita `profit` opcional (`version:1`, `completenessReference`, `lines`, `topics`). As linhas mantêm o código/origem financeira, estado `known|absent|''` e referência; os tópicos conservam separadamente estado, montante original e referência. `known` com montante zero não se torna `absent`; `''` não se torna zero. Tópicos de valor conhecido não zero sem regra implementada não são aplicados. Uma ausência incompatível com a origem ou com montante preenchido mantém pendência.
Sem `profit`, o cálculo/leitor/histórico `IRPC-normal-adjustments/1` mantém significado e chave anterior. Com conferência adicional, `IRPC-normal-adjustments/2` acrescenta `model.profit` congelado e pode produzir `taxableProfit` racional com sinal. `taxableBase` e `tax` continuam nulos. O cálculo só fecha no recorte anual/residente/MZN documentado, sujeito-exercício completo, receitas/custos ordinários qualificados, acréscimos resolvidos e demais efeitos expressamente ausentes ou zero conhecidos. A origem continua `projected`; não é demonstração contabilística nem confirmação AT. Depreciação positiva e juros financeiros remanescentes exigem tratamento próprio.
O fingerprint inclui os novos factos apenas quando presentes; alterações do plano ou da conferência desactualizam o resultado sem eliminar histórico. Os demais livros permanecem intactos no snapshot. Gravação e recuperação usam a API privada existente com ETag/If-Match; sem novo endpoint, schema, permissões ou activação de parâmetros. Matéria colectável/colecta/créditos anuais e M20/M22 não são inferidos de um lucro conhecido.
## IRPC normal — matéria colectável opcional, versão de cálculo3
O envelope de livros e entradas mantém `version:1`; `irpcNormal[opportunity].base` é opcional e versionado1. Conserva NUIT/suporte,método,situação/completude das perdas,manutenção da actividade,linhas anuais de perdas e estado/montante/referência dos benefícios à base. Os montantes apurados,utilizados anteriormente e propostos são stringsMZN,não negativos,até dois decimais;campos ausentes não recebem zero. Um saldo por sujeito/exercício;sem fusão de livros ou origens.
Sem `base`,as versões1/2 mantêm chaves e significado. Com `base`,`IRPC-normal-adjustments/3` acrescenta modelo congelado de elegibilidade/propostas/deduções/saldos e pode produzir `taxableBase` racional no recorte documentado;`tax` permanece nulo. O fingerprint inclui apenas as novas entradas quando presentes. Repetir cálculo não altera `previouslyUsed`;`remaining` é saldo aritmético desta simulação,não reporte/consumo oficial. Uma edição preserva os resultados anteriores no histórico e exige novo cálculo antes de exportar.
Estado conhecido zero,ausência suportada e informação em falta permanecem distintos. Benefício positivo,perda transmitida ou saldo/regime não correspondido não se convertem em dedução livre. Dados e resultado usam a APIprivada existente/ETag,sem schema,endpoints,permissões ou parâmetros novos. A matéria colectável simulada não é colecta nem imposto a pagar.
## IRPC normal — colecta opcional, versão de cálculo4
O envelope e o livro mantêm `version:1`; `irpcNormal[opportunity].assessment` opcional guarda `version:1`, `treatment:''|general_61_1|other` e referência do enquadramento. Sem esta entrada,versões/chaves1–3 mantêm o significado anterior. Com ela,o cálculo `IRPC-normal-adjustments/4` acrescenta modelo congelado `assessment` e `colecta` racional,sem reutilizar o campo legado `tax` como colecta ou saldo final.
A colecta corresponde à matéria colectável actual×32/100 no recorte2026/MZN/residente geral,após classificação e suporte expressos. O modelo identifica taxa32,art61(1),versão da regra e período anual. Informação em falta,período fora do recorte,moeda/âmbito distintos ou caso especial mantêm colecta nula;zero exige base conhecida zero. A fracção racional é conservada exactamente;`centExact:false` não autoriza arredondamento fiscal nem transcrição oficial.
`assessment.finalBalance` é sempre `scope:L8,status:not_calculated,payable:null,recoverable:null` nesta versão. Retenções,pagamentos e créditos anuais não entram na fórmula da colecta nem são subtraídos automaticamente. UI,HTML e dossier apresentam lucro tributável→matéria colectável→colecta→saldo final com esse limite. APIprivada/ETag existente conserva todo o snapshot e histórico,sem novos endpoints,schema,permissões ou migração dos resultados anteriores.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
{
"status": "prepared_for_Git_delivery_not_installed",
"installed": "5fa64bc0",
"previous_QA": "acf8ec3c",
"date": "2026-10-25",
"scope": "Existing AUD-SIM-INT02 only; J1-J5 and C1-C5 each with example in existing matrix/manual; not sent to AT",
"presentation": "Automatic interest is a simulation with supplied assumptions, not fiscally confirmed. Entered CER is not validated by official catalogue. Fictional999/998 and10% remain fictional.",
"pending": "Exact annual rate/source/validity, day basis, rounding, on-account not-withheld/mora; official CER by nature/digital-special and official transcription of mixed rates/codes.",
"verification": {
"new_delta_tests": 13,
"typescript": "passed",
"QA_build": "passed exit0",
"accepted_API_UI_L3_ISPC_FX": "reused; no new round",
"protected_runtime": 31
},
"runtime_sha256_LF": {
"resources/js/lib/irpc-interest.ts": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd",
"resources/js/lib/irpc-mrfta.ts": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c",
"resources/js/lib/irpc-mrfta-cases.ts": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862",
"resources/js/components/simulation-irpc-mrfta.tsx": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
"previous_receipt": "irpc-interest-cer-qa-20261025.json remains historical proof for acf8ec3c; current presentation hashes in this receipt",
"schema_API_permissions_originals_changed": false,
"L5_complete": false
}
@@ -0,0 +1,579 @@
{
"status": "installed_operational_L5_demonstrated_scope_only",
"installed": {
"status": "installed",
"commit": "7a11c4ef8f06ef149eb0488be3cd0749dc609bd0",
"release": "/var/www/investmoz-homologacao/releases/7a11c4ef8f06ef149eb0488be3cd0749dc609bd0-68c76bdc",
"previous_release": "/var/www/investmoz-homologacao/releases/5fa64bc0f4b067e81d8728b344eb8697415ebedf-b08a592f",
"database_migrations": 0,
"content_imports": 0
},
"previous_baseline": "5fa64bc0f4b067e81d8728b344eb8697415ebedf",
"backup": {
"stage": "/var/backups/investmoz-irpc-interest-delivery-20261025/backup",
"created_at": "2026-10-25T19:14:23Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "ae9ba280390f9ca676845fdced1193642102658ea1274669c81387b26e38c8ba",
"files_sha256": "45b492019ca2f7cc93388f54b776754e5e045e15916f824d257928bb45e324f4",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l5_restore_20261025",
"port": 55441,
"source_dump_sha256": "ae9ba280390f9ca676845fdced1193642102658ea1274669c81387b26e38c8ba",
"active_database_writes": 0
},
"preservation": {
"previous_release_preserved": "/var/www/investmoz-homologacao/releases/5fa64bc0f4b067e81d8728b344eb8697415ebedf-b08a592f",
"installed": {
"status": "installed",
"commit": "7a11c4ef8f06ef149eb0488be3cd0749dc609bd0",
"release": "/var/www/investmoz-homologacao/releases/7a11c4ef8f06ef149eb0488be3cd0749dc609bd0-68c76bdc",
"previous_release": "/var/www/investmoz-homologacao/releases/5fa64bc0f4b067e81d8728b344eb8697415ebedf-b08a592f",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 4,
"preserved_L3_ISPC_FX_runtime_files_verified": 31,
"documentary_files_verified": 30,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 106,
"checksum": "e4bcbac53e96b6fef0b4bf512aeb9470"
},
"after": {
"rows": 106,
"checksum": "58c1c37e3152c0e387a19b3bcf057bb0"
}
},
"sessions": {
"before": {
"rows": 21,
"checksum": "887634a88e9462f38305ff7623c4c508"
},
"after": {
"rows": 22,
"checksum": "6a080a3d85940d192748fa272fe94f15"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"schema_permissions": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart value/expiry and request-throttle counter/timer pair;no deleted cache rows",
"sessions": "anonymous sessions created by exact delivery verification user-agent",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "8d6ea77eb4b34d86d207362d583cfa8bf2880b907becd9b00398964482c6b4bd",
"kind": "updated",
"fields": [
"expiration"
],
"key_pattern": "investemoz-cache-{hash}",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "2f251473865d14b953236ab95b1521764754d76abd79b58ca7d38c96dfe2fab1",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-{hash}:timer",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false
}
]
},
"sessions": {
"before_rows": 21,
"after_rows": 24,
"changes": [
{
"key_sha256": "f72f988e8b92b60a9a4c888ad2e0a275af4dd678ca1c3f59765808df2385706b",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "c1d4a5d1f3f22112b617003a45e285538c6afbfc16502fe76476528808c5a62f",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "fb07fca164c39ae39fbf4002fe20469826c1c6050f2e6af7ce54926bffe87a87",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"public_verification": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "7a11c4ef8f06ef149eb0488be3cd0749dc609bd0",
"branch": "main",
"built_at": "2026-10-25T19:18:14.226356+00:00",
"manifest_sha256": "d78df5e7caee48690641143c8e8633b850db421468c837ec37992ee9cfa21aaa"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"Simulação pelos pressupostos introduzidos, sem confirmação fiscal dos juros.": [
"assets/services-xTyGW6qB.js"
],
"Códigos provisórios ou de simulação não são correspondências oficiais.": [
"assets/project-dossier-CxbkzdT3.js"
],
"Casos de trabalho separados por período, rubrica, taxa e CER": [
"assets/services-xTyGW6qB.js"
],
"Não são juros calculados pelo portal.": [
"assets/project-dossier-CxbkzdT3.js"
],
"Dispensa de retenção": [
"assets/project-dossier-CxbkzdT3.js",
"assets/services-xTyGW6qB.js"
],
"Calcular e guardar apuramento trimestral ISPC": [
"assets/services-xTyGW6qB.js"
],
"Calcular e guardar restituição E": [
"assets/services-xTyGW6qB.js"
],
"Reutilizar selecção cambial": [
"assets/services-xTyGW6qB.js"
]
},
"assets": [
{
"file": "assets/project-dossier-CxbkzdT3.js",
"status": 200,
"sha256": "be74df50d3dbed2fcf9873c70e9afd8b7e5403f74c4dfe3805ad96ab21f85440"
},
{
"file": "assets/services-xTyGW6qB.js",
"status": 200,
"sha256": "7a127267891fe3b05112ee7d749027d4c290e70539652d797345f9f6e059ffae"
},
{
"file": "assets/project-dossier-document-BjM1GMjD.js",
"status": 200,
"sha256": "b745b5faea379ce38afd77a90c4e391caf446513059727d1fcb75917a85b2429"
},
{
"file": "assets/simulation-form-BqVD91Ek.js",
"status": 200,
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-D3TVl0n5.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"runtime_delta": [
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256_LF": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256_LF": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256_LF": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256_LF": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
}
],
"protected_runtime": [
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256": "01d20f4761933a3e4dd7c776bd4adcf9610ac0435d918a1998ae9f0c3ce3f234"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256": "df8b224b9472449711d0b69a873fa75f9cc9f4d84dce1a314fc576fae9c6eae2"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256": "4523365e2d4a2fcd014e13393deb33a5ec4b9396ff580d8a237aa8c4f02265e4"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
}
],
"originals": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"pipeline_checks": [
"OK (1 test, 3106 assertions)",
"built in 30.04s",
"OK (59 tests, 317 assertions)",
"# tests 872",
"# pass 872",
"# fail 0"
],
"accepted_proofs_reused": true,
"manually_repeated_accepted_functional_suites": false,
"limitations": "Simulation with explicit supplied parameters is not fiscal confirmation of interest; provisional CER not official correspondence. Ten exact AT questions J1-J5/C1-C5 retained in existing matrix. L5 operational within demonstrated scope,not fully completed.",
"L5_complete": false,
"next": "L6 normal IRPC:adjustments to financial result;no repeated L5 source research without new information",
"proof_files": {
"backup.txt": "f321c1f1f595c3a056b41b6fe0dfe68941461d8efa686de7e76905946af180c9",
"compact-dependencies.txt": "6c66d80adb889a470b2500dfbbd6f984bef3a2ce9967f11ea21ac1bafe5af745",
"installed-protected.txt": "60564bfd4ee8d7158ebd5247b1321c0c1a4cfb69eb2401b8d7e4ec1b71f8e560",
"installed-public-delta.json": "9f121ebaff22a17942d2ba3ca98feaf3e5f9735c1eb25f1dcc47c0d07ba95804",
"installed-public.txt": "da646d8f4adfc9f6314bd5201675ea35c7bf9d247a15612bbcb0370dda1672c2",
"integration.txt": "dcdc8f4540117e2d87c44fbe99c92028700dc998b8d051cbebc9fe8638ef25f0",
"manifest-served.json": "d78df5e7caee48690641143c8e8633b850db421468c837ec37992ee9cfa21aaa",
"operational-delta.txt": "264946621bdd67789d3d6b2c4589fc77e2337e606f90e90a5baec812a2368940",
"preflight.txt": "fbf315297e990f29224c110982d02dbae88da98c2819f001af914f7f8a23c73e",
"preparation.json": "e4b83c40a692adc864650391515f29e97b59da6ddfee3f19840ff07e7e8771ec",
"progress.txt": "2f9ccb94847d399d18b4e76e1f283ae00376791d428cf138c750d5075fba1ce0",
"restore.txt": "e51ada3301c3c18af3dfda10a537275b55f183bb6ac1e9bb1d2ea10ec1d4ecff",
"schema-permissions-after.txt": "76b5a4d8af11e4898a205062766cfb7ab6ec0783200e77e60a1927aa1ca18597",
"schema-permissions-before.txt": "0ab7c964792acdd8917bce256c472e55e034b103500a58b49f020b5084823ed7",
"status1.txt": "b6da9d8d0b2a31b94bed039b7806400193bcbf9c386faae848d7ea7512e6da71",
"status2.txt": "b6da9d8d0b2a31b94bed039b7806400193bcbf9c386faae848d7ea7512e6da71",
"status3.txt": "998b40a5ebef08ac85ee0cdf80a8f8b07da159565f0f7a62e8c02613d9859c8d",
"status4.txt": "f2580fba78230810b2bd95885494d76c86a2e5ee7f3705e3d300eca2f06e5109",
"status5.txt": "f2580fba78230810b2bd95885494d76c86a2e5ee7f3705e3d300eca2f06e5109",
"status6.txt": "f2580fba78230810b2bd95885494d76c86a2e5ee7f3705e3d300eca2f06e5109",
"status7.txt": "1248021d6ed7f0651a4d19b0d9985eb19cb285cb73927ed6c02a3e195881aabc"
}
}
@@ -0,0 +1,391 @@
{
"status": "QA_two_point_delta_demonstrated_not_installed",
"installed_baseline": "5fa64bc0f4b067e81d8728b344eb8697415ebedf",
"branch": "codex/irpc-interest-cer-qa-20261025",
"scope_only": [
"juros automáticos por parâmetros documentados",
"separação CER/rubrica/taxa por casos de trabalho"
],
"implemented": {
"juros": "Aritmética racional diária com taxa anual final/base anual/arredondamento/fontes/versão do caso;principal após entregas parciais,paragem no pagamento integral,contagem por anos quando documentada,versão própria apenas da nova aritmética. Definitiva e por conta efectivamente retida neste recorte.",
"CER_rubricas": "Chaves estáveis por período/rubrica/taxa/CER;origens,documentos e referências conservados;fichaHTML por caso,mantendo pendências do período e sem declarar anexo/declaração autónoma.",
"compatibility": "Campos adicionais;modo legado preservado. Leitor5fa64bc0 conserva o payload exacto e o cálculo fiscal actual;novo resultado de juros é histórico nessa versão,sem recálculo."
},
"not_claimed": [
"Taxa fiscal2026 global cadastrada/activada ou substituição automática daMAIBOR",
"Convenção fiscal de base anual/arredondamento inferida sem fonte do caso",
"Juros de mora ou regra completa de imposto por conta não retido",
"CatálogoCER integral e novas correspondências oficiais digitais/especiais",
"Autorização para fundir taxas/CER ou criar declarações/anexos oficiais",
"Instalação deste novo incremento ou conclusão deL5"
],
"remaining_only_two_points": {
"juros": "Ligar parâmetro/fonte fiscal aplicáveis2026 e as convenções documentadas do caso;regra de mora e retenção por conta não efectuada continuam separadas. Sem perfil completo,a aritmética fica indeterminada;não reutilizar taxa de exemplo.",
"CER_rubricas": "Obter/corresponder os códigos/rubricas ainda pendentes e a transposição oficial de múltiplas taxas/CER;as fichas separam trabalho,mas não resolvem o catálogo ou o procedimento oficial."
},
"verification": {
"new_frontend": "13 tests passed;no old functional suites manually repeated",
"types": "tsc --noEmit exit0",
"build": "complete QA build exit0",
"private_api": "1test/19assertions;DatabaseTransactions rollback;loopback55441/simulator_fiscal_delta_20261021_test",
"dossier": "generated from actual API recovery;parameters/day segments/report preserved",
"UI": {
"documentedParameterCalculation": true,
"fictionalRateExplicit": true,
"missingRateIndeterminate": true,
"principalPreserved": true,
"localSaveRecovery": true,
"caseDownload": true,
"notOfficialDeclaration": true,
"differentRatesCodesSeparated": true,
"periodTotalIndeterminate": true,
"privateApi": "IrpcInterestCerDraftTest,separate",
"errors": []
},
"installed_reader_new_payload": {
"readerRevision": "5fa64bc0",
"readNewPayload": true,
"taxResultCurrent": true,
"newPreparationHistorical": true,
"roundTripExact": true,
"oldCalculationsReexecuted": false
},
"accepted_proofs": "Existing5fa64bc0,L3,ISPC,FX proofs reused;onlynewdelta andnew-payload-reader compatibility checked"
},
"examples": "Annual10%,365days,rounding conventions andCER999/998 are explicitly fictional QA parameters/codes,not official2026 fiscal data. Principal7300,paid3650,interest15 on5+5days,total3665 in onecase;20%/10%withholding and999/998 separate cases keepperiodtotalindeterminate.",
"runtime_delta": [
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256_LF": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256_LF": "65133d0005051e0e5c9fbc8346478cca5198717e283e153094132a16d384a620"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256_LF": "c3132e6c1cdecff6a2d6d369ef5d8118aa6d58b59bca51516a1a3e0cb42f058e"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256_LF": "27a93e14eecfb002fe2f264e1854ec5bf852997535d61db1a8d3373a8e8470eb"
}
],
"protected_runtime": [
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d",
"sha256_LF": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd",
"sha256_LF": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73",
"sha256_LF": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542",
"sha256_LF": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf",
"sha256_LF": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225",
"sha256_LF": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d",
"sha256_LF": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e",
"sha256_LF": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2",
"sha256_LF": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54",
"sha256_LF": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704",
"sha256_LF": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955",
"sha256_LF": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18",
"sha256_LF": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25",
"sha256_LF": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4",
"sha256_LF": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878",
"sha256_LF": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129",
"sha256_LF": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4",
"sha256_LF": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c",
"sha256_LF": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977",
"sha256_LF": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846",
"sha256_LF": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998",
"sha256_LF": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf",
"sha256_LF": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb",
"sha256_LF": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08",
"sha256_LF": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb",
"sha256_LF": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256": "01d20f4761933a3e4dd7c776bd4adcf9610ac0435d918a1998ae9f0c3ce3f234",
"sha256_LF": "01d20f4761933a3e4dd7c776bd4adcf9610ac0435d918a1998ae9f0c3ce3f234"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256": "df8b224b9472449711d0b69a873fa75f9cc9f4d84dce1a314fc576fae9c6eae2",
"sha256_LF": "df8b224b9472449711d0b69a873fa75f9cc9f4d84dce1a314fc576fae9c6eae2"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256": "4523365e2d4a2fcd014e13393deb33a5ec4b9396ff580d8a237aa8c4f02265e4",
"sha256_LF": "4523365e2d4a2fcd014e13393deb33a5ec4b9396ff580d8a237aa8c4f02265e4"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
}
],
"originals_unchanged": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"source_review": {
"reuse": "AcceptedDecreto9/2008,25/35 andMRFTA/BM original sources. No new rate/CER activated from research.",
"AT_inventory": {
"url": "https://www.at.gov.mz/api/documents?root=LEGISLACAO",
"path": "outputs/irpc-interest-cer/at-legislation-inventory.json",
"sha256": "d74e764224d97fdea2e6e6e3496614c9b0f94941e8f8757eed8e7847bda9508c",
"documents": 189,
"read_scope": "Metadata/title inventory;not a fresh integral reading of189PDFs. No identified title supplies the required successor fiscal parameter or MRFTA CER crosswalk."
},
"CER_search": "Decreto68/2014 and subsequent disaggregation references identified;no applicable detailed CER crosswalk recovered for automatic mapping. Unnumbered drafts,field numbers and budget aggregates not used as revenue codes.",
"rate_search": "No applicable2026 fiscal replacement parameter obtained in this scoped check;current banking reference rates were not substituted."
},
"implementation_choices": [
"Complete parameter references are case data,not a new organizational approver. No default tax rate/day basis/rounding or source publication activates a calculation.",
"Working-case export retains period gaps;it does not decide official declaration splitting."
],
"active_changes": false,
"schema_backend_api_config_permissions_dependencies_delta": false,
"L5_integrally_completed": false,
"proofs": {
"outputs/irpc-interest-cer/api.txt": "e647e9d8daf16cfa4359e35edd373cfdbc7e35ef684b5fb8cdb1107eeb158ee7",
"outputs/irpc-interest-cer/at-legislation-inventory.json": "d74e764224d97fdea2e6e6e3496614c9b0f94941e8f8757eed8e7847bda9508c",
"outputs/irpc-interest-cer/build.txt": "3841d26e7f52f6468a337f1fd786dc7c04be122bc639bf3755842c39e1a837ad",
"outputs/irpc-interest-cer/calculated.json": "ff2d649ba269e7618a9cb9208f5e47baff5bbbc45c65176ba163cea5e69ad390",
"outputs/irpc-interest-cer/case-10-998.html": "bcfe6a84e07d3b411e28e231c797daf7c013041856dbb0aa05ba605309e8370a",
"outputs/irpc-interest-cer/case.html": "24ee8874acb770769bbe4e807af05e9d42646257142717c55c621d34259a6dc8",
"outputs/irpc-interest-cer/dossier.html": "5f69bd87ff0bcaa52c20eaa1c9feafeb6ae263d667aa4c53df15bd2abce8752d",
"outputs/irpc-interest-cer/dossier.json": "61c194509f6c2feb432819ff6f5d72647acf3ec2ff068bb299fe4c6be6a294da",
"outputs/irpc-interest-cer/dossier.txt": "a0473de355821758c4d320eea8e7af76a0d196a9cee652c71af723d6f69832f0",
"outputs/irpc-interest-cer/frontend.txt": "686362609c03b88d3f0d90951be11d0a3c65be8d79a3c50aa24c0249ab545da2",
"outputs/irpc-interest-cer/index.html": "6bb76e37ac20a73cb9ffcda14f1ac9db701aa01bc2ef2f62fc5adaaffb640ca8",
"outputs/irpc-interest-cer/installed-reader-compatibility.json": "dcac8cb281bac3d3ccace6c73087632c53dec1c27c5e4967b631a822dcb7da14",
"outputs/irpc-interest-cer/mixed.json": "82fec05e50261f4eb13160de93c78d76a6a58c79644ed2ca97fc27ae3ce41c3e",
"outputs/irpc-interest-cer/preparation.html": "8f210407ab61ed7a1f0bd3b8bce7c247bcecfc4ce2fe932924957fd3af1ff990",
"outputs/irpc-interest-cer/recovered.json": "ac9d7c1338c99190616d62f0ad5c7d11403af65d73ff6f7726a871c1693596e1",
"outputs/irpc-interest-cer/types.txt": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"outputs/irpc-interest-cer/ui-proof.json": "366a3aa989f40ea195b4d334bdc666d255ed88125eca9533a669eb0721e0267d",
"outputs/irpc-interest-cer/ui.png": "cac3bab6a576d5394b97d349903ead7ad12f3270a9c8a9f16ec2880822420d41",
"outputs/irpc-interest-cer/ui.txt": "98b34de11dd5b993510b997413d537320f291c447c6a1a9244817df99cc7cc72"
}
}
@@ -0,0 +1,360 @@
{
"status": "QA_juros_MRFTA_demonstrated_not_installed",
"installed_baseline": "ce746d889d5711f23f4e0ac8d9802997b5e106f9",
"branch": "codex/irpc-juros-mrfta-qa-20261025",
"implemented": [
"MRFTA preparation fields1–7 by single month;reserved8/9;HTML preparation export",
"Rubric/base/rate/tax and reconciled payments reused from frozen IRPC result;separate suffered/dispensed/other-month rows",
"Documented CER transcription with reference;no inferred CER from old guide field numbers",
"Documented compensatory-interest assessment amount or zero only after full timely remittance with documented deadline",
"Unknown rates/interest,digital/special rubrics,unknown CER,multiple rates or other taxes keep final total indeterminate while principal rows remain available",
"Private draft persistence,recovery,history;standalone MRFTA and full dossier reports;old IRPC inputs/calculations retained"
],
"not_implemented": [
"Automatic compensatory-interest arithmetic for2026:applicable successor/parameter for discontinuedMAIBOR12months not obtained",
"Juros de mora;autonomous tax;IRPS beyond prior delivered case",
"Digital/e-money and unqualified special rubrics;MRFTA CER catalogue not supplied by this increment",
"Mixed rate/CER same official rubric remains separate pending correspondence",
"No official PDF changed/filled;HTML preparation reflects fields and retains sourcePDF original;no submission/signatures/ATacceptance"
],
"verification": {
"frontend": "12 new tests+1 directed existing IRPC presentation test passed",
"types": "tsc --noEmit exit0",
"build": "complete QA build exit0",
"private_api": "1test/14assertions;DatabaseTransactions rollback;127.0.0.1:55441/simulator_fiscal_delta_20261021_test",
"dossier": "generated from actual private API recovered model",
"UI": {
"calculation": true,
"localSaveRecovery": true,
"privateApiProof": "IrpcMrftaDraftTest, separate",
"report": true,
"documentedInterest": true,
"insufficientInformation": true,
"download": true,
"errors": []
},
"CER_example": "999 is explicitly fictional QA data,not an official recipe-code mapping",
"unchanged_proofs": "AcceptedL3/ISPC/FX and ce746d88 calculation proofs reused;no manual repeat suites"
},
"runtime_delta": [
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256_LF": "1ff1725724dbdaaa9a3857941d03e312c6a7da573d369ee86015edc90cd2d0d1"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256_LF": "9cf7d5e447e1a9ed37d1bd24b4ac5104b1adec3790ff8db4356c3b68b339d89a"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
}
],
"protected_runtime": [
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d",
"sha256_LF": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd",
"sha256_LF": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73",
"sha256_LF": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542",
"sha256_LF": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf",
"sha256_LF": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225",
"sha256_LF": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d",
"sha256_LF": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e",
"sha256_LF": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2",
"sha256_LF": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54",
"sha256_LF": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704",
"sha256_LF": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955",
"sha256_LF": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18",
"sha256_LF": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25",
"sha256_LF": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4",
"sha256_LF": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878",
"sha256_LF": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129",
"sha256_LF": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4",
"sha256_LF": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c",
"sha256_LF": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977",
"sha256_LF": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846",
"sha256_LF": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998",
"sha256_LF": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf",
"sha256_LF": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb",
"sha256_LF": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08",
"sha256_LF": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb",
"sha256_LF": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256": "01d20f4761933a3e4dd7c776bd4adcf9610ac0435d918a1998ae9f0c3ce3f234",
"sha256_LF": "01d20f4761933a3e4dd7c776bd4adcf9610ac0435d918a1998ae9f0c3ce3f234"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256": "df8b224b9472449711d0b69a873fa75f9cc9f4d84dce1a314fc576fae9c6eae2",
"sha256_LF": "df8b224b9472449711d0b69a873fa75f9cc9f4d84dce1a314fc576fae9c6eae2"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256_LF": "4523365e2d4a2fcd014e13393deb33a5ec4b9396ff580d8a237aa8c4f02265e4"
}
],
"accepted_originals_inventory": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"new_official_source": {
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063",
"url": "https://bancomoc.mz/pt/areas-de-actuacao/mercados/mercado-monetario/",
"review": "Official page expressly documentsdiscontinuedMAIBOR publication;MIMO/Prime not transported into fiscalrule",
"publication_import_activation": "Private source archive only;no library publication or fiscal activation;no scan claimed"
},
"source_mapping": [
"AT MRFTA19/39PDF1–2,visuallyreviewed;fields1–7,reserved8/9,singleperiod",
"Decreto9/2008 arts25/35 PDF6/8,p121/123;reusedacceptedofficialoriginal,notoldrevoked2002code"
],
"implementation_choices": [
"Completeness and absence of other tax rubrics are recorded facts to avoid treating this context subtotal as the entire declaration;not new approvers or organizational permissions",
"Manual CER/assessment references record applicable documents;no generic legal authenticity revalidation"
],
"active_changes": false,
"schema_migrations_configuration_permissions_changed": false,
"L5_integrally_completed": false,
"proofs": {
"outputs/irpc-mrfta/api.txt": "63e401f6422cdea294b4ae58bf1ff5c25e7c5dd87eccf81c249319bffbb06dd3",
"outputs/irpc-mrfta/AT-MRFTA-19-39.pdf1.png": "d0f4118a696ab940d2fd9a9cb792656dcba860b9b3a300c78334445d43d46a72",
"outputs/irpc-mrfta/AT-MRFTA-19-39.pdf2.png": "449ce541e08d886e7851e04c6b53ee44694d89508143da3c497d16db1a3f6a59",
"outputs/irpc-mrfta/build.txt": "ede4498073edeeadcbda9b1868b4be5574ad31a36d78664a1ebf8fb27ee89c86",
"outputs/irpc-mrfta/calculated.json": "b41a7dec0802a573d67f8e9b0ba42e54c4a20e935e844febd538752605d3446f",
"outputs/irpc-mrfta/Decreto-9-2008-BR16.pdf6.png": "ae8f0d02c2c01fafd1f390492ecf442defa094edd5612923c5f34b458f6c6392",
"outputs/irpc-mrfta/Decreto-9-2008-BR16.pdf8.png": "6097b3137f22a59c55cf1017643e0be4c0d6ba571e1d3c84331940988a4967b7",
"outputs/irpc-mrfta/dossier.html": "743a1960b2b70dfd4e5231f37bbf0799184f8f9d39c58c7569f66852ad1e3db5",
"outputs/irpc-mrfta/dossier.json": "864a2c9da690b086a2aa7c10ae18549d7d462f43a6f87826e6b1f57d8751e5c0",
"outputs/irpc-mrfta/dossier.txt": "a0473de355821758c4d320eea8e7af76a0d196a9cee652c71af723d6f69832f0",
"outputs/irpc-mrfta/frontend.txt": "707ef1a9c37fbeb53997027c1aff5c3a85c3358e40b3ed63512ddf93ded74b7a",
"outputs/irpc-mrfta/index.html": "6bb76e37ac20a73cb9ffcda14f1ac9db701aa01bc2ef2f62fc5adaaffb640ca8",
"outputs/irpc-mrfta/preparation.html": "c8855ab0bcbaa85e95149ca36d1b035b59a21760d3336c088b552c147eafc330",
"outputs/irpc-mrfta/recovered.json": "f7ef8221ad1ffba237f683eb2333e4bde8b076e00a459c131f8c81c96c3048f5",
"outputs/irpc-mrfta/types.txt": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"outputs/irpc-mrfta/ui-export.html": "c8855ab0bcbaa85e95149ca36d1b035b59a21760d3336c088b552c147eafc330",
"outputs/irpc-mrfta/ui-proof.json": "9d41f8a7f48e0a1f611bd0916e58e9dc6ffaa9760b281f056edbe2ccde115777",
"outputs/irpc-mrfta/ui.png": "ee9e6f5240d1f0b58569609bdb6c0c38a3cd11373db7b6ad0008b15fb229afad",
"outputs/irpc-mrfta/ui.txt": "59df712c7a7873532c4eab94fb582fd1e470803a5da1bfd68c884f8e8ad2386b"
}
}
@@ -0,0 +1,193 @@
{
"status": "QA_grouped_compatible_L5_prepared_not_installed",
"installed_baseline": "5c0cb25cea7826811c389b55a64bcdf5e43b937f",
"previous_QA": "da0d8abb4775a7a68142f84129e312b86dadfe23",
"branch": "codex/irpc-l5-withholdings-qa-20261025",
"authorization": "Tempo:agrupar restantes enquadramentos compatíveis,reutilizar contrapartes/documentos/pagamentos e câmbio entregue;preparar entrega conjunta;manterportal5c/L3/ISPC;sem instalar este incremento.",
"implemented": [
"Firstda0d8abb scope preserved;MZN10%digital/nonresident resultscurrentandunchanged without forcedrecalculation.",
"Ordinary20% qualifiedroyalties/equipment/services/nonlistedcapital;rentstandard20%onaccount;residentroyalties20%onaccount;onlydependentdispensascaseslimited.",
"62(3):20%definitivelisteddebt/Treasuryinterestandbankliquidityswaps with exactnationalheadquarters/effectivemanagementfacts.",
"62(4):10%qualifiedtelecom/internationaltransport/connectedinstallation/aircraftmaintenancecharter/publicruralelectricity/maritimefishingcabotage/otherBMlistedsecurities;notgeneral10%.",
"Expiredagriculturalmeasures31/12/2025 not carriedto2026;source2022gapresolved.",
"ExistingFXselector/selectFx/fxSelectionKey/convertCents reused unchanged through IRPCadapter;originalcurrency/amount,bulletin,column,direction,date andhistory retained.",
"Foreignwithholdingproofcapacityconvertedonce;MZNallocations,sharedpaymentlimits andsourcechangeschecked;ATremittance/beneficiarypaymentnotconfused.",
"Private draft persistence/recovery/report/preparationexport;annualcredits/ATactsnotautomaticallygenerated."
],
"new_source": {
"url": "https://www.cipmoz.org/wp-content/uploads/2023/financas/17F%29%20Lei%2029_2022%20Plano%20Economico%20Social%20Or%C3%A7amento%20do%20Estado%202023.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d",
"pages": 268,
"bytes": 17966640,
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"citation": "BR252/I,30/12/2022,p2731/PDF1,Lei20/2022 arts1/2",
"read_scope": "Full268pages preserved/inventoried;first3pages textread;page1 visuallyreviewed;budgetpages not usedforwithholding",
"provenance": "Original officialBR hostedCIP;acceptance ofofficialsource preserved,no second authenticityvalidation",
"scan": "Not claimed performed;private source archive,not librarypublication/import"
},
"source_mapping_reused": [
"Lei34/2007,62(1)/67/68,PDF17–19",
"Lei19/2013,62(3/4),PDF2/p682(22),visuallyreviewed",
"Lei20/2022,62(1–5),PDF1/p2731,visuallyreviewed",
"Lei12/2025,62(5)/67(5/7),previouslyacceptedBR248/2025PDF19"
],
"runtime_delta": [
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "f10d82f1bf353b1a92c37790b213fad9e769ed39139a99577747ee703be63b49"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "5cffcc26c72ed736e88386589710cf7929ec9bc25f78910648ba676fb1cf4b08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256_LF": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256_LF": "01d20f4761933a3e4dd7c776bd4adcf9610ac0435d918a1998ae9f0c3ce3f234"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256_LF": "df8b224b9472449711d0b69a873fa75f9cc9f4d84dce1a314fc576fae9c6eae2"
}
],
"additional_runtime_since_da0d8abb": [
"resources/js/lib/irpc-withholdings.ts",
"resources/js/components/simulation-irpc-withholdings.tsx",
"resources/js/lib/irpc-fx.ts"
],
"existing_FX_files_unchanged": {
"resources/js/lib/iva-fx-selection.ts": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998",
"resources/js/components/simulation-fx-selection.tsx": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf",
"resources/js/lib/business-financial-plan.ts": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb",
"resources/js/lib/iva-currency-events.ts": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
"previous_resources_unchanged_except_manifest": 438,
"old_original_PDFs_preserved": 26,
"total_source_original_PDFs": 27,
"previous_QA_proofs_reused": {
"new_frontend_distinct": 17,
"frontend": "frontend.txt:16pass;directed-cross-context.txt:1pass",
"API": "1test/23assertions;guardedloopback55441/simulator_fiscal_delta_20261021_test;DatabaseTransactionsrollback;allpreviousL3/ISPCmapsidentical",
"types": "types-final.txt:exit0",
"build": "build-final.txt:exit0",
"UI": "Actualcomponent calculation/save/recover/report andexport;localfileharness distinguishedfromprivateAPI;reuse existingacquisition at373 demonstrated;UI proof reused for unchanged positive route after final shared-payment-key refinement;directed test proves only that delta",
"previous_functional_suites_repeated": false
},
"previous_QA_proof_hashes_reconciled": true,
"verification": {
"new_frontend_distinct": 19,
"frontend_proofs": [
"frontend.txt:17pass;listedcapitalcase superseded bydirectedcapital",
"directed-capital.txt:updatedcapitalcase+1newcasepass",
"directed-report.txt:3affectedreportcasespass",
"directed-fx-origin.txt:1newcasepass"
],
"API": "1test/34assertions;loopback55441/simulator_fiscal_delta_20261021_test;DatabaseTransactionsrollback;acceptedhistory/oldmaps preserved",
"types": "types-final.txt:exit0",
"build": "build-final.txt:exit0",
"UI": "ActualexistingFXpreview/confirmationinsideIRPC,calculation/save/recover/report/export;localfileharness distinguishedfromprivateAPI",
"unaffected_old_functional_suites_repeated": false
},
"example": {
"foreign_royalty": "1000USD×64=64000MZN;20%=12800;ATreceipt5000MZN;balance7800MZN;FXdate20Oct vs costevent2Oct",
"special_telecom": "100000MZN;qualified62(4)a10%=10000;notdigital62(5)",
"resident_royalty": "50000MZN;20%=10000;onaccount,notannualcredit",
"foreign_withholding_proof": "100USDbase→6400MZN;tax1280;10USDproof→640MZN;difference640MZN"
},
"remaining_calculations_and_specific_mapping": [
{
"item": "Dispensas68 e casos residentes/EP dependentes",
"data_needed": "Titular/operação e condições de68(a/b/c/d/f/g),incluindo gestão de imóveis próprios/transparência,participações e tipos de juros;casos digitais residentes/EP confrontados com62(5)/68(d).",
"resolution": "Ramo específico por dispensa/factos;não bloquear royalties comuns,retenções definitivas ou especiais independentes."
},
{
"item": "Convenções/benefícios invocados",
"data_needed": "País/convenção/artigo,beneficiário,residência,condições/período e prova invocados",
"resolution": "Só esse caso fica indeterminado;sem taxa reduzida presumida."
},
{
"item": "Outros rendimentos/devedores/períodos",
"data_needed": "Artigo próprio para categorias fora dos ramos agrupados,via devedorIRPS,anos fora2026,EP de categorias especiais62(4)quando não cabe62(2)",
"resolution": "Não aplicar20%ou10%genéricos;avançar os casos compatíveis."
},
{
"item": "Juros,rectificações e arredondamento de entrega",
"data_needed": "Regra/taxa/base/período dejuros,declaração/guia anterior,documentos de correcção e regra de arredondamento legal da entrega se aplicável",
"resolution": "Aritmética exacta preservada;aproximação assinalada;sem zero dejuros ou crédito anual automático."
},
{
"item": "EntregaAT com comprovativo em moeda estrangeira",
"data_needed": "MontanteMZN efectivamente entregue no comprovativo;conversão do pagamento ao beneficiário não prova entregaIRPC",
"resolution": "Base e comprovativo de retenção sofrida já convertem pelo mecanismo entregue;esta limitação não reabre o câmbio geral."
}
],
"external_formalities": [
{
"item": "MRFTA/CER e remissão67(7)",
"data_needed": "Correspondência concreta de rubricas/CER para novos casos;67(7)refere62(6),nova taxaestá62(5);manteroriginal",
"resolution": "Preparação/exportação disponível;sem adivinhar código,assinatura ou submissão."
},
{
"item": "ActosAT",
"data_needed": "Submissão,recepção,aceitação e eventuais comprovativos externos",
"resolution": "Externos;exportar não executa nem certifica esses actos."
}
],
"currency_gap_previous": "Resolvedforbaseandforeignwithholdingproofbyexistingoperationalmechanism;no newselector ormeanformula. ATremittanceamount remainsactualdocumentedMZN.",
"new_organizational_restrictions": false,
"restriction_origin": "Tempoexpressedreuse;legalrates/conditionsfromacceptedBR;optionaltypedlinks/fingerprints aretechnicalchoices,notnewapprovers.",
"L3_ISPC": "Preserved;ISPCinterest/otherexcess/instructionsinexistingmatrix;IRPSstillonlypreviousdemonstratedcase;P001/P058nonblocking;P084/P085closed;statistics/AIdeferred.",
"L5_integrally_completed": false,
"IRPC_integrally_completed": false,
"IRPS_integrally_completed": false,
"schema_backend_config_dependency_changes": false,
"active_changes": false,
"execution_remaining": [
"Authenticatedfreshdestinationcomparison,backupandisolatedrestorebeforeinstallation.",
"FastforwarddeliverybyexistingGitprocessafterfreshguards;nevermergerootP001experimentalruntime.",
"Verifyinstalledruntime/compiledmarkers/persistentfiles/configuration/schema/permissions/dataunder equivalentidentity;reuseacceptedfunctionalproofs."
],
"compiled_markers": {
"Calcular e guardar retenções IRPC": [
"assets/services-Es7_7t9u.js"
],
"Base do rendimento/conversão por resolver:": [
"assets/project-dossier-DZQJzKcc.js"
],
"Retenção liberatória20%62(3)a/b": [
"assets/project-dossier-DZQJzKcc.js"
],
"Reutilizar selecção cambial": [
"assets/services-Es7_7t9u.js"
],
"Calcular e guardar apuramento trimestral ISPC": [
"assets/services-Es7_7t9u.js"
],
"Calcular e guardar restituição E": [
"assets/services-Es7_7t9u.js"
]
},
"active_readonly_revision": {
"commit": "5c0cb25cea7826811c389b55a64bcdf5e43b937f",
"branch": "main",
"built_at": "2026-10-25T16:24:27.707113+00:00",
"manifest_sha256": "385a289f9ba26a632aa0164fbba3913cc8dc2fb891641881fc8d2dcda1951626"
},
"proof_hashes": {
"outputs/irpc-l5-grouped-20261025/preservation-before-tests.json": "ab8a892a14cd7cac916cbda51c1904eae87f3008d5f2e41d65494abb09e25dd8",
"outputs/irpc-l5-grouped-20261025/frontend.txt": "1939704865fc1f963adf4616837b615aeb5dfb7d5fa1567b8dc9d978bd39299a",
"outputs/irpc-l5-grouped-20261025/directed-capital.txt": "ba5dbd9d0047decb36e646f6152258552f0a36e34141b60070e0c36e41b4d610",
"outputs/irpc-l5-grouped-20261025/directed-report.txt": "2bc8ac7c9e5bfdfe18a59eb3e0eb7e2450c9ae0cb211efb4e07752851c5250a7",
"outputs/irpc-l5-grouped-20261025/directed-fx-origin.txt": "121c998e6d95820b8d6dda8fc09dc9d190416d3f64e5fc8dfed6df78dd18e523",
"outputs/irpc-l5-grouped-20261025/api.txt": "58365c069bb4c5d7bc91c24834575c19e1458049b73f5b42e9b1e543cd2b4944",
"outputs/irpc-l5-grouped-20261025/types-final.txt": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
"outputs/irpc-l5-grouped-20261025/build-final.txt": "db910282d69133fbdaee6c5d22b0397d377ed0b652072094be0a165884d97fba",
"outputs/irpc-l5-grouped-20261025/ui-fx-preview.txt": "a5ddc73db4cf9a8424ce0a8fcec9da55d8828f2cb13faf9f8715c0bcd6074523",
"outputs/irpc-l5-grouped-20261025/ui-report.txt": "0561e14566e4b9b4ab333c5c2a13b03f055c4ae413d3f9d211e663f2da38a7b5",
"outputs/irpc-l5-grouped-20261025/preparation.html": "c3c3e8df77e3f22e34e0cfbd2a8cc04a7d3cdc2e7080a0a70415f8f1c661818b",
"outputs/irpc-l5-grouped-20261025/active-baseline.json": "2f2d1a9d3e311f12099d2372d0c1a01eb5ff3918a39218c73b668dfbe51c66f8"
}
}
@@ -0,0 +1,22 @@
{
"status": "directed_presentation_delta_passed",
"base": "4d6f8282302c7646bd7350b8d67695d005feab9a",
"authorization": "Tempo:each calculation identifiesincomeclassification,rateanddefinitive/onaccountnature.",
"changed_runtime": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "919a6b7427fcbf67976797358dde0d02a3aba1121bb827b17280b13c0ddc3bd4",
"arithmetic_input_persistence_logic_changed": false,
"verification": {
"presentation": "1newdirectedtest;all6savedcases showcategory/rate/nature inPortuguese;frozendataunchanged",
"affected_export": "1existingexportcase;obsoleteEnglishlabelassertionupdated",
"types": "exit0",
"build": "exit0"
},
"proof_hashes": {
"presentation.txt": "7b348f1e6d64ac0e5cab732175e69fa32154db504e7781c028ced14ec703aaf8",
"export-presentation.txt": "54ada0166f309a216fdbc294bcee98283392b09a2d20a6b2718f2584fb78a133",
"types.txt": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
"build.txt": "2291bfc0b02957632c92a3a39215c35931a469eba4548473db4de26135468eed"
},
"other_accepted_proofs": "Reused;no new calculationround.",
"active_changes": false
}
@@ -0,0 +1,521 @@
{
"status": "installed_scoped_IRPC_reliefs_delta_verified",
"candidate_installed": "ce746d889d5711f23f4e0ac8d9802997b5e106f9",
"previous_installed": "2b33a1c343d192f80fb24aac2a27b2d375af5601",
"previous_release_preserved": "/var/www/investmoz-homologacao/releases/2b33a1c343d192f80fb24aac2a27b2d375af5601-23fd8416",
"authorization": "Tempo: disponibilizar entrega conjunta via Git,backup/restauro fresco e conferência do delta;preservar2b33a1c3,L3,ISPC,câmbio;L5 parcial.",
"fresh_backup": {
"stage": "/var/backups/investmoz-irpc-reliefs-delivery-20261025/backup",
"created_at": "2026-10-25T18:00:39Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "3dc0eeea326beff9a7780f3a11ef1ed23a58dbaab8382db975ddfb356d6206c8",
"files_sha256": "d0dc27540dd41131c0fbf923b15b05fefc81760d80bfb0bd8ce04bf80ec9eb50",
"restore_verified": false
},
"isolated_restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l5_restore_20261025",
"port": 55441,
"source_dump_sha256": "3dc0eeea326beff9a7780f3a11ef1ed23a58dbaab8382db975ddfb356d6206c8",
"active_database_writes": 0
},
"preflight": {
"free_bytes": 6596661248,
"existing_pipeline_minimum_bytes": 5368709120,
"space_guard_satisfied": true,
"installed": {
"status": "installed",
"commit": "2b33a1c343d192f80fb24aac2a27b2d375af5601",
"release": "/var/www/investmoz-homologacao/releases/2b33a1c343d192f80fb24aac2a27b2d375af5601-23fd8416",
"previous_release": "/var/www/investmoz-homologacao/releases/5c0cb25cea7826811c389b55a64bcdf5e43b937f-32c4fd00",
"database_migrations": 0,
"content_imports": 0
},
"current_link": "/var/www/investmoz-homologacao/releases/2b33a1c343d192f80fb24aac2a27b2d375af5601-23fd8416",
"release_revision": {
"commit": "2b33a1c343d192f80fb24aac2a27b2d375af5601",
"branch": "main",
"built_at": "2026-10-25T17:27:10.176918+00:00",
"manifest_sha256": "75b06330161a813a10e3eb3a044e2ba4a924537dae381f97d0c8d4ee7295295a"
},
"service": "ExecMainStatus=0\nActiveState=inactive\nSubState=dead\n",
"configuration_keys": [
"repository",
"branch",
"target_url",
"legacy_root",
"state_root",
"release_root",
"current_link",
"shared_assets",
"php",
"schema_contract",
"ci_environment",
"postgis_image",
"test_database",
"qa_port",
"retention",
"webhook_secret_file"
],
"safe_paths": {
"repository": "nala/Investidor-V2",
"release_root": "/var/www/investmoz-homologacao/releases",
"postgis_image": "postgis/postgis@sha256:01a6a70e41e6c4467c8f55f6063555ed72db2d6662cd0d571040d42eadaeb6f6"
},
"pipeline_sha256": "adec1c17654f3a8658b83b134f1e75f95391b235738552721906c3236e388604"
},
"protected_delta": {
"previous_release_preserved": "/var/www/investmoz-homologacao/releases/2b33a1c343d192f80fb24aac2a27b2d375af5601-23fd8416",
"installed": {
"status": "installed",
"commit": "ce746d889d5711f23f4e0ac8d9802997b5e106f9",
"release": "/var/www/investmoz-homologacao/releases/ce746d889d5711f23f4e0ac8d9802997b5e106f9-5fdb1b51",
"previous_release": "/var/www/investmoz-homologacao/releases/2b33a1c343d192f80fb24aac2a27b2d375af5601-23fd8416",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 4,
"preserved_L3_ISPC_FX_runtime_files_verified": 28,
"documentary_files_verified": 29,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 106,
"checksum": "df13c9623faded047b71df595d350ec7"
},
"after": {
"rows": 106,
"checksum": "cf7d9fdcfb64c81360cce81a5fa8c45d"
}
},
"sessions": {
"before": {
"rows": 15,
"checksum": "2c17940b66d6fd97d011edabbbf9ec47"
},
"after": {
"rows": 16,
"checksum": "4b7ab676493d6d1892d9933b3fde1780"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"schema_permissions": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart value/expiry and request-throttle counter/timer pair;no deleted cache rows",
"sessions": "anonymous sessions created by exact delivery verification user-agent",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "8d6ea77eb4b34d86d207362d583cfa8bf2880b907becd9b00398964482c6b4bd",
"kind": "updated",
"fields": [
"expiration"
],
"key_pattern": "investemoz-cache-{hash}",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "2f251473865d14b953236ab95b1521764754d76abd79b58ca7d38c96dfe2fab1",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-{hash}:timer",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false
}
]
},
"sessions": {
"before_rows": 15,
"after_rows": 18,
"changes": [
{
"key_sha256": "4dd9d761c194f0c736e2b800add6792a790734c947d6de06bb7d91dc8778ec3b",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "93dba7d9de797b0301f4395afa891df1c9803a7abbd2f5c083ebb4a01569f75e",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "0208243bb27c67eee43773c1d4f3df5a1df5a24af6402a68de18bb518ce27beb",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"public_delta": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "ce746d889d5711f23f4e0ac8d9802997b5e106f9",
"branch": "main",
"built_at": "2026-10-25T18:06:03.871601+00:00",
"manifest_sha256": "feb2dce3fc8845c6307c982323b3e3523b333a018189c47488f9fcba25490555"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"Calcular e guardar retenções IRPC": [
"assets/services-rCdKRO1R.js"
],
"Dispensa de retenção": [
"assets/project-dossier-I7GMfANo.js",
"assets/services-rCdKRO1R.js"
],
"Limite convencional": [
"assets/project-dossier-I7GMfANo.js"
],
"Portugal–Moçambique — royalties, artigo 12": [
"assets/project-dossier-I7GMfANo.js"
],
"Informação insuficiente: documente residência convencional": [
"assets/project-dossier-I7GMfANo.js"
],
"Calcular e guardar apuramento trimestral ISPC": [
"assets/services-rCdKRO1R.js"
],
"Calcular e guardar restituição E": [
"assets/services-rCdKRO1R.js"
],
"Reutilizar selecção cambial": [
"assets/services-rCdKRO1R.js"
]
},
"assets": [
{
"file": "assets/simulation-form-BqVD91Ek.js",
"status": 200,
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
},
{
"file": "assets/project-dossier-document-CR2W33oB.js",
"status": 200,
"sha256": "d5e23e7b8da99bdf4368991f54c6d4d5a12c206a18eeef754f0bc0f68183865c"
},
{
"file": "assets/project-dossier-I7GMfANo.js",
"status": 200,
"sha256": "2e5134e2163dbd23a83374d9e06e2ed68b3e37009f3ed07e97af7aa34f97e8ca"
},
{
"file": "assets/services-rCdKRO1R.js",
"status": 200,
"sha256": "ecd38dd17a4b371f2bc55167887206a98db8f066e6ab3f66b7a0b1938fdcf49d"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-GOBc44N3.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"runtime_delta": [
{
"path": "resources/js/lib/irpc-relief-preparation.ts",
"sha256_LF": "e41a389ad0b5d3f33985e375b0c488eed8c2d185257eec1cf5f7d40fccd365d4"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "75bf1c5940595e90d7a27355aeae6f9fdca4841f3e9ce3cb02103376bbd4d91b"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "28dd35e40c5d8440adad01131714d324f0c7fcdfeb3f6ddd9d27750d563b5e4f"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256_LF": "4523365e2d4a2fcd014e13393deb33a5ec4b9396ff580d8a237aa8c4f02265e4"
}
],
"preserved_runtime": [
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256": "01d20f4761933a3e4dd7c776bd4adcf9610ac0435d918a1998ae9f0c3ce3f234"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256": "df8b224b9472449711d0b69a873fa75f9cc9f4d84dce1a314fc576fae9c6eae2"
}
],
"accepted_QA_proofs_reused": {
"routes": "normal Wayfinder generate --with-form through guarded QA wrapper",
"types": "tsc --noEmit passed",
"build": "complete QA build passed; existing optional-font/chunk-size notices only",
"frontend": "9 new tests passed",
"compatibility": "5 directed IRPC cases passed;no repeated L3/ISPC/FX suites",
"api": "1test/17assertions;private endpoints;55441/simulator_fiscal_delta_20261021_test;DatabaseTransactions rollback",
"report": "retentions preparation and financial dossier from actual API recovered sample",
"ui": {
"calculation": true,
"localSaveRecovery": true,
"privateApiProof": "IrpcReliefsDraftTest, separate",
"report": true,
"insufficientInformation": true,
"errors": []
}
},
"installer_report": {
"status": "installed",
"commit": "ce746d889d5711f23f4e0ac8d9802997b5e106f9",
"release": "/var/www/investmoz-homologacao/releases/ce746d889d5711f23f4e0ac8d9802997b5e106f9-5fdb1b51",
"previous_release": "/var/www/investmoz-homologacao/releases/2b33a1c343d192f80fb24aac2a27b2d375af5601-23fd8416",
"database_migrations": 0,
"content_imports": 0,
"requested_commits": [
"ce746d889d5711f23f4e0ac8d9802997b5e106f9"
],
"finished_at": "2026-10-25T18:06:07.393002+00:00"
},
"space": {
"status": "dependencies_archived_and_verified",
"versions": 5,
"free_before": 5281300480,
"free_after": 6596743168,
"receipt": "/var/backups/investmoz-build-dependencies-irpc-reliefs-20261025/receipt.json",
"protected": [
"/var/www/investmoz-homologacao/releases/2b33a1c343d192f80fb24aac2a27b2d375af5601-23fd8416",
"/var/www/investmoz-homologacao/releases/5c0cb25cea7826811c389b55a64bcdf5e43b937f-32c4fd00"
],
"active_or_previous_release_modified": false,
"source_data_backups_deleted": 0
},
"remaining": [
"Other68paragraphs and digital/resident-specific cases",
"Other countries,treaties,EP-related and special-relationship excess cases",
"Dividends,interest-specific treaty branches",
"Late-payment interest,rectifications,aggregation,MRFTA/CER/form filling",
"External treaty claiming formalities are not declared satisfied by this calculation"
],
"database_migrations": 0,
"content_imports": 0,
"L5_integrally_completed": false,
"scope": "Only demonstrated68d/68f and qualifiedPT-MZ12royalties/equipment;nextinterest/MRFTAincrementstaysQA",
"evidence": {
"backup.txt": "53019c43c14005ca429e747a38d909b175218490add7fa416d7b3c387211db3b",
"compact-dependencies.txt": "4f087279b4760e71de0621da342d2dea14dbf38272816e938d5b9e6c171afe1d",
"installed-protected.txt": "0dff5ae05c6e73542c99fa14f0c06fcf87e7c096d29ff80b1517d21b57404504",
"installed-public.txt": "ae35a04719d1f05478b4936d4d563f9050c47f1db7d9b69610322e7653878858",
"integration.txt": "1c4d1be9b3a758a39529c69ebf87eda0b2dea36aef7622ba550ca7021dc41b6f",
"operational-delta.txt": "711f26fd0e56b8b52cef90d6245bbf32f7ec1758f5af8fcb8112241a919dbd94",
"preflight.txt": "90411a15339db664782a58139072c0fec52331d5a336348d260d6e336f2d299e",
"restore.txt": "a199e138c500d1f94da75ab38022932aa37232585ca2a6914eaf1dea91accf1a",
"schema-permissions-after.txt": "76b5a4d8af11e4898a205062766cfb7ab6ec0783200e77e60a1927aa1ca18597",
"schema-permissions-before.txt": "0ab7c964792acdd8917bce256c472e55e034b103500a58b49f020b5084823ed7",
"status1.txt": "595260a11ec30b4e7ef3e2a2aad11a178077283300f3572270a8d104307fe3ad",
"status2.txt": "4de7380a350e99585cbeea3646331759892b469aae5fd121effdb4f18fa39922",
"status3.txt": "49c26c68447722bfafed48930cd7cf0da62a088d2f66c05b3ef0ed90c3dc32b8",
"status4.txt": "7cbb15d32c6b6455b60df644f045880854c7acc4e21dfce0dd77e0df88c2a97e",
"status5.txt": "7cbb15d32c6b6455b60df644f045880854c7acc4e21dfce0dd77e0df88c2a97e",
"status6.txt": "a1224e56d81b8fbed83555dd413084cb9fff74a6b4f88960ea83ee6faec09f2f",
"status7.txt": "e2b53e3916f2a77a530f663d971d66fe495aefd1159d37b4e7c595dd93f3bf0c"
}
}
@@ -0,0 +1,330 @@
{
"status": "QA_demonstrated_grouped_candidate_not_installed",
"baseline_reported_installed": "2b33a1c3",
"branch": "codex/irpc-l5-reliefs-qa-20261025",
"implemented": [
"CIRPC68d qualified on-account services/equipment",
"CIRPC68f own-property management,not fiscal transparency",
"PT-MZ12 qualified royalties/equipment10%gross definitive",
"Insufficient/contradictory/out-of-period evidence remains indeterminate",
"Private API persistence,recovery,history;standalone report and complete financial dossier",
"IRPC dossier section association restored"
],
"runtime_delta": [
{
"path": "resources/js/lib/irpc-relief-preparation.ts",
"sha256_LF": "e41a389ad0b5d3f33985e375b0c488eed8c2d185257eec1cf5f7d40fccd365d4"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "75bf1c5940595e90d7a27355aeae6f9fdca4841f3e9ce3cb02103376bbd4d91b"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "28dd35e40c5d8440adad01131714d324f0c7fcdfeb3f6ddd9d27750d563b5e4f"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256_LF": "4523365e2d4a2fcd014e13393deb33a5ec4b9396ff580d8a237aa8c4f02265e4"
}
],
"verification": {
"routes": "normal Wayfinder generate --with-form through guarded QA wrapper",
"types": "tsc --noEmit passed",
"build": "complete QA build passed; existing optional-font/chunk-size notices only",
"frontend": "9 new tests passed",
"compatibility": "5 directed IRPC cases passed;no repeated L3/ISPC/FX suites",
"api": "1test/17assertions;private endpoints;55441/simulator_fiscal_delta_20261021_test;DatabaseTransactions rollback",
"report": "retentions preparation and financial dossier from actual API recovered sample",
"ui": {
"calculation": true,
"localSaveRecovery": true,
"privateApiProof": "IrpcReliefsDraftTest, separate",
"report": true,
"insufficientInformation": true,
"errors": []
}
},
"preserved_FX_files": [
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256_LF": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256_LF": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256_LF": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256_LF": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256_LF": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
}
],
"sources_inventory": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973",
"bytes": 308401
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c",
"bytes": 159748
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57",
"bytes": 319577
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b",
"bytes": 256695
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee",
"bytes": 2267865
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
"bytes": 440018
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5",
"bytes": 9456358
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358",
"bytes": 329070
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d",
"bytes": 17966640
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5",
"bytes": 905551
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb",
"bytes": 665722
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8",
"bytes": 590418
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be",
"bytes": 135471
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c",
"bytes": 730017
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697",
"bytes": 900370
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b",
"bytes": 2127554
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56",
"bytes": 1604284
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4",
"bytes": 1603184
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a",
"bytes": 1990307
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76",
"bytes": 147521
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d",
"bytes": 1894997
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899",
"bytes": 161625
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53",
"bytes": 1834284
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e",
"bytes": 1676884
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e",
"bytes": 186487
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121",
"bytes": 187572
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d",
"bytes": 309350
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d",
"bytes": 199331
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b",
"bytes": 197027
}
],
"new_sources": [
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d",
"bytes": 199331,
"url": "https://dcjri.ministeriopublico.pt/sites/default/files/documentos/instrumentos/rar36-1992.pdf"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b",
"bytes": 197027,
"url": "https://files.dre.pt/1s/2009/05/08900/0275202756.pdf"
}
],
"remaining": [
"Other68paragraphs and digital/resident-specific cases",
"Other countries,treaties,EP-related and special-relationship excess cases",
"Dividends,interest-specific treaty branches",
"Late-payment interest,rectifications,aggregation,MRFTA/CER/form filling",
"External treaty claiming formalities are not declared satisfied by this calculation"
],
"active_changes": false,
"active_verification": "No fresh live inspection claimed;2b33a1c3 remains last reported installation",
"schema_config_permissions_delta": false,
"L5_integrally_completed": false,
"L3_ISPC_FX": "Unchanged;accepted proofs reused;no repeated functional suites",
"installation_remaining": "Existing Git release process,destination comparison and fresh backup/restore safeguards at installation",
"proofs": [
{
"path": "outputs/irpc-reliefs/api.txt",
"sha256": "5cccf4ee4e62ae00ef85276d48482fa8c13e202ddf68b6d79b1948977fb1f597"
},
{
"path": "outputs/irpc-reliefs/build.txt",
"sha256": "c60d4a5285f57a6458285163f64279d87558a8119f9b386cad8d12861d49e025"
},
{
"path": "outputs/irpc-reliefs/calculated.json",
"sha256": "563e05189c0a1255bf071fd1086aa8e67d6f0872891c5851dccbfc0d944752fe"
},
{
"path": "outputs/irpc-reliefs/compatibility.txt",
"sha256": "f37ad0ac9a0f2675fa4199f7600f3ae4e5a2df35a7294fe6e5aefd8024344051"
},
{
"path": "outputs/irpc-reliefs/dossier.html",
"sha256": "a34c2e9ef8b4d202e23412aaf6862ef9d603efeee0518a16adeb9d895f775641"
},
{
"path": "outputs/irpc-reliefs/dossier.json",
"sha256": "717561321d4b6c7659f0e6ab82c0e411ada0002a4f5436ba42092f8002f96076"
},
{
"path": "outputs/irpc-reliefs/dossier.txt",
"sha256": "a0473de355821758c4d320eea8e7af76a0d196a9cee652c71af723d6f69832f0"
},
{
"path": "outputs/irpc-reliefs/frontend.txt",
"sha256": "f86464b0d6a36ccfc39e22c0616d4a2e4f657126da134cb2014fcc199a11bdf2"
},
{
"path": "outputs/irpc-reliefs/index.html",
"sha256": "6bb76e37ac20a73cb9ffcda14f1ac9db701aa01bc2ef2f62fc5adaaffb640ca8"
},
{
"path": "outputs/irpc-reliefs/Lei-19-2013-BR76.pdf-review.png",
"sha256": "b62716ed89669622a33bde81a5ab6dcf0a6faafaf41726a09cd5b473b59abab1"
},
{
"path": "outputs/irpc-reliefs/Lei-34-2007-BR52.pdf19.png",
"sha256": "8355aa0b103439bb2b652b8499b2abf9bee1e4f3cc1af54b1be3ea059a2384f4"
},
{
"path": "outputs/irpc-reliefs/Lei-4-2012-BR3.pdf-review.png",
"sha256": "207224d8712713c9f4c5dda4e61539eba28f37af1ec70ef139cff0b450a62b2e"
},
{
"path": "outputs/irpc-reliefs/preparation.html",
"sha256": "2943b6cd21cc4ac043ae9b0605aee23c0fbbbed552842aeafef187ff963389a1"
},
{
"path": "outputs/irpc-reliefs/protocol-page1.png",
"sha256": "d981c72e254239c911554ff1289b578f7136bae7964a3d53f76a69094186cc04"
},
{
"path": "outputs/irpc-reliefs/PT-MZ-CDT-1992.pdf13.png",
"sha256": "2a57bc9924c0c826452bbc7f097b48c1899e6b642d6cdc247c244ace8993bb96"
},
{
"path": "outputs/irpc-reliefs/PT-MZ-CDT-1992.pdf14.png",
"sha256": "9fd31dcf17bdd1526390758a48a5afa8f9b98aebd83209b962ea97b7deef4006"
},
{
"path": "outputs/irpc-reliefs/PT-MZ-Protocolo-2009.pdf-review.png",
"sha256": "ba5ad799456a16959b83878c8935eb326ec3f0d87a2ba32e43217411e3f0dac9"
},
{
"path": "outputs/irpc-reliefs/recovered.json",
"sha256": "0b2378d1b8232b1424cf3d13e199146f4eabc330b9750a74b2b59f172741515e"
},
{
"path": "outputs/irpc-reliefs/types.txt",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
},
{
"path": "outputs/irpc-reliefs/ui-proof.json",
"sha256": "274ffe6c237da799aceff79df76087cf17f2a83505755aa6354d90b9d1f85abb"
},
{
"path": "outputs/irpc-reliefs/ui.png",
"sha256": "55df91c9dfc9a028eceafaf0b55b4ad2df892da491f8ac97d5d8edaacea73a4e"
}
]
}
@@ -0,0 +1,200 @@
{
"status": "QA_first_scoped_increment_not_installed",
"base_installed": "5c0cb25cea7826811c389b55a64bcdf5e43b937f",
"branch": "codex/irpc-l5-withholdings-qa-20261025",
"L5_integrally_completed": false,
"IRPC_integrally_completed": false,
"IRPS_integrally_completed": false,
"scope": "Shared counterpart/document reuse;2026event chronology;10% digitalgoods/services/emoneycommission,nonresident nonattributabletoEP with explicit IRPCpayer/recipient/Mozambiquesource and no invokedspecialrelief;withheld/remitted/proven amounts separate;private draft persistence/recovery/report/preparationexport.",
"sources": [
{
"file": "Lei-34-2007-BR52.pdf",
"url": "https://www.dlapiperafrica.com/export/sites/africa/mozambique/insights/legislation-series/tax/downloads/Lei_34_2007.pdf_2063068952.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e",
"pages": 22,
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"usage": "Art67(3)/68 visually reviewed onPDF19;other text identified"
},
{
"file": "Lei-4-2012-BR3.pdf",
"url": "https://www.dlapiperafrica.com/export/sites/africa/mozambique/insights/legislation-series/tax/downloads/Lei-n-4.2012-de-23-de-Janeiro-de-2012.pdf_2063068952.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121",
"pages": 3,
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"usage": "Original inventoried/preserved;full article mapping not yet complete,no rate activated from this copy"
},
{
"file": "Lei-19-2013-BR76.pdf",
"url": "https://www.dlapiperafrica.com/export/sites/africa/mozambique/insights/legislation-series/tax/downloads/Lei-n_19.2013.pdf_2063068952.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76",
"pages": 2,
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"usage": "Original inventoried/preserved;full article mapping not yet complete,no rate activated from this copy"
},
{
"file": "Decreto-9-2008-BR16.pdf",
"url": "https://www.dlapiperafrica.com/export/sites/africa/mozambique/insights/legislation-series/tax/downloads/Decreto_9_2008.pdf_2063068952.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697",
"pages": 11,
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"usage": "Original inventoried/preserved;full article mapping not yet complete,no rate activated from this copy"
},
{
"file": "AT-MRFTA-19-39.pdf",
"url": "https://www.at.gov.mz/api/webdav?path=%2FFORMULARIOS%2FIMPOSTOS%20FISCAIS%2FIRPS%2FIRPS-IRPC%20MRFTA%20-%2019-39.pdf",
"pages": 2,
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b",
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"usage": "MRFTA p1–2 visually reviewed;consultation/preparation,not submission"
}
],
"existing_2026_source": {
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251",
"citation": "Lei12/2025 PDF18–20;p2180(18–20);PDF19visually reviewed via identical text in received4pageexemplar;62(5),67(5/7)"
},
"excluded_legacy_sources": [
{
"file": "IRPColectivas.pdf",
"sha256": "06b1ac1310e973c2cc0406396177f9182922988b2ce4f95786f128c8310f907f",
"reason": "Decreto21/2002 revogadoLei34/2007 art3;consultation only,not2026calculation"
},
{
"file": "BR252-2022.pdf",
"sha256": "3339f1a11099466b01bf7b9024ff36266d056e6a914d1fa67f6b60f0e9f12f2b",
"reason": "Filename identifiesdate/issue butactual3rdsupplementDecree74/2022 tourism;notLei20/2022"
}
],
"inventories_reused": [
"8143localaccessiblefiles",
"39ATforms and189ATlegislation:all inventoriedbeforeselection",
"existingModelosinventory andIRPC_IRPSM39structure;no new workbook formulas trusted"
],
"runtime_delta": [
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "7a2f92695d5732c3c3525f70f23598bbfd9ab0346429e2997c9e07e324106eb5"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "e513e9ee9318d71fb4cc40b8b132e6bb5fc6cf88746061fff8c537cb5e88291a"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256_LF": "01d20f4761933a3e4dd7c776bd4adcf9610ac0435d918a1998ae9f0c3ce3f234"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256_LF": "df8b224b9472449711d0b69a873fa75f9cc9f4d84dce1a314fc576fae9c6eae2"
}
],
"existing_integrations_additions_only": {
"resources/js/components/simulation-form.tsx": 2,
"resources/js/lib/project-dossier.ts": 2
},
"unchanged_previous_resources": 438,
"previous_original_PDFs_preserved": 21,
"new_PDFs_preserved": 5,
"verification": {
"new_frontend_distinct": 17,
"frontend": "frontend.txt:16pass;directed-cross-context.txt:1pass",
"API": "1test/23assertions;guardedloopback55441/simulator_fiscal_delta_20261021_test;DatabaseTransactionsrollback;allpreviousL3/ISPCmapsidentical",
"types": "types-final.txt:exit0",
"build": "build-final.txt:exit0",
"UI": "Actualcomponent calculation/save/recover/report andexport;localfileharness distinguishedfromprivateAPI;reuse existingacquisition at373 demonstrated;UI proof reused for unchanged positive route after final shared-payment-key refinement;directed test proves only that delta",
"previous_functional_suites_repeated": false
},
"examples": {
"retained": "base100000;10%;tax10000;remittance6000;outstanding4000;cost2026-10-02beforepayment2026-11-03=>period2026-10",
"suffered": "base20000;tax2000;documentedwithholding1500;difference500notannualcredit"
},
"remaining_calculations_and_mapping": [
{
"item": "Taxas normais e especiais dos demais rendimentos",
"needed": "Corresponder62(1–4)/67 por rendimento e período,com alterações20/2009,4/2012,19/2013 e20/2022. Ficheiro local BR252/2022 contém apenas3.ºsuplemento/Decreto74/2022,semLei20/2022;INM identifica esta na p2731. Texto exacto em falta não é revalidação de autenticidade.",
"resolution": "Implementar ramo dirigido após correspondência do texto aplicável;não usar2002 ou taxa genérica."
},
{
"item": "Residentes/EP e dispensa68",
"needed": "Corresponder62(5) novo com dispensas68,em especial68(d),titular/rendimento imputável aEP e factos de cada dispensa;sem confundir taxa com obrigação de reter.",
"resolution": "Ramo próprio por natureza/dispensa;sem presumirretenção10%ouzero."
},
{
"item": "Convenções/benefícios",
"needed": "Convenção invocada,artigo,residência,beneficiário,condições,período e documento aplicável",
"resolution": "Só o caso dependente permanece indeterminado;nenhuma taxa reduzida sem esses elementos."
},
{
"item": "Conversão cambial",
"needed": "Moeda,montante,data,taxa efonte aplicáveis à operação",
"resolution": "Conversão rastreável;sem taxa actual nem relabelagemMZN."
},
{
"item": "Juros/regularizações/guia agregada",
"needed": "Regra/taxa/base/período próprios;guias/declarações anteriores e pagamentos para substituições",
"resolution": "Não substituir juros porzero;preparação actual não é declaração rectificativa nem liquidação anualIRPC."
}
],
"external_formalities": [
{
"item": "MRFTA19/39:rubricas eCER digitais/moeda electrónica",
"needed": "Correspondência da nova categoria62(5)a/b às rubricas/CERdo quadro7;remissão67(7)para62(6)existe no original,masnova taxa aparece62(5).",
"resolution": "Preservar divergência e original;não renumerar,adivinharCERou bloquear cálculo positivo independente."
},
{
"item": "GuiaM39 anterior eMRFTAactual",
"needed": "Manter exemplares;instruçõesMRFTAidentificamperíodoúnico e prazonominaldia20mêsseguinte àdedução;calendário/prorrogação eprocedimento2026específico nãoinferidos",
"resolution": "Mapa de preparação/exportação;sem preenchimentofinalCER,assinaturaouusodosserviços."
},
{
"item": "ActosAT",
"needed": "Submissão,recepção,aceitação eeventualcomprovativo externo",
"resolution": "Externos aoportal;exportar nãoexecuta nemcertifica estes actos."
}
],
"preservation": "L3/ISPCbooks unchanged;131L1closures preserved;P001/P058nonblocking;P084/P085closed;statistics/AIdeferred. ISPCinterest/otherexcess/forminstructionsremaininexistingmatrix;IRPSlimitedpriorcase.",
"technical_choices": "Snapshotversion1 extension,exactfractions,source fingerprints andsharedpaymentdependencies areimplementationchoices;notnewTempoapprovals. ExistingIVApayments remainboundtoIVA;newIRPCproofregisteredonce/reusedwithoutoverallocation;noautomaticannualcredit.",
"schema_backend_configuration_dependency_changes": false,
"active_changes": false,
"proof_hashes": {
"outputs/irpc-l5-20261025/preservation-before-tests.json": "bd4ac1ee0e0d892b204f30baeed8842d00787d4b1f20656479e11ccafaca279f",
"outputs/irpc-l5-20261025/frontend.txt": "40bfc0c12fbf5b1f690a7a12570fbdc390f039b9ac845bab4bbddca622bbbcee",
"outputs/irpc-l5-20261025/directed-cross-context.txt": "5303e16fb702f8e022ac694965345d2388779af278844a7262d66bcbc630fd16",
"outputs/irpc-l5-20261025/api.txt": "f2ec740d0df65c8336abcbea48bf49eecb8bfcc1c70440ba7a8b27d24707d9f3",
"outputs/irpc-l5-20261025/types-final.txt": "5346ac8a6566c1c38cb0bbda6a029579df58cd78af78e2c4845d9c82b5d1d76c",
"outputs/irpc-l5-20261025/build-final.txt": "28b7601fefa8d992c9ff7dcf95465a84358381d073dc5f537e37d9a48ae36d9e",
"outputs/irpc-l5-20261025/ui-report.txt": "545f5fdaabd96e5dad996e6992e0721a8f39ed4dd473d769450ea35bbf39c311",
"outputs/irpc-l5-20261025/ui-reuse.txt": "26fc3ae1fbb7c6a5afbc1f57181e93566415bd17d418aceebe7f0d579f99c532",
"outputs/irpc-l5-20261025/preparation.html": "dce6700bffbffb9885f80c777ba0d85c61b5303778f6993dd3f9d70eee3d9fde",
"outputs/irpc-l5-20261025/active-baseline.json": "2f2d1a9d3e311f12099d2372d0c1a01eb5ff3918a39218c73b668dfbe51c66f8"
},
"compiled_markers": {
"Calcular e guardar retenções IRPC": [
"assets/services-D_pyIjFg.js"
],
"Exportar preparação IRPC": [
"assets/services-D_pyIjFg.js"
],
"Reutilizar contrapartes e documentos existentes": [
"assets/services-D_pyIjFg.js"
],
"Calcular e guardar apuramento trimestral ISPC": [
"assets/services-D_pyIjFg.js"
],
"Calcular e guardar restituição E": [
"assets/services-D_pyIjFg.js"
]
},
"active_revision_readonly": {
"commit": "5c0cb25cea7826811c389b55a64bcdf5e43b937f",
"branch": "main",
"built_at": "2026-10-25T16:24:27.707113+00:00",
"manifest_sha256": "385a289f9ba26a632aa0164fbba3913cc8dc2fb891641881fc8d2dcda1951626"
},
"current_balance_followup": {
"receipt": "irpc-l5-grouped-qa-20261025.json",
"source2022_gap": "ResolvedbynewfullBR,p2731",
"currency_gap": "Resolvedthroughdeliveredmechanismforbaseandwithholdingproof",
"previous_proofs": "Preserved;originalscopeandhistorynotrevoked"
}
}
@@ -0,0 +1,359 @@
{
"status": "L6_first_scoped_adjustments_QA_not_installed",
"installed_baseline": "7a11c4ef8f06ef149eb0488be3cd0749dc609bd0",
"branch": "codex/irpc-l6-adjustments-qa-20261025",
"QA_workspace": "C:\\laragon\\www\\portal-investidor-irpc-l6-qa-20261025",
"scope": "Projection from financial plan for resident general-regime subject,explicit12monthJan-Dec2026 mapping,MZN. First documented full addbacks36(1)c:noncontractual fines/charges and compensatory interest already included in accounting expense.",
"implemented": [
"reuse reconciled finance bridge;cash flows and loan principal excluded",
"per-document-line and expense-source traceability;positive cents,duplicate and source capacity guards",
"unknown case limits its own addition;partial result remains indeterminate if any adjustment unresolved",
"versioned separate opportunity book;save/recovery/history/stale source guards;installed L5 payload preserved",
"UI,partial HTML export and private recovered dossier reporting"
],
"not_implemented": [
"full taxable profit or taxable base/tax",
"automatic expense classification or actual accounting statement import",
"other addbacks/deductions,patrimonial variations,depreciation/tax amortisation,losses and collection",
"M20/M22 official field mapping/submission,annual withholding credits",
"automatic reuse of L5 simulated interest as actual expense",
"nonresidentEP/specialregimes/othercurrency/years/shorterhorizons"
],
"example": {
"origin": "synthetic projection",
"accounting_profit_before_tax": "6480.00 MZN",
"included_noncontractual_fine": "100.00 MZN",
"included_compensatory_interest": "20.00 MZN",
"partial_additions": "120.00 MZN",
"partial_adjusted_result": "6600.00 MZN",
"taxable_profit": null,
"taxable_base": null,
"tax": null,
"missing_reference_example": "Fine unsupported -> addition20 only;partial adjusted total indeterminate;principal financial result retained"
},
"verification": {
"frontend_new_tests": 7,
"private_API": "1test/19assertions,DatabaseTransactions rollback,isolatedloopback55441/simulator_fiscal_delta_20261021_test",
"typescript": "pass",
"QA_build": "pass exit0",
"UI": {
"calculation": true,
"localSaveRecovery": true,
"report": true,
"missingInformationPartial": true,
"independentAdditionPreserved": true,
"download": true,
"privateApi": "IrpcNormalDraftTest separate",
"errors": []
},
"dossier": "generated from actual privateAPI recovered payload;contains6600",
"accepted_suites": "not repeated;reused",
"protected_runtime_files": 32,
"old_originals": 30
},
"runtime_delta": [
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "659e8f198632097f08404857e7766621aa38d98622aaaaba8f6cf31a993fa2f0"
},
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "a512052f4a170d7c40f55ab2bfe695281be839a1cacb92c6c5ec0da8f6b3c3d7"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256_LF": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256_LF": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256_LF": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
}
],
"protected_runtime": [
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256_LF": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256_LF": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256_LF": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256_LF": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256_LF": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256_LF": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256_LF": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256_LF": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256_LF": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256_LF": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256_LF": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256_LF": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256_LF": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256_LF": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256_LF": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256_LF": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256_LF": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256_LF": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256_LF": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256_LF": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256_LF": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256_LF": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256_LF": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256_LF": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256_LF": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256_LF": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256_LF": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256_LF": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
}
],
"originals_preserved": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"new_source": {
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee",
"bytes": 6269169,
"url": "https://www.at.gov.mz/api/webdav?path=%2FLEGISLA%C3%87%C3%83O%2FLEGISLA%C3%87%C3%83O%20GERAL%2FLEI%2FLei%20n%C2%BA.%2019-2009%2C%20de%2010%20de%20Setembro.pdf",
"read_scope": "Official AT catalogue title19/2009 contains BR36 4th supplement pp272(13–17),including20/2009;all5pages inventoried,PDF4/p272(16) visually reviewed.36(1)a–i retained;adds j–n. Only36(1)c used in this L6 increment. No L5 points reopened;no library publication/import or scan claimed."
},
"source_review": "Visual:Lei34/2007PDF6/10;Lei20/2009PDF4;Lei4/2012PDF2/3;Lei19/2013PDF1/2. Lei12/2025 explicit amendment list and effective date reused from accepted evidence;20/2022 changes61/62 reused. No generic legal revalidation.",
"proof_sha256": {
"api.txt": "ebefca22663853108963f34aa70c98b81fee7196b9dc96c9dd74ad5e532326a5",
"build-exit.txt": "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9",
"build.txt": "8268c2fe3d56f20c0ede7f8245a70657f54410c4941f77f2c337aae430c1eb20",
"calculated.json": "22968d447a30ad222f83bfb1c142ea1900fc2456945bfc6d517440829dec32cc",
"dossier.json": "4f5f1810cb60f4bb117958d89a8332231e82424e28b6ad380678932042e4374a",
"download.html": "b09b0f69a7aef7812d700234dfedbec3e5f4136cdd9e7497ad094052e8bcea99",
"frontend.txt": "6526af2df04cf412dc0b54e6282d32faa86661a9130712ae5b176eb54646c7a0",
"index.html": "9af7b69c19ca2fb213988ace8eb927008cb0bea73e267f16dee363fcdbcb0f12",
"preparation.html": "588d3f573d1f5cfc6286cd7da726dbfae39cb29d99d0753547580779090aac8f",
"recovered-preparation.html": "588d3f573d1f5cfc6286cd7da726dbfae39cb29d99d0753547580779090aac8f",
"recovered.json": "409eca12048865fc0f4d7828e45fb30554c6ace018c7e9960976c962e9e25eec",
"types.txt": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"ui-proof.json": "c381d89d855a0d4cc2f57c6c97795060f6638990eac6f1bea0c2d47bc24ec4dd",
"ui.png": "4a10262a1ce34d962fdeadc62fb43fa5724b874db821e37af19c009f95342124",
"ui.txt": "2529288ae9c74296003f1f591d984f3671c5e8922a99116bec67d42062a03230"
},
"active_changes": false,
"schema_API_config_permissions_dependencies_delta": false,
"L5_operational_demonstrated_scope": true,
"L5_complete": false,
"L6_complete": false,
"L5_AT_questions": "J1-J5/C1-C5 unchanged;no repeated research without new information"
}
@@ -0,0 +1,690 @@
{
"status": "installed_joint_L6_taxable_base_and_normal_colecta",
"installed": {
"status": "installed",
"commit": "2f684e59846187f3fb8a338d9d6f6a08cadb4d0d",
"release": "/var/www/investmoz-homologacao/releases/2f684e59846187f3fb8a338d9d6f6a08cadb4d0d-b46cd351",
"previous_release": "/var/www/investmoz-homologacao/releases/5e02c23af863485f6881e409c8704ec7e7573cc9-e83fcca2",
"database_migrations": 0,
"content_imports": 0
},
"previous_baseline": "5e02c23af863485f6881e409c8704ec7e7573cc9",
"backup": {
"stage": "/var/backups/investmoz-irpc-l6-colecta-delivery-20261025/backup",
"created_at": "2026-10-25T20:05:19Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "0f33d0bd0b8740bcc5363445a0fe59c85af42c16f02e723f9db3d0ef5898e020",
"files_sha256": "498b72430bbe9bd005856b65cb0d7e41e12898380e3324c5687044730796e95c",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l5_restore_20261025",
"port": 55441,
"source_dump_sha256": "0f33d0bd0b8740bcc5363445a0fe59c85af42c16f02e723f9db3d0ef5898e020",
"active_database_writes": 0
},
"preservation": {
"previous_release_preserved": "/var/www/investmoz-homologacao/releases/5e02c23af863485f6881e409c8704ec7e7573cc9-e83fcca2",
"installed": {
"status": "installed",
"commit": "2f684e59846187f3fb8a338d9d6f6a08cadb4d0d",
"release": "/var/www/investmoz-homologacao/releases/2f684e59846187f3fb8a338d9d6f6a08cadb4d0d-b46cd351",
"previous_release": "/var/www/investmoz-homologacao/releases/5e02c23af863485f6881e409c8704ec7e7573cc9-e83fcca2",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 6,
"preserved_L3_ISPC_FX_runtime_files_verified": 37,
"documentary_files_verified": 31,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 106,
"checksum": "7ff72d185a8c0dc624a7043fb5e68d72"
},
"after": {
"rows": 106,
"checksum": "49de7290166a6bdb90b3b2428106a6a5"
}
},
"sessions": {
"before": {
"rows": 28,
"checksum": "86bfbd7a7cc79988cf30ee47bc023e33"
},
"after": {
"rows": 29,
"checksum": "875df8b3f32a30fa7cbf7764e5290472"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"schema_permissions": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart value/expiry and request-throttle counter/timer pair;no deleted cache rows",
"sessions": "anonymous sessions created by exact delivery verification user-agent",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "8d6ea77eb4b34d86d207362d583cfa8bf2880b907becd9b00398964482c6b4bd",
"kind": "updated",
"fields": [
"expiration"
],
"key_pattern": "investemoz-cache-{hash}",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "2f251473865d14b953236ab95b1521764754d76abd79b58ca7d38c96dfe2fab1",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-{hash}:timer",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false
}
]
},
"sessions": {
"before_rows": 28,
"after_rows": 31,
"changes": [
{
"key_sha256": "521c7bd9ee130bd5be6200caff027c80f95ac631aa7889296adfd3c9504726fe",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "52e0cf41e90b1efe2651dee901feefc64e2b2a2edc2ee76238ae280765f7794d",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "e4606ee652bc13d62167aff5f88b13ddb14a746bd84e0445961832b344cfa3e4",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"public_verification": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "2f684e59846187f3fb8a338d9d6f6a08cadb4d0d",
"branch": "main",
"built_at": "2026-10-25T20:08:55.991892+00:00",
"manifest_sha256": "db2d2ff2e4f69877f6112cf57886720e3b57635b8bc993478f1cb2083fe94d23"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"Iniciar determinação da matéria colectável": [
"assets/services-C5XL4k_e.js"
],
"Iniciar cálculo da colecta normal": [
"assets/services-C5XL4k_e.js"
],
"Colecta — regime normal": [
"assets/services-C5XL4k_e.js",
"assets/project-dossier-DG7_2Cag.js"
],
"Saldo final — âmbito L8": [
"assets/project-dossier-DG7_2Cag.js"
],
"colecta simulada:": [
"assets/project-dossier-DG7_2Cag.js"
],
"Saldo final a pagar ou recuperar por determinar emL8:": [
"assets/project-dossier-DG7_2Cag.js"
],
"Simulação pelos pressupostos introduzidos, sem confirmação fiscal dos juros.": [
"assets/services-C5XL4k_e.js"
],
"Códigos provisórios ou de simulação não são correspondências oficiais.": [
"assets/project-dossier-DG7_2Cag.js"
],
"Calcular e guardar apuramento trimestral ISPC": [
"assets/services-C5XL4k_e.js"
],
"Calcular e guardar restituição E": [
"assets/services-C5XL4k_e.js"
],
"Reutilizar selecção cambial": [
"assets/services-C5XL4k_e.js"
]
},
"assets": [
{
"file": "assets/services-C5XL4k_e.js",
"status": 200,
"sha256": "4a97b79acd063296697ca75cc6c7be36dec142d697c74247a539457925ff2531"
},
{
"file": "assets/project-dossier-DG7_2Cag.js",
"status": 200,
"sha256": "4a04d6ca91df6db1c03f3a08a658a5f65dffbe9dd88f6e66aa2c62bc4b7250ed"
},
{
"file": "assets/simulation-form-BqVD91Ek.js",
"status": 200,
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
},
{
"file": "assets/project-dossier-document-Ctx2pT1S.js",
"status": 200,
"sha256": "fa9a89f7136265a8a701f723cfcc961c86f711566de71d77fe09194be97ca213"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-CN8XDMiO.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"runtime_delta": [
{
"path": "resources/js/lib/irpc-normal-base.ts",
"sha256_LF": "ab7f7389bac23abd990d0d3a8d4c52b81f7b11066586d74b4254c6cc2c15392f"
},
{
"path": "resources/js/components/simulation-irpc-taxable-base.tsx",
"sha256_LF": "e4fe9f66d35d24aa68fd87de6a5a6a0e901706b270c18962fd0c7ab00f9abd93"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "682de29e04cd0e3a6c33ef7c5cb2ebf763e16448bdf787be5de66e94fac61bc1"
},
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "78274f4d63162d0bb0fb32dcedbfc8b1de9b7eb4fbb7b638f8db1b8a064c0d58"
},
{
"path": "resources/js/lib/irpc-normal-assessment.ts",
"sha256_LF": "e5bce1e5015b52477febce1ba2a164e4064d887385f550b7ee55d1e20065b5a8"
},
{
"path": "resources/js/components/simulation-irpc-assessment.tsx",
"sha256_LF": "7174cc0160005a0c332ea40f02ba8a6d57985081b5ab45177ccd6e721bceea54"
}
],
"protected_runtime": [
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
{
"path": "resources/js/lib/financial-fiscal-bridge.ts",
"sha256": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256": "35dc586d9ab6c77405f3a46ed2ce3d9db74c54f338314d5e3c4959f0b6a55860"
}
],
"originals": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"pipeline_checks": [
"OK (1 test, 3106 assertions)",
"built in 29.57s",
"OK (59 tests, 317 assertions)",
"# tests 906",
"# pass 906",
"# fail 0"
],
"accepted_proofs_reused": true,
"manually_repeated_accepted_functional_suites": false,
"sequence": {
"taxable_profit": "6700MZN simulated",
"taxable_base": "4400MZN simulated",
"normal_colecta": "1408MZN simulated,32%,2026",
"final_payable": null,
"final_recoverable": null,
"final_balance_scope": "L8"
},
"remaining_L6": [
{
"work": "Outros ajustamentos ordinários: admissibilidade de custos e correcções aos proveitos",
"evidence": "`irpc-normal.ts`, `NormalAdjustment.rule` e `calculateNormal`: apenas multas não contratuais e juros compensatórios36(1)c; `other` fica fora do recorte. `irpc-normal-profit.ts` não aplica `incomeCorrections`/`expenseCorrections` conhecidos não zero.",
"example": "Encargo de terceiro de250MZN com qualificação36(1)b, ou despesa não documentada36(1)g, incluído no resultado; a correcção não tem regra executável neste livro. A eventual tributação autónoma é outra operação, emL7.",
"completion_criterion": "Corresponder a regra geral e condições de cada categoria incluída, calcular acréscimo/dedução/exclusão com sinal e origem, evitar dupla contagem e demonstrar reflexo no lucro, base e colecta. A tributação autónoma que possa coexistir pertence aL7."
},
{
"work": "Dedutibilidade dos juros financeiros ordinários",
"evidence": "`irpc-normal-profit.ts`, `closeNormalProfit`: qualquer remanescente não zero de `interest_expense` mantém pendência; só os compensatórios integralmente acrescidos estão cobertos.",
"example": "Juros de financiamento comercial de120MZN, distintos de juros compensatórios, com finalidade/custo documentados.",
"completion_criterion": "Qualificar a parcela ordinária, dedutibilidade e correcção aplicável, conservar os montantes reconhecidos/pagos separados e fechar o lucro sem a equiparar a infracção. Relações especiais/benefícios e regras especiais seguemL7; taxa de juros compensatóriosL5 só é dependência se esse cálculo for efectivamente usado."
},
{
"work": "Reintegrações/amortizações fiscais e diferença face à contabilidade",
"evidence": "`irpc-normal-profit.ts`: `depreciation` positivo bloqueia o fecho; não existe mapa fiscal de activos/quotas nesta família de módulos.",
"example": "Depreciação contabilística120MZN com quota fiscal do activo ainda por corresponder.",
"completion_criterion": "Reutilizar activo, base e datas; corresponder método/taxa/limites e afectação ordinários, calcular quota fiscal e diferença para o resultado; manter mapas por activo/exercício e histórico. Incentivos, majorações e regimes especiais de activos seguemL7."
},
{
"work": "Variações patrimoniais e periodização ordinárias de montante não zero",
"evidence": "`irpc-normal-profit.ts`, `profitTopics`/`closeNormalProfit`: `positivePatrimonial`, `negativePatrimonial` e `timing` conhecidos não zero conservam valor e impedem o fecho; ausência/zero suportados são o caminho demonstrado.",
"example": "Variação500MZN fora do resultado, ou diferença temporal300MZN entre reconhecimento contabilístico e exercício fiscal, com natureza concreta documentada.",
"completion_criterion": "Corresponder natureza/ano/regra ordinária e decidir inclusão, exclusão ou ajustamento com sinal; impedir reaplicação em dois exercícios; demonstrar cálculo→gravação→recuperação→relatório. Operações especiais/benefícios do tópico `special` não são saldo deL6."
},
{
"work": "Resultado fiscal negativo do próprio exercício",
"evidence": "`irpc-normal-base.ts`, `calculateNormalBase`: lucro negativo é conservado, mas a base fica indeterminada; o livro de perdas só admite exercícios anteriores ao de utilização.",
"example": "Resultado fiscal actual−500MZN conhecido; não é uma perda anterior dedutível a si própria.",
"completion_criterion": "Tratar a situação da base/colecta nesse exercício e preparar a perda fiscal própria com origem/ano para utilização futura, conforme regra aplicável, sem confundir ausência de lucro, falta de informação, crédito ou consumo do saldo oficial. Perdas anteriores ordinárias já demonstradas continuam aceites."
},
{
"work": "Extensões do âmbito normal previstas no L6 original",
"evidence": "`irpc-normal.ts` fixa12meses/ano civil2026/residente/MZN; `irpc-normal-base.ts` exige exercícios anuais ordinários; a entrada deL6 no plano original inclui exercício fiscal e residência/EP.",
"example": "Caso de estabelecimento estável sob regime geral, ou período fiscal normal diferente do calendário/horizonte do plano; plano noutra moeda ainda sem reconciliação fiscal anualMZN.",
"completion_criterion": "Delimitar os casos normais a admitir, imputação de resultados ao sujeito/EP, datas/períodos e reconciliaçãoMZN usando o câmbio já entregue; demonstrar o percurso dependente. Não reimplementar câmbio, exigir pesquisa de todos os anos históricos ou aplicar automaticamente32% fora do período correspondido. Benefícios/convenções/regimes específicos pertencem aos lotes próprios."
},
{
"work": "Representação fiscal da colecta com fracção de cêntimo",
"evidence": "`irpc-normal-assessment.ts` conserva o racional e assinala `centExact:false`; não aplica regra fiscal de arredondamento/transcrição.",
"example": "Base0,01MZN×32%=0,0032MZN exactos; o caso1408MZN não tem esta ambiguidade e continua válido.",
"completion_criterion": "Identificar e executar a convenção aplicável à colecta/representação do formulário, mantendo o exacto e a rastreabilidade do valor transcrito. Não importar por analogia arredondamento de prestações/pagamentosL8 nem criar uma regra por defeito."
},
{
"work": "Correspondência dos dados de L6 aos exemplares M/20/M/22",
"evidence": "A família `irpc-normal*` produz mapaHTML/dossier e exclui expressamente correspondência/transcrição oficial; o âmbito original deL6 inclui M/20/M/22 e diferenças de ediçãoPDF/XLSX.",
"example": "Resultado, correcções, perdas, base4400 e colecta1408 existem no mapa de trabalho; os respectivos campos/anexos aplicáveis dos exemplares não estão correspondidos no motor.",
"completion_criterion": "Cotejar os exemplares já inventariados e mapear apenas os dados deL6 aos campos/versões efectivamente aplicáveis, com prova de preenchimento/recuperação. Os campos de retenções,pagamentos,créditos e saldo final sãoL8. Submissão electrónica/aceitaçãoAT não são presumidas como parte desta correspondência."
}
],
"remaining_scope_origin": "Existing L6 scope in traceability-and-manual.md table:normal costs/amortisations/losses/colecta/M20-M22,exercise and residence/EP;actual code at2f684e59. No new backlog or generic legal approval imposed.",
"excluded_from_L6_remainder": {
"L7": "Annual benefits/exemptions,reduced/cooperative rates,autonomous expense/capital-gain taxation,special operations,transferred losses and special-regime segregation",
"L8": "Annual retentions,PPC/PEC/otherpayments,credits/deductions tocolecta,doubletaxation,limits/carryforwards,reconciliation,final payable/recoverable balance/calendar",
"data_gaps": "Missing support,identity,amount,completeness or qualification under an already implemented rule is case data,not automatically new development",
"already_accepted": "Demonstrated6700->4400->1408 path,persistence/history/recovery/report,known/absent/missing handling,L3/ISPC/FX/L5 proofs"
},
"matrix_row": "AUD-SIM-INT02 existing matrix only",
"L6_status": "operational in demonstrated scope;partial only for the eight listed L6 work items,not for L7/L8",
"L6_complete": false,
"documentation_runtime_changed": false,
"new_legal_research": false,
"proof_files": {
"backup.txt": "26a42cfc6ac437c9bf7ffbd46f5f87b355b9e05e4fb82b10ee9b9f519dfe317c",
"compact-dependencies.txt": "80e9605f77b859630bd5d52c43908d72e76ee055e62892c3617b5e8c9cd82aaa",
"installed-protected.txt": "4c655d788b48214a1e6697bef459315756815eb6974e0c930c32a53334c8f7fc",
"installed-public-delta.json": "8d4d53ff066a5c48a505870973f26ca4d168e95376bb8085eed9b3cd6bdc0385",
"installed-public.txt": "4f6a74186b0d1371a7438a8e50bfbd0548b4039c3d8d04f850c8fbf0530bd9a7",
"integration.txt": "871bb24ee1fa0f45d096b85141124940500c6b84edfae01d8ff2bcf1d53bffd8",
"manifest-served.json": "db2d2ff2e4f69877f6112cf57886720e3b57635b8bc993478f1cb2083fe94d23",
"operational-delta.txt": "a24421b24ebc470bf0b0a12cc5345b41b229c1f5181320d2a7422f1bd044687c",
"preflight.txt": "2b68ed9a649a68ca1ba6c0c217a7e60287dc56d4af7e83c3dfe77e8a18a13f83",
"preparation.json": "d5c4124098015fef2a7f69bfc5d88f7789dc95cad38ef4430d24a34079f5b68f",
"progress.txt": "458df3545877efa51b97967221b8e3b2b737316970f3ccc63a01d5e07a6d8dda",
"remaining-section.md": "32ce79517daa0c9d33963f71c15e068eb5be548d7eddbf9874bab594b5592461",
"restore.txt": "524b246a6c0f62692c7a774347560962c4021bcf46e0368d9a075c44843b362a",
"schema-permissions-after.txt": "76b5a4d8af11e4898a205062766cfb7ab6ec0783200e77e60a1927aa1ca18597",
"schema-permissions-before.txt": "0ab7c964792acdd8917bce256c472e55e034b103500a58b49f020b5084823ed7",
"status-final.txt": "c20d733a19ff8d25afdf4a52e67193b1d0d255847d8aeef2c78c80a4dcf29476",
"status1.txt": "0d2be4308f1b2a4eda966d5bf4c10d719bf13cb87ba69b724bf90f765543fee4",
"status2.txt": "248a3a7e6921d2021971e43cc15df8bc0f76a5834a7ef6c46c839304e1a21349",
"status3.txt": "248a3a7e6921d2021971e43cc15df8bc0f76a5834a7ef6c46c839304e1a21349",
"status4.txt": "df65a125eb3ea41c86c9b0f2fd78ea77775aa240846eac75faeacbf459b55382"
}
}
@@ -0,0 +1,582 @@
{
"status": "normal_colecta_QA_joint_with_taxable_base_prepared_not_installed",
"installed_baseline": "5e02c23af863485f6881e409c8704ec7e7573cc9",
"previous_QA": "b8d45796dd8785e26dd27375f6da8b745c73e6ad",
"branch": "codex/irpc-l6-colecta-qa-20261025",
"QA_workspace": "C:\\laragon\\www\\portal-investidor-irpc-l6-colecta-qa-20261025",
"scope": "Normal general rate32%,CIRPC61(1),annual2026,01January-31December,MZN,resident general regime,current taxable base. Explicit case classification/reference;special/reduced/benefit/autonomous cases not mapped to general rate by approximation.",
"sequence": {
"simulated_taxable_profit": "6700MZN",
"simulated_taxable_base": "4400MZN",
"general_rate": "32%",
"simulated_colecta": "1408MZN",
"final_balance_payable": null,
"final_balance_recoverable": null,
"final_balance_scope": "L8"
},
"implemented": [
"Reuse current taxable base from b8d45796,not profit as a substitute;no re-entry of4400",
"Versioned statutory rate identification scoped to2026 and resident-general/MZN classification;missing/special case keeps base visible but colecta indeterminate",
"Exact rational base*32/100;zero only when base known zero,subcent result retained exact without invented fiscal rounding",
"Optional calculationversion4;legacy1/2/3 readers/history remain supported and legacy3 current without recalculation",
"UI and exports preserve profit -> base -> colecta -> final balance order;known1408 never labelled final payable amount",
"FinalBalance explicitly not_calculated/payable null/recoverable null,L8;legacytax remains null",
"No withholding/payment/annual credit input,netting,refund or final settlement introduced",
"Private API create/update/recovery;known/missing dossier from actual recovered payload"
],
"source_review": {
"existing_primary_sources": [
"Lei34/2007PDF17/p768(71),61(1):32%general",
"Lei4/2012PDF2/p34(5),61(2) amendment reused",
"Lei20/2022PDF1/p2731:61(1)retained,61(2)temporary reductions end31/12/2025",
"Lei12/2025PDF18/p2180(18):amendment list excludes61(1);PDF20/p2180(20):separate61-Acapitalgain taxation and effective01/01/2026"
],
"visual_review": "2007PDF17,2022PDF1,2025PDF18/20;accepted originals unchanged",
"primary_index": "https://www.inm.gov.mz/pt-br/content/br-n%C2%BA-252-de-301222-boletim-da-rep%C3%BAblica-i-serie",
"new_originals": 0,
"not_inferred": "No reduced-rate extension,benefit eligibility,autonomous tax or rounding rule presumed. No L5 tax-rate/CER research reopened."
},
"verification": {
"frontend_new_tests": 8,
"private_API": "1test/40assertions;create/update If-Match/recovery;DatabaseTransactions rollback;isolated127.0.0.1:55441/simulator_fiscal_delta_20261021_test",
"Wayfinder": "existing guarded generation ofroutes/actions",
"typescript": "passed",
"QA_build": "passed exit0",
"UI": {
"normalColecta1408": true,
"ratePeriodClassificationVisible": true,
"baseReused": true,
"sequenceOrdered": true,
"finalPayableAndRecoverableUnknownL8": true,
"localSaveRecovery": true,
"download": true,
"specialCaseNoGeneralRate": true,
"missingClassificationIndeterminate": true,
"privateApi": "IrpcNormalAssessmentDraftTest separate",
"errors": []
},
"dossier": "known and missing outputs from actual private API recovery",
"accepted_proofs": "b8d45796,L5,L3,ISPC,FX reused,no manual repeated accepted suites;legacy3 snapshot only read/roundtripped",
"legacy_fixture_sha256": "ee1b1b49e0686bed3f8171beaacf9f57327850bcd36c96e1cc2ba5f1064ff585",
"protected_from_previous_QA": 39,
"protected_from_installed": 37,
"originals": 31
},
"runtime_delta_increment": [
{
"path": "resources/js/lib/irpc-normal-assessment.ts",
"sha256_LF": "e5bce1e5015b52477febce1ba2a164e4064d887385f550b7ee55d1e20065b5a8"
},
{
"path": "resources/js/components/simulation-irpc-assessment.tsx",
"sha256_LF": "7174cc0160005a0c332ea40f02ba8a6d57985081b5ab45177ccd6e721bceea54"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "682de29e04cd0e3a6c33ef7c5cb2ebf763e16448bdf787be5de66e94fac61bc1"
},
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "78274f4d63162d0bb0fb32dcedbfc8b1de9b7eb4fbb7b638f8db1b8a064c0d58"
}
],
"runtime_delta_joint_from_5e02c23a": [
{
"path": "resources/js/lib/irpc-normal-base.ts",
"sha256_LF": "ab7f7389bac23abd990d0d3a8d4c52b81f7b11066586d74b4254c6cc2c15392f"
},
{
"path": "resources/js/components/simulation-irpc-taxable-base.tsx",
"sha256_LF": "e4fe9f66d35d24aa68fd87de6a5a6a0e901706b270c18962fd0c7ab00f9abd93"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "682de29e04cd0e3a6c33ef7c5cb2ebf763e16448bdf787be5de66e94fac61bc1"
},
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "78274f4d63162d0bb0fb32dcedbfc8b1de9b7eb4fbb7b638f8db1b8a064c0d58"
},
{
"path": "resources/js/lib/irpc-normal-assessment.ts",
"sha256_LF": "e5bce1e5015b52477febce1ba2a164e4064d887385f550b7ee55d1e20065b5a8"
},
{
"path": "resources/js/components/simulation-irpc-assessment.tsx",
"sha256_LF": "7174cc0160005a0c332ea40f02ba8a6d57985081b5ab45177ccd6e721bceea54"
}
],
"protected_runtime": [
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256_LF": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256_LF": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256_LF": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256_LF": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256_LF": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256_LF": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256_LF": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256_LF": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256_LF": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256_LF": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256_LF": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256_LF": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256_LF": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256_LF": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256_LF": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256_LF": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256_LF": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256_LF": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256_LF": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256_LF": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256_LF": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256_LF": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256_LF": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256_LF": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256_LF": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256_LF": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256_LF": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256_LF": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
{
"path": "resources/js/lib/financial-fiscal-bridge.ts",
"sha256_LF": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256_LF": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256_LF": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256_LF": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256_LF": "35dc586d9ab6c77405f3a46ed2ce3d9db74c54f338314d5e3c4959f0b6a55860"
}
],
"protected_previous_QA_runtime": [
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256_LF": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256_LF": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256_LF": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256_LF": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256_LF": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256_LF": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256_LF": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256_LF": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256_LF": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256_LF": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256_LF": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256_LF": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256_LF": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256_LF": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256_LF": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256_LF": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256_LF": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256_LF": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256_LF": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256_LF": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256_LF": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256_LF": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256_LF": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256_LF": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256_LF": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256_LF": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256_LF": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256_LF": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
{
"path": "resources/js/lib/financial-fiscal-bridge.ts",
"sha256_LF": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256_LF": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256_LF": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256_LF": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256_LF": "35dc586d9ab6c77405f3a46ed2ce3d9db74c54f338314d5e3c4959f0b6a55860"
},
{
"path": "resources/js/lib/irpc-normal-base.ts",
"sha256_LF": "ab7f7389bac23abd990d0d3a8d4c52b81f7b11066586d74b4254c6cc2c15392f"
},
{
"path": "resources/js/components/simulation-irpc-taxable-base.tsx",
"sha256_LF": "e4fe9f66d35d24aa68fd87de6a5a6a0e901706b270c18962fd0c7ab00f9abd93"
}
],
"originals_preserved": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"proof_sha256": {
"api.txt": "0d75de04e58963d6c3a6c4f8a8347770ca3ece09784e0ad2a9db6fd7e457af13",
"BR-248-I-Suplemento-1-2025.pdf-page18.png": "48e5cde488cb879bbe55f35a75e4153b4a29668757e9da49c3c67f69b581ed1b",
"BR-248-I-Suplemento-1-2025.pdf-page20.png": "9412fe514a0ee097ddd32c5bf212b72a87063d251118a4b97565bf29c0be634d",
"BR252-I-Serie-2022-Lei20-PESOE.pdf-page1.png": "be4585d255933806a3a79fa826c8bf2ee57a096b64dbb0b65b1eb0014bf05c80",
"build-exit.txt": "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9",
"build.txt": "00d322501e52ed59d4a36d1dde50a8cc15c6643f8af8a786da522ebe11308f6c",
"calculated.json": "16f6398a752c780781ad7d8a3133afbeb3bbc0776beadb7341d10ca2923ff58e",
"dossier-calculated.json": "d9f6b225930dbc0652593d67119bf06190e39dc46e73328ddb8d41a3d487fb87",
"dossier-missing.json": "cd8f122e98c62e6170676594bd413644323af6ed6d44ee2613bd5449ba67f636",
"download.html": "65ad3a808e97404fb0690a587ecf9a09cd58ced4d640956615d0aaf48e58d941",
"frontend.txt": "baae440ead1ff0649087f86431e4751db91d21f7639c40e1073e8b4fb6247dd0",
"index.html": "9af7b69c19ca2fb213988ace8eb927008cb0bea73e267f16dee363fcdbcb0f12",
"Lei-34-2007-BR52.pdf-page17.png": "55de382892c9ec9c9344aa8a8dc195abf0cffd41535a36bafadf1868f80614c0",
"missing.json": "bd9a8feca32ac0eb36abbc8c81b8eb898856bf9a14fe4bb2fd9ead35c87583d1",
"preparation.html": "d1c159d8747b25233f4b2f2cb729d2f9c56c117e9a9cbd9f4253d6a3b907fb46",
"recovered-calculated.html": "d1c159d8747b25233f4b2f2cb729d2f9c56c117e9a9cbd9f4253d6a3b907fb46",
"recovered-calculated.json": "7dc6602a5751822d556181d92a4517d631d1689b8d7073f9b14a206dfb22f57d",
"recovered-missing.html": "4f5c9d02bf4feb8413d452aaa4b5bbffead43bf1e8581e6074ebee39d17caf09",
"recovered-missing.json": "86087de983c1cb43406fb605b6ff10958b22e543206dac281f64656b7621f9cb",
"regulation.txt": "c680dfb73eeb638cf85d06fb0fe19550487de2994ce76f60077ef4baa88e3238",
"types.txt": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"ui-colecta.png": "2de2150e0a13c97a6e9ef641da5f426aa6f73a4e2e583dcc684c99de4b247b71",
"ui-missing.png": "33d0f91aa83e03aaf7667c6540aa73cd5d26852101b1109180dfa4c8fb7c1728",
"ui-proof.json": "491adb430be266abe0e8c95a311fa187d186a6d2beba2658f1431b6e61f58bed",
"ui.txt": "9bd1f1515b85823da48fc2a6b2b513b37b421e26764367f08b3dea23eb77e151"
},
"not_claimed": [
"Final annual payable/recoverable balance,annual withholding/payment/credit reconciliation reserved toL8",
"Reduced or benefit rates,autonomous taxes,capital gains61-A or other special cases",
"Fiscal cent rounding or official M20/M22 transcription/submission",
"Full L6 completion or installation of b8d45796/colecta candidate"
],
"prepared_joint_delivery": "b8d45796 taxable base plus this colecta increment over installed5e02c23a;bundle/manifest aftercommit. No push/installation.",
"active_changes": false,
"schema_API_config_permissions_dependencies_delta": false,
"L6_complete": false,
"L8_implemented": false,
"L5_questions": "Only dependent cases blocked;ten questions unchanged"
}
@@ -0,0 +1,145 @@
{
"status": "three_compatible_L6_sets_QA_prepared_not_installed",
"installed_baseline": "2f684e59846187f3fb8a338d9d6f6a08cadb4d0d",
"branch": "codex/irpc-l6-compatible-sets-qa-20261025",
"QA_workspace": "C:\\laragon\\www\\portal-investidor-irpc-l6-sets-qa-20261025",
"scope": "Ordinary documented rules, annual MZN periods ending2026, resident general or attributable EP result; no assumed fiscal rounding or final settlement.",
"demonstrated": {
"accounting_profit": "6240MZN",
"installed_addbacks": "220MZN",
"new_effects": {
"third_party_tax": 250,
"patrimonial_gain": 200,
"patrimonial_cost": -50,
"timing": 100,
"depreciation_difference": 20
},
"taxable_profit": "6980MZN",
"previous_losses_explicit_deduction": "2300MZN",
"taxable_base": "4680MZN",
"general_rate": "32%",
"colecta": "1497.60MZN",
"payable": null,
"recoverable": null,
"current_loss_case": "3820MZN loss;known zero base/colecta;no official carryforward",
"EP_case": "2025-07-01 to2026-06-30,12 monthly periods"
},
"new_proofs": {
"frontend_tests": 14,
"private_API_tests": 1,
"private_API_assertions": 78,
"database": "127.0.0.1:55441/simulator_fiscal_delta_20261021_test;DatabaseTransactions rollback",
"routes_actions_generated": true,
"typescript": "passed",
"build": "passed",
"actual_UI": "field editing;unsupported asset rate;missing interest;save/recovery;download;current loss",
"dossier": "from API-recovered calculated/missing/loss/EP JSON"
},
"preservation": {
"installed4_fixture_matches_accepted_sha256": true,
"versions1_to4_keys_unchanged_without_optin": true,
"other_runtime_changes": false,
"schema_API_config_permissions_dependencies_changed": false,
"L3_ISPC_FX_L5_accepted_proofs": "reused;not repeated",
"L5_ten_questions": "unchanged,only dependent cases blocked",
"active_data_changed": false
},
"runtime_delta": [
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "e33b3839aac53a1b7ca2a76eda0ec4c54015a6d1c75e386aaeb5d342943f5965"
},
{
"path": "resources/js/components/simulation-irpc-schedules.tsx",
"sha256_LF": "eebd6d9e4100920a5ebf91b800537ffe301fd6a994b86a3b080d673f4a9c9a42"
},
{
"path": "resources/js/lib/irpc-normal-assessment.ts",
"sha256_LF": "1dc6adc0835af033ef296d12cdc1e9ef354b2f54cd36e2349b2df66e369c1ee3"
},
{
"path": "resources/js/lib/irpc-normal-base.ts",
"sha256_LF": "85fa1eb78ce2b8a144a9f0dcda93b542083a7ff119cbc43f4334c87284bfd312"
},
{
"path": "resources/js/lib/irpc-normal-forms.ts",
"sha256_LF": "4e986addb9f2d74e7a80345f8f1e4d8e0b2f562c867fa6eee84880d9f72a3649"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256_LF": "d5a2b52f7deb4cf35651188e04f103fcba950a007e3aa4de5ba7017e686614df"
},
{
"path": "resources/js/lib/irpc-normal-schedules.ts",
"sha256_LF": "b0045fd2c072998ebb290c2a8332c26d05a1f5f746b3beb1805508147497cac8"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "62d20bbcebb523f77fde950f623933a13f03283238665cf22fec9390f7ba9333"
}
],
"source_exemplar_added": {
"document": "Decreto72/2013,BR102,2suplemento,23December2013",
"official_issue": "https://www.inm.gov.mz/pt-br/content/conselho-de-ministros-suplemento-n%C2%BA-2-de-231213-pag-1074-3-24-br-n%C2%BA-102-boletim-da-rep%C3%BAblica",
"gazette_copy": "https://www.lexlink.eu/FileGet.aspx?FileId=1152468",
"local_original": "C:\\laragon\\www\\portal-investidor-irpc-l6-sets-qa-20261025\\outputs\\irpc-l6-sets\\decreto-72-2013.pdf",
"sha256": "922ef67cb0c1111405c3c0a092d8c302a74fba8a34d627b6e9e13223612e0659",
"visual_pages": [
1,
2,
17
],
"rate_table": "tableII/group3/items9=25%,9.1=20%,Gazettepage1074(21)/PDF17",
"consultation": "preserved in QA proof archive;no publication/import into active library",
"legal_application": "articles3–7,ordinary annual constant method,tableI precedence;other categories/methods visibly unsupported",
"scan_status": "not asserted"
},
"existing_form_sources": {
"M22": "4b61bd83d1fbcfd3b7b5c5523cea5923f7d0f65dc4c004eff58e5db38f763c88;three accepted page images reused",
"M20_workbook": "1ceca6f4c6d77853c1b2b445876599b42093175fa89eecf40590180956d83a9e;existing structure inventory reused;no third-party sample values or cached formulas",
"concrete_conflict": "M20A.1 refers result to M22 field201/Q8;PDF M22 uses200/Q10;automatic transfer blocked only for that mapping"
},
"remaining": "Concrete cases enumerated in same matrix/manual section25/10;cost limits/provisions/prior-year timing;remaining asset categories/methods;short periods/annual foreign-currency reconciliation;fractional fiscal representation;remaining result/form mapping. L7 benefits/special cases and L8 settlement remain own scopes.",
"L6_complete": false,
"installation_performed": false,
"next_delivery": "Joint Git bundle from installed2f684e59;fresh authenticated destination backup/restore and delta required only at installation,not performed in QA.",
"proof_sha256": {
"api.txt": "3c3142dd55febf17c5e16e3cfabf2266759be7290b8d5ac92823e0f71cbffa6a",
"build-exit.txt": "13bf7b3039c63bf5a50491fa3cfd8eb4e699d1ba1436315aef9cbe5711530354",
"build.txt": "ba955cab87896b78652787f188c092e79108fc0e5289f237be1ddf21d73dbbf3",
"calculated.json": "109426b86ae7c14463699b1d197064617f124ecec0c55085d9e81aeddc505a5a",
"decreto-72-2013.pdf": "922ef67cb0c1111405c3c0a092d8c302a74fba8a34d627b6e9e13223612e0659",
"decreto-72-2013.txt": "bbbf05f109201a6d31e153046576a088e6c0cca97ada07833d0499698d0afcfa",
"decreto-72-page1.png": "bb681e5df24a13d8484a521ae58e480c9dd23b4fd09de3ff11d5287ddd26a4f9",
"decreto-72-page17.png": "bb3468fde9f95576d8d6392a4c906ae904941ad35843c472d3671492c24f0945",
"decreto-72-page2.png": "9bf0f11a4724b079b494f640e905eee5bd278b729091e67aa03d0bfe71f5c273",
"dossier-calculated.json": "e9487c0325db125f8a0ff5266d137141916f329283857f2efc1f64732353454b",
"dossier-ep.json": "57b55c94118bd9767f06b4cd0673bcecbd8882ca1ec8681c393216a0fc3a7ac7",
"dossier-loss.json": "28eb77522fea39947a6cffd7419c24cd37795f361559050377f79d8b9f1cd1fb",
"dossier-missing.json": "bda0394cb059a1800a5dcf4728ba58a5b3ee975a87a7a938ebf5673e0ace1587",
"dossier.mjs": "9ab7bc1ad64ab8f04936068df0f0555749048d9edd9f2d48e8246542204257dc",
"download.html": "d084c44b3b527c9ed5f3f2c2e7ccd88229b0a19b9956e153e63b14618020acdb",
"ep.json": "9ae0b179c100ea5e642ce2ed9362b74e60bf1040bf6e7227592db84220babb23",
"frontend.txt": "92d096de8d364f04339178feeb6e77cf247cbc4974974bce56ba7728401bbdc5",
"index.html": "09941968500d2910121bdcb0029e326fc6d44bb025b01766654289a28caa62fa",
"loss.json": "8a0e85205db146a02fc9e06a2667cdce5a00e48ed8a7e7568a50d361e40671b2",
"missing.json": "1f52b06286d0724fe27d24ab91386732c873fc65064521c270faf357ac193135",
"preparation.html": "7ac15855048512bec05690170368df1ee4d4879f224a9d6c56749c3500d2d9c0",
"qa.tsx": "e2f5dc5e9a9c142b3fe65889c0cefcbfb03fb3b46957437af1108dbf20569647",
"recovered-calculated.html": "7ac15855048512bec05690170368df1ee4d4879f224a9d6c56749c3500d2d9c0",
"recovered-calculated.json": "db98c66ba9cf46a67ead4267d7b3d25b08275a4d8a11bbd316f4bec2b77644af",
"recovered-ep.html": "47df28ba65d7825192ec7fd3fad61998f378829046df2c1b3ab74b7fb32980ef",
"recovered-ep.json": "56f12435276c4cf9604f10e8c53bba61f1eb84dcaa5b911ac06242112d740764",
"recovered-loss.html": "a3f70ddcfe4a10a38110690b7583f1c89be6427fe347a321e9a395db6214fc6a",
"recovered-loss.json": "fe280337741a5004c13c83a41f83ca87c98c07f815fc87b617a0d5c8dbd03573",
"recovered-missing.html": "8989a835f9145e94434f31c90c96c801219494019fbc6167f1c8272d08c6debc",
"recovered-missing.json": "a4a24bc80dd6352c0883a1a555de9cd32a71335bd07b4826526ebe311700766f",
"types.txt": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"ui-calculated.png": "1578772454a4e5902d3ac8f607dbcda3b3c3b7e23d0870bbe233da036f15ba5e",
"ui-missing.png": "72d48f81bc67bd9342c5078d81044290912afacd305980806c42cd96b038a614",
"ui-proof.json": "7bd7a522b4307d8f72fb04317106c3b7cc53763fe8923017ae0f63a510b9bb9e",
"ui.cjs": "207eea61db65ac778f26f35beecd18387d6126b75e1effcf3e33c1e26e957215",
"ui.txt": "9b120d22b3e2539e8862c5ce5a973cce4fc2632a16680e7f997020f4e2cd0196",
"vite.config.ts": "11a4a8f0bf0394f380e731cfb30cf4a0f3de3c6f3734653491e1aa26f57315f1"
}
}
@@ -0,0 +1,695 @@
{
"status": "installed_L6_cost_limits_provisions_timing",
"installed": {
"status": "installed",
"commit": "043dd35d8ee247123b3a32f1fc10fd2ede81e9f4",
"release": "/var/www/investmoz-homologacao/releases/043dd35d8ee247123b3a32f1fc10fd2ede81e9f4-917b3c47",
"previous_release": "/var/www/investmoz-homologacao/releases/a2de725901c308fb2ac2bc3d72181ab50ef46b7a-145e8f25",
"database_migrations": 0,
"content_imports": 0
},
"previous_baseline": "a2de725901c308fb2ac2bc3d72181ab50ef46b7a",
"backup": {
"stage": "/var/backups/investmoz-irpc-l6-costs-delivery-20261026/backup",
"created_at": "2026-10-26T06:35:29Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "bf7f4e6ad9e18ef479ae46a08ec9c072047240655331e437da14ae8c39e8bd0b",
"files_sha256": "4046d8eff093201371a9e5fbdd14a6d5fe805d7f72cf30e9d6132e5804da1788",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l5_restore_20261025",
"port": 55441,
"source_dump_sha256": "bf7f4e6ad9e18ef479ae46a08ec9c072047240655331e437da14ae8c39e8bd0b",
"active_database_writes": 0
},
"preservation": {
"previous_release_preserved": "/var/www/investmoz-homologacao/releases/a2de725901c308fb2ac2bc3d72181ab50ef46b7a-145e8f25",
"installed": {
"status": "installed",
"commit": "043dd35d8ee247123b3a32f1fc10fd2ede81e9f4",
"release": "/var/www/investmoz-homologacao/releases/043dd35d8ee247123b3a32f1fc10fd2ede81e9f4-917b3c47",
"previous_release": "/var/www/investmoz-homologacao/releases/a2de725901c308fb2ac2bc3d72181ab50ef46b7a-145e8f25",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 6,
"preserved_L3_ISPC_FX_runtime_files_verified": 42,
"documentary_files_verified": 31,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 106,
"checksum": "5226f818ead8e964983de752574a1647"
},
"after": {
"rows": 106,
"checksum": "82f4ca900546cfbd7c046c9e2a681522"
}
},
"sessions": {
"before": {
"rows": 35,
"checksum": "077762df7046fb9e6ce60a7470f3b61f"
},
"after": {
"rows": 38,
"checksum": "b90979f4d72922226d368ab21ffe162a"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"schema_permissions": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart value/expiry and request-throttle counter/timer pair;no deleted cache rows",
"sessions": "anonymous sessions created by exact delivery verification user-agent",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "dbb99b7e17f5b4b9bb7a8bdf9350d9b2ae368aaa4bc44593a2522d87617d8461",
"kind": "updated",
"fields": [
"expiration"
],
"key_pattern": "investemoz-cache-{hash}",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "c1c7bc86ef3255c103a0be6aeb651b824eb07259e993cc5daf3665c1a6afff2d",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-{hash}:timer",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false
}
]
},
"sessions": {
"before_rows": 35,
"after_rows": 38,
"changes": [
{
"key_sha256": "29cd831ee5192663271b023bde8978c87f54e6779a76887fbdbb7d8b52898085",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "5818b9263233545023da019e37aa9c88c4f02128d540df592d1eb4cb075b406d",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "e30d5aad1397f2c086ee5dcd82a279b9a307415336c02059ff9513ef5251f262",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"public_verification": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "043dd35d8ee247123b3a32f1fc10fd2ede81e9f4",
"branch": "main",
"built_at": "2026-10-26T06:40:10.666340+00:00",
"manifest_sha256": "d91dd39d49e9e0251c76c811ca6a0798b7cf544e3e807735574ba51691afac9e"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"Iniciar custos com limites, provisões e periodização": [
"assets/services-DkQ7aTGY.js"
],
"Acrescentar custo, provisão ou periodização": [
"assets/services-DkQ7aTGY.js"
],
"Publicidade — limite único anual": [
"assets/services-DkQ7aTGY.js"
],
"Créditos — limites anual e acumulado": [
"assets/services-DkQ7aTGY.js",
"assets/project-dossier-EB1GFWid.js"
],
"Conferir correspondência dos temas com os mapas": [
"assets/services-DkQ7aTGY.js"
],
"Aplicar correspondências conferidas dos mapas": [
"assets/services-DkQ7aTGY.js"
],
"Iniciar mapas complementares L6": [
"assets/services-DkQ7aTGY.js"
],
"Saldo final — âmbito L8": [
"assets/project-dossier-EB1GFWid.js"
],
"Calcular e guardar apuramento trimestral ISPC": [
"assets/services-DkQ7aTGY.js"
],
"Calcular e guardar restituição E": [
"assets/services-DkQ7aTGY.js"
],
"Reutilizar selecção cambial": [
"assets/services-DkQ7aTGY.js"
]
},
"assets": [
{
"file": "assets/project-dossier-document-DDnA8FXy.js",
"status": 200,
"sha256": "47280845a07c33b1d2dd3c8f770a9f0f213476e99ad8f927f812c75a66a855df"
},
{
"file": "assets/simulation-form-BqVD91Ek.js",
"status": 200,
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
},
{
"file": "assets/services-DkQ7aTGY.js",
"status": 200,
"sha256": "8782f7a7758e8f25803737ec5e072ba4888ad946d54611ce501364608c24a633"
},
{
"file": "assets/project-dossier-EB1GFWid.js",
"status": 200,
"sha256": "8328b2676e8da123e8126ed718895a0ddaaabed30a80a7cef902be911ef8bffd"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-Dz8nCVw7.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"runtime_delta": [
{
"path": "resources/js/components/simulation-irpc-costs.tsx",
"sha256_LF": "c4156916835daf0f33addf89dfedd40c31b8dc3297112cd98beac33422af274d"
},
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "8001d2e71b58fa07c77f74da2c2b51566659a5d784d9e044133192c66518cb15"
},
{
"path": "resources/js/lib/irpc-normal-base.ts",
"sha256_LF": "fef34966db603633eb03c9830ad3c09e7cd0ffaed49720dbab60f9dc0fd8a8fb"
},
{
"path": "resources/js/lib/irpc-normal-costs.ts",
"sha256_LF": "29aeb16bf8fe60bb322b5449fb3efd84b5108b06112b91be5fc76d8e897d8860"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256_LF": "26810caea4e7d177b385e36452147d84602a7b23cb5f8f23a88488d1bfaf619f"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "98adf3e1c84938d27535f65afa24edc0650bfb12a1f9b32352b0d4d71c2c2035"
}
],
"protected_runtime": [
{
"path": "resources/js/components/simulation-irpc-schedules.tsx",
"sha256": "eebd6d9e4100920a5ebf91b800537ffe301fd6a994b86a3b080d673f4a9c9a42"
},
{
"path": "resources/js/lib/irpc-normal-assessment.ts",
"sha256": "1dc6adc0835af033ef296d12cdc1e9ef354b2f54cd36e2349b2df66e369c1ee3"
},
{
"path": "resources/js/lib/irpc-normal-forms.ts",
"sha256": "4e986addb9f2d74e7a80345f8f1e4d8e0b2f562c867fa6eee84880d9f72a3649"
},
{
"path": "resources/js/lib/irpc-normal-schedules.ts",
"sha256": "b0045fd2c072998ebb290c2a8332c26d05a1f5f746b3beb1805508147497cac8"
},
{
"path": "resources/js/components/simulation-irpc-taxable-base.tsx",
"sha256": "e4fe9f66d35d24aa68fd87de6a5a6a0e901706b270c18962fd0c7ab00f9abd93"
},
{
"path": "resources/js/components/simulation-irpc-assessment.tsx",
"sha256": "7174cc0160005a0c332ea40f02ba8a6d57985081b5ab45177ccd6e721bceea54"
},
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
{
"path": "resources/js/lib/financial-fiscal-bridge.ts",
"sha256": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
}
],
"originals": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"pipeline_checks": [
"OK (1 test, 3106 assertions)",
"built in 31.63s",
"OK (59 tests, 317 assertions)",
"# tests 942",
"# pass 942",
"# fail 0"
],
"accepted_QA_proofs": {
"new_frontend_tests": 22,
"private_API_tests": 1,
"private_API_assertions": 83,
"database": "127.0.0.1:55441/simulator_fiscal_delta_20261021_test;DatabaseTransactions rollback",
"routes_actions": "generated by existing guarded procedure",
"typescript": "passed",
"build": "passed",
"UI": "actual component;fieldediting;missingconditions;reviewed topic reconciliation;sharedcaps;local roundtrip;download;mandatory work method",
"dossier": "generated from5 API recovered cases",
"accepted_functional_suites": "reused,not manually repeated"
},
"accepted_proofs_reused": true,
"manually_repeated_accepted_suites": false,
"sequence": {
"taxable_profit": "6730MZN simulated",
"taxable_base": "4430MZN simulated",
"normal_colecta": "1417.60MZN simulated,32%",
"final_payable": null,
"final_recoverable": null,
"final_balance_scope": "L8"
},
"remaining_L6": [
{
"pending_case_or_mapping": "Combinação36h/i com36(4)",
"resolution_condition": "Corresponder a regra de articulação dos trechos aplicáveis ou esclarecer comAT o exemplo combustível100/comprovado80/passageiro sem excepção;sem somar ou repartir correcções por presunção.",
"blocking_scope": "Apenas o caso/campo dependente."
},
{
"pending_case_or_mapping": "Quota36h automática e amortizações restantes",
"resolution_condition": "Reconciliar tabela/método/entrada emuso/quotas contabilísticas e fiscais anteriores;prioridade seguinte deL6. A parcela36h documentada continua reutilizável nos casos independentes.",
"blocking_scope": "Apenas o caso/campo dependente."
},
{
"pending_case_or_mapping": "Campanhas plurianuais36-A e limite1%",
"resolution_condition": "Implementar a periodização por três exercícios e a sua articulação com36n; não tratar a campanha como publicidade ordinária.",
"blocking_scope": "Apenas o caso/campo dependente."
},
{
"pending_case_or_mapping": "Provisões reguladas28d e reforços financeiros28(3)",
"resolution_condition": "Corresponder a regra sectorial/supervisão ou o reforço financeiro e os saldos documentados; não usar os limites ordinários29 por aproximação.",
"blocking_scope": "Apenas o caso/campo dependente."
},
{
"pending_case_or_mapping": "Receita antecipada19(5) positiva e mudança autorizada19(6)",
"resolution_condition": "Corresponder os custos futuros/receita antecipada e o transporte entre exercícios ou a autorização da mudança de método;os casos zero conhecido/método mantido permanecem executáveis.",
"blocking_scope": "Apenas o caso/campo dependente."
},
{
"pending_case_or_mapping": "Outras periodizações,âmbitos eM20/M22",
"resolution_condition": "Tratar apenas os casos específicos18(6–10),períodos curtos/conversão anual,representação fiscal e campos ainda sem correspondência,com os parâmetros da edição/caso;divergência201/Q8 versus200/Q10 só afecta o transporte indicado.",
"blocking_scope": "Apenas o caso/campo dependente."
}
],
"matrix_row": "AUD-SIM-INT02",
"L6_complete": false,
"L7_L8_own_scopes": true,
"documentary_divergence": "Only result transfer M20A.1 field201/Q8 versus PDFM22 field200/Q10;independent calculations and mapped fields remain available",
"L5_ten_questions": "unchanged;only dependent cases blocked;no new research",
"documentation_runtime_changed": false,
"proof_files": {
"backup.txt": "a40060e515e6f9a23962654ceca1384a8c4f3a9c0b5cb84a2510a892172023f5",
"compact-dependencies.txt": "52b6b2b5abe937c37c975efa4c595eb0c38b5f23ea9d342786d859c63eb30ebf",
"installed-protected.txt": "d10547839935cf162a2f335aafc6d0e274b1623338fbb3c51031c27ac7fde19c",
"installed-public-delta.json": "00db424cb414c133adb85ae8bd1b3bfa7dc01b89b3bc055db71ab7b921651981",
"installed-public.txt": "ab32725cb73e82888851b46ffc2111e23a839567ccfafca945e6ee2d72f967f0",
"integration.txt": "cb09cb7139c730d7e178de518c4158347725009d4ccee9fc0252e8da7cd6bbc3",
"manifest-served.json": "d91dd39d49e9e0251c76c811ca6a0798b7cf544e3e807735574ba51691afac9e",
"operational-delta.txt": "8739d8f2cc58dd500e8fa393eb65ed15d24ba840e30f429e135d0ed8b49cd60f",
"preflight.txt": "289577c3c3a959ec01405e5bc3d929a0b7be1654579b4bfd32f82ab20c3f22c2",
"preparation.json": "603d3e4f9a40b91a717945160a11723ca3ddeb0e329af69179dba8276f0d4331",
"remaining-section.md": "253d4d1de16bbfe6253971507c3a2e3976ea9ce017930d9ba80eef8c1191955e",
"restore.txt": "bbdee061e3947b1e606c04ad17f83d5951cca0be0d33027a9e20be76121f38b7",
"schema-permissions-after.txt": "76b5a4d8af11e4898a205062766cfb7ab6ec0783200e77e60a1927aa1ca18597",
"schema-permissions-before.txt": "0ab7c964792acdd8917bce256c472e55e034b103500a58b49f020b5084823ed7",
"status-final.txt": "04413dcbffc95e88abd7f5201b5709ee7a3b9856ccf0c5824d9a4d036ea6d3b4",
"status1.txt": "177d1c66d844074ffb3db7b1392804f4de92ab804076671750362b9987a748e5",
"status2.txt": "04413dcbffc95e88abd7f5201b5709ee7a3b9856ccf0c5824d9a4d036ea6d3b4"
}
}
@@ -0,0 +1,869 @@
{
"status": "compatible_cost_limits_provisions_timing_QA_prepared_not_installed",
"installed_baseline": "a2de725901c308fb2ac2bc3d72181ab50ef46b7a",
"branch": "codex/irpc-l6-costs-provisions-timing-qa-20261026",
"QA_workspace": "C:\\laragon\\www\\portal-investidor-irpc-l6-costs-qa-20261026",
"version": "IRPC-normal-adjustments/6",
"scope": "AnnualMZN periods ending2026,ordinary documented cost/provision categories and prior-year/work timing;normal profit/base/colecta only;L7/L8 remain own scopes.",
"demonstrated_sequence": {
"accounting_profit": "6240MZN unchanged",
"previous_addbacks": "220MZN",
"previous_schedule_effect": "520MZN",
"new_cost_provision_prior_timing_adjustments": "350MZN",
"new_work_adjustment": "-600MZN",
"taxable_profit": "6730MZN",
"previous_loss_deduction": "2300MZN explicit,unchanged",
"taxable_base": "4430MZN",
"rate": "32%",
"colecta": "1417.60MZN",
"final_payable": null,
"final_recoverable": null,
"final_balance_scope": "L8"
},
"cases_recovered_by_private_API": {
"calculated": {
"profit": {
"numerator": "6730",
"denominator": "1"
},
"base": {
"numerator": "4430",
"denominator": "1"
},
"colecta": {
"numerator": "7088",
"denominator": "5"
},
"cost_effect": {
"numerator": "-250",
"denominator": "1"
},
"pending": [],
"payable": null,
"recoverable": null
},
"missing": {
"profit": null,
"base": null,
"colecta": null,
"cost_effect": {
"numerator": "-400",
"denominator": "1"
},
"pending": [
"QA-credit: Provisão fiscal anterior dos créditos em falta; não presumir zero."
],
"payable": null,
"recoverable": null
},
"additional": {
"profit": {
"numerator": "7050",
"denominator": "1"
},
"base": {
"numerator": "4750",
"denominator": "1"
},
"colecta": {
"numerator": "1520",
"denominator": "1"
},
"cost_effect": {
"numerator": "70",
"denominator": "1"
},
"pending": [],
"payable": null,
"recoverable": null
},
"limits": {
"profit": {
"numerator": "7210",
"denominator": "1"
},
"base": {
"numerator": "4910",
"denominator": "1"
},
"colecta": {
"numerator": "7856",
"denominator": "5"
},
"cost_effect": {
"numerator": "230",
"denominator": "1"
},
"pending": [],
"payable": null,
"recoverable": null
},
"closing": {
"profit": {
"numerator": "6530",
"denominator": "1"
},
"base": {
"numerator": "4230",
"denominator": "1"
},
"colecta": {
"numerator": "6768",
"denominator": "5"
},
"cost_effect": {
"numerator": "-450",
"denominator": "1"
},
"pending": [],
"payable": null,
"recoverable": null
}
},
"categories_demonstrated": {
"allowance": {
"case": "calculated",
"source_amount": {
"numerator": "100",
"denominator": "1"
},
"accepted": {
"numerator": "70",
"denominator": "1"
},
"adjustment": {
"numerator": "30",
"denominator": "1"
},
"limit": {
"numerator": "30",
"denominator": "1"
},
"rule_source": "CIRPC36(1)e",
"reason": "50% só da parcela não facturada a clientes nem tributada emIRPS; parcelas mutuamente exclusivas."
},
"representation": {
"case": "calculated",
"source_amount": {
"numerator": "50",
"denominator": "1"
},
"accepted": {
"numerator": "10",
"denominator": "1"
},
"adjustment": {
"numerator": "40",
"denominator": "1"
},
"limit": null,
"rule_source": "CIRPC36(1)f/36(3)",
"reason": "20% aceite;80% acrescido. Eventual tributação autónoma não calculada, âmbitoL7."
},
"advertising": {
"case": "calculated",
"source_amount": {
"numerator": "80",
"denominator": "1"
},
"accepted": {
"numerator": "80",
"denominator": "1"
},
"adjustment": {
"numerator": "0",
"denominator": "1"
},
"limit": {
"numerator": "120",
"denominator": "1"
},
"rule_source": "CIRPC36(1)n,Lei20/2009",
"reason": "Limite único anual1% das vendas normais; repartição aritmética proporcional entre parcelas para a simulação, sem ordem fiscal obrigatória."
},
"credit": {
"case": "calculated",
"source_amount": {
"numerator": "200",
"denominator": "1"
},
"accepted": {
"numerator": "50",
"denominator": "1"
},
"adjustment": {
"numerator": "150",
"denominator": "1"
},
"limit": {
"numerator": "50",
"denominator": "1"
},
"rule_source": "CIRPC28(1)a/29",
"reason": "29:1,5% anual,6% acumulado sobre créditos da actividade normal existentes no fim; saldo fiscal anterior conhecido. Repartição proporcional do limite único, sem consumir saldo oficial."
},
"stock": {
"case": "calculated",
"source_amount": {
"numerator": "60",
"denominator": "1"
},
"accepted": {
"numerator": "30",
"denominator": "1"
},
"adjustment": {
"numerator": "30",
"denominator": "1"
},
"limit": {
"numerator": "40",
"denominator": "1"
},
"rule_source": "CIRPC28(1)b",
"reason": "28b:limite das perdas efectivamente observadas, incluindo saldo anterior."
},
"litigation": {
"case": "calculated",
"source_amount": {
"numerator": "90",
"denominator": "1"
},
"accepted": {
"numerator": "80",
"denominator": "1"
},
"adjustment": {
"numerator": "10",
"denominator": "1"
},
"limit": {
"numerator": "100",
"denominator": "1"
},
"rule_source": "CIRPC28(1)c",
"reason": "28c:obrigações de processo judicial em curso que seriam custos dedutíveis, com saldo anterior reconciliado."
},
"fuel": {
"case": "calculated",
"source_amount": {
"numerator": "50",
"denominator": "1"
},
"accepted": {
"numerator": "40",
"denominator": "1"
},
"adjustment": {
"numerator": "10",
"denominator": "1"
},
"limit": null,
"rule_source": "CIRPC36(1)i/36(4)",
"reason": "36i: parcela ligada a activo próprio/locado e consumo normal comprovados."
},
"prior_cost": {
"case": "calculated",
"source_amount": {
"numerator": "80",
"denominator": "1"
},
"accepted": {
"numerator": "0",
"denominator": "1"
},
"adjustment": {
"numerator": "80",
"denominator": "1"
},
"limit": null,
"rule_source": "CIRPC18(2)",
"reason": "18(2):conhecido/previsível no encerramento anterior; excluído do actual, sem alterar declarações/históricos anteriores."
},
"work": {
"case": "calculated",
"source_amount": {
"numerator": "1000",
"denominator": "1"
},
"accepted": {
"numerator": "200",
"denominator": "1"
},
"adjustment": {
"numerator": "-600",
"denominator": "1"
},
"limit": {
"numerator": "400",
"denominator": "1"
},
"rule_source": "CIRPC19(1–6)",
"reason": "19:grau=incorrido/custo total;valores fiscais do exercício obtidos dos acumulados menos o já reconhecido. Proveito fiscal corrente:400.00 MZN;custo fiscal corrente:200.00 MZN;sem imposto/pagamento ou perda estimada presumidos."
},
"vehicle": {
"case": "additional",
"source_amount": {
"numerator": "100",
"denominator": "1"
},
"accepted": {
"numerator": "50",
"denominator": "1"
},
"adjustment": {
"numerator": "50",
"denominator": "1"
},
"limit": null,
"rule_source": "CIRPC36(4)",
"reason": "50% dos outros encargos de passageiros, excepto serviço público de transportes/locação na actividade normal; não inclui quotas, aluguer sem condutor ou combustível já discriminados."
},
"rental": {
"case": "additional",
"source_amount": {
"numerator": "100",
"denominator": "1"
},
"accepted": {
"numerator": "80",
"denominator": "1"
},
"adjustment": {
"numerator": "20",
"denominator": "1"
},
"limit": null,
"rule_source": "CIRPC36(1)h/36(4)",
"reason": "36h: reutiliza parcela de quota não aceite documentada; o portal não apura automaticamente essa quota de viatura."
},
"estimated_work_loss": {
"case": "additional",
"source_amount": {
"numerator": "50",
"denominator": "1"
},
"accepted": {
"numerator": "0",
"denominator": "1"
},
"adjustment": {
"numerator": "50",
"denominator": "1"
},
"limit": null,
"rule_source": "CIRPC36(1)m,Lei20/2009",
"reason": "36m:perda meramente estimada em obra em curso não dedutível; custo efectivo não confundido com estimativa."
},
"provision_reversal": {
"case": "additional",
"source_amount": {
"numerator": "50",
"denominator": "1"
},
"accepted": {
"numerator": "50",
"denominator": "1"
},
"adjustment": {
"numerator": "50",
"denominator": "1"
},
"limit": null,
"rule_source": "CIRPC28(2)",
"reason": "28(2):proveito da provisão antes deduzida; só acresce quando ainda não incluído no resultado."
},
"taxed_reversal": {
"case": "additional",
"source_amount": {
"numerator": "50",
"denominator": "1"
},
"accepted": {
"numerator": "50",
"denominator": "1"
},
"adjustment": {
"numerator": "-50",
"denominator": "1"
},
"limit": null,
"rule_source": "CIRPC17/28;sem dupla tributação da parcela comprovada",
"reason": "Parcela antes tributada comprovada; exclui a reversão contabilística sem duplicar dedução."
},
"prior_income": {
"case": "additional",
"source_amount": {
"numerator": "50",
"denominator": "1"
},
"accepted": {
"numerator": "0",
"denominator": "1"
},
"adjustment": {
"numerator": "-50",
"denominator": "1"
},
"limit": null,
"rule_source": "CIRPC18(2)",
"reason": "18(2):conhecido/previsível no encerramento anterior; excluído do actual, sem alterar declarações/históricos anteriores."
}
},
"verification": {
"new_frontend_tests": 22,
"private_API_tests": 1,
"private_API_assertions": 83,
"database": "127.0.0.1:55441/simulator_fiscal_delta_20261021_test;DatabaseTransactions rollback",
"routes_actions": "generated by existing guarded procedure",
"typescript": "passed",
"build": "passed",
"UI": "actual component;fieldediting;missingconditions;reviewed topic reconciliation;sharedcaps;local roundtrip;download;mandatory work method",
"dossier": "generated from5 API recovered cases",
"accepted_functional_suites": "reused,not manually repeated"
},
"preservation": {
"installed5_fixture_sha256": "109426b86ae7c14463699b1d197064617f124ecec0c55085d9e81aeddc505a5a",
"matches_accepted5_fixture": true,
"versions1_to5_current_keys": "unchanged without optional costs input",
"history": "old record preserved unchanged on new calculation;no rewriting prior returns",
"other_books": "preserved in snapshot roundtrip",
"source_plan": "reused,no re-entry of financial result/base/colecta",
"schema_API_config_permissions_dependencies_changed": false,
"active_data_changed": false,
"official_fiscal_balances_consumed": false,
"fractional_precision_delta": "Exact numerator comparison for current loss and loss-deduction cap;negative subcent result cannot be truncated to zero"
},
"runtime_delta_joint_from_a2de7259": [
{
"path": "resources/js/components/simulation-irpc-costs.tsx",
"sha256_LF": "c4156916835daf0f33addf89dfedd40c31b8dc3297112cd98beac33422af274d"
},
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "8001d2e71b58fa07c77f74da2c2b51566659a5d784d9e044133192c66518cb15"
},
{
"path": "resources/js/lib/irpc-normal-base.ts",
"sha256_LF": "fef34966db603633eb03c9830ad3c09e7cd0ffaed49720dbab60f9dc0fd8a8fb"
},
{
"path": "resources/js/lib/irpc-normal-costs.ts",
"sha256_LF": "29aeb16bf8fe60bb322b5449fb3efd84b5108b06112b91be5fc76d8e897d8860"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256_LF": "26810caea4e7d177b385e36452147d84602a7b23cb5f8f23a88488d1bfaf619f"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "98adf3e1c84938d27535f65afa24edc0650bfb12a1f9b32352b0d4d71c2c2035"
}
],
"protected_runtime": [
{
"path": "resources/js/components/simulation-irpc-schedules.tsx",
"sha256_LF": "eebd6d9e4100920a5ebf91b800537ffe301fd6a994b86a3b080d673f4a9c9a42"
},
{
"path": "resources/js/lib/irpc-normal-assessment.ts",
"sha256_LF": "1dc6adc0835af033ef296d12cdc1e9ef354b2f54cd36e2349b2df66e369c1ee3"
},
{
"path": "resources/js/lib/irpc-normal-forms.ts",
"sha256_LF": "4e986addb9f2d74e7a80345f8f1e4d8e0b2f562c867fa6eee84880d9f72a3649"
},
{
"path": "resources/js/lib/irpc-normal-schedules.ts",
"sha256_LF": "b0045fd2c072998ebb290c2a8332c26d05a1f5f746b3beb1805508147497cac8"
},
{
"path": "resources/js/components/simulation-irpc-taxable-base.tsx",
"sha256_LF": "e4fe9f66d35d24aa68fd87de6a5a6a0e901706b270c18962fd0c7ab00f9abd93"
},
{
"path": "resources/js/components/simulation-irpc-assessment.tsx",
"sha256_LF": "7174cc0160005a0c332ea40f02ba8a6d57985081b5ab45177ccd6e721bceea54"
},
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256_LF": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256_LF": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256_LF": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256_LF": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256_LF": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256_LF": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256_LF": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256_LF": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256_LF": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256_LF": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256_LF": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256_LF": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256_LF": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256_LF": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256_LF": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256_LF": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256_LF": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256_LF": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256_LF": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256_LF": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256_LF": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256_LF": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256_LF": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256_LF": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256_LF": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256_LF": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256_LF": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256_LF": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
{
"path": "resources/js/lib/financial-fiscal-bridge.ts",
"sha256_LF": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256_LF": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256_LF": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256_LF": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
}
],
"originals_preserved": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"source_evidence": [
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"new_clauses": "18(2)/19 PDF6–7;28/29 PDF8–9;36e/f/h/i/4 PDF10–11",
"use": "ordinaryconditions/rates/caps/timing,visual excerpts retained inQA"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"new_clauses": "PDF2 retains18(1–6),adds7–10;PDF3 updates28 wording;PDF4 adds36m/n and36-A",
"use": "provisions/estimatedworkloss/ordinary advertising1percent;campaign36-A explicitlypending"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"new_clauses": "PDF2 retains36a–n;adds36o",
"use": "scope cross-check of supplied amended source"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"new_clauses": "PDF2 retains36a–o;adds p/q",
"use": "scope cross-check;no new related-party interest rule introduced"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"use": "Existing supplied scope ofLei12/2025,source acceptance and rateproof reused;no unrelated revalidation or L5 research"
}
],
"case_specific_remaining": [
{
"case": "Overlapping36h/i exclusion and36(4)50percent",
"example": "Fuel100,supported80,ordinary passenger vehicle",
"condition": "Correspond explicit combination rule for the cited clauses or obtain a targeted AT clarification;no additive/proportional tax rule presumed"
},
{
"case": "Rental36h quota",
"condition": "Supply documented nonaccepted quota for supported matching;automatic vehicle-quota determination remains in asset scope"
},
{
"case": "Multi-year launch campaign36-A and1percent limit",
"condition": "Implement3exercise timing and its interaction with36n;do not treat as ordinary advertising"
},
{
"case": "Regulated provisions28d,financial unwind28(3),other sector provisions",
"condition": "Map applicable supervision/sector rule and documented balances;do not reuse ordinary29 caps"
},
{
"case": "Positive deferred receipts19(5),authorised method change19(6)",
"condition": "Map remainingcost/deferredreceipt rollforward and applicable authorisation;only knownzero deferral/unchanged method demonstrated"
},
{
"case": "Specific timing18(6–10),other asset/method/shortperiod/annualFX/fiscalrepresentation/form mappings",
"condition": "Remaining concrete L6 cases preserved in existing matrix,not closed by this ordinary increment"
}
],
"m20_m22_divergence": "Unchanged and limited to result transfer201/Q8 versus200/Q10;no dependency gate in cost calculation;no new official field correspondence presumed",
"L5_ten_questions": "unchanged,not researched;only actual dependent cases blocked",
"L6_complete": false,
"L7_L8_own_scopes": true,
"installation_performed": false,
"proof_sha256": {
"additional.json": "b76790cb34736281fd181cbf0c871135cb42e75e1acc34ab3c42ed7e696ad5b1",
"api.txt": "dff9be0d1338e833adf5c7f10dc4c4e5d5cefde97f284db927608f3c3c334be2",
"build-exit.txt": "13bf7b3039c63bf5a50491fa3cfd8eb4e699d1ba1436315aef9cbe5711530354",
"build.txt": "21ce0d3af4edc5c74d5cbeebd817b4716b233b0eb54ad03b1f22ebe80edd844a",
"calculated.json": "23119339a0337c755f2a045078903858b7da6b95196a91de51170ca115d468a7",
"closing.json": "9f87eec9710aeec4819a7b10b64986ad9e4afbb458cd95a49a8f6f035c235ad8",
"Decreto-9-2008-BR16.txt": "c680dfb73eeb638cf85d06fb0fe19550487de2994ce76f60077ef4baa88e3238",
"dossier-additional.json": "19ad04483c38306982cd182e08445952ec1e5ad5ce821cc345df5ccf75ac4a7a",
"dossier-calculated.json": "99c4bff798b7338138216a405aa5de228e88429af3c12290bf1b7071bd40e01a",
"dossier-closing.json": "d054eb3da44363d3861037c7bb59074572f630078f6d3aa3d2e4de89983928b0",
"dossier-limits.json": "52aaea2415159cacdbc44d56a98918a8438e3bacde06199e0545a265b7d6982d",
"dossier-missing.json": "50eff5af4b909ef08f4619ac768d5e8f8d4de01d003c81ef3748bd74a9bccfe2",
"dossier.mjs": "0824a3b05fa4bf758bbb165c0fce74fe9cd6ab817ceda5437ef7c73b28794a46",
"download.html": "ebf40a955530b10753da0cfd7769c0ad879b079bdade64f4e06ec901912456df",
"frontend.txt": "c6aa5222a8b5c867e50a2aca4ab5edd6ab9812f9fb2f6bce8482092951e022bd",
"index.html": "09941968500d2910121bdcb0029e326fc6d44bb025b01766654289a28caa62fa",
"Lei-19-2013-BR76-page2.png": "952cb5d68fa162043964c282b1ac32faf8bcbb92f2bb83fef2084ae691afae12",
"Lei-19-2013-BR76.txt": "7060584c3e59f0b2f12f34aa0b40faadf4aa5790a0459f3319852bcd63262cbb",
"Lei-20-2009-BR36-AT-exemplar19-page2.png": "e39eadef731b6c3ae8cb4820238c4db3184111557d982a20dadee139ea2952a2",
"Lei-20-2009-BR36-AT-exemplar19-page3.png": "a4a39a81849f32e4c596ef7c0726d2054e74bf45531dd8e920d3927cafdb70bd",
"Lei-20-2009-BR36-AT-exemplar19-page4.png": "cafa0e22b0f29296bd28772609fa87708811704c25ae7bf676dba53783e25168",
"Lei-20-2009-BR36-AT-exemplar19.txt": "2e04eb1c5be52619e21eb1c376f71603d998672f4c220e0bfc1648df80d5e6fe",
"Lei-34-2007-BR52-page10.png": "74937b18d2863c1199e88380e25d39c7ada80c37621196e5402bffa61f6b49be",
"Lei-34-2007-BR52-page6.png": "de2c1cc9c8bf5b0cefa9671cc8ad776e21a8492b791648be492d1540d78f748f",
"Lei-34-2007-BR52-page8.png": "f69bbe8484e315a5bf5818277c1bb3d67e4e86724544b34565731d5c3f4408df",
"Lei-34-2007-BR52-page9.png": "e449f13d39c9f23e408c185e00bafd621706d9cccd037d399e602eece33b6ba5",
"Lei-4-2012-BR3-page2.png": "99c5a820ad1e1201af25f60b51c86b3c7bced25acc12343366eadb3133185128",
"Lei-4-2012-BR3.txt": "9478ac3ef61ae9df286d951edbfce4c24049f65e860f053ed9eb2c3fbd78d051",
"limits.json": "c73905029246c1bbdf91b24869582b6057d62d01dd853e76d2e603786d8810ea",
"missing.json": "159c4d3f21d87ff3ea43ad5cfa8a42faea05105feab0a4b5529d37e72d9aea73",
"originals-inventory.json": "f91baf686619187dac23bce2c3bde71cc7ddf201fef10a24479548c44abc7d94",
"preparation.html": "e9951a85471c44fd9ff5211e59a8eb740e5b8823a4bb6b63c12237feb3d997fd",
"qa.tsx": "58e66698e44d68d169117a70d0d15aa07ce77b88bed1234d922d0844a9aac9b0",
"recovered-additional.html": "3f562a91fcc2ba6f47c1661f13a39a6c7d939c4730bd4ba9178b60fb05d5b6a6",
"recovered-additional.json": "a7adf543887479edf259d2501fe061a14c8aa03e206848726fae0f567b594419",
"recovered-calculated.html": "e9951a85471c44fd9ff5211e59a8eb740e5b8823a4bb6b63c12237feb3d997fd",
"recovered-calculated.json": "e000b426aefbfad520fe2a03707ca756a87fe04ab39536d509008e03c6288c2b",
"recovered-closing.html": "d17bd5944b2f37d752883b22955bcd3c57695f72b464580087403dfa448d785e",
"recovered-closing.json": "5f1b2cbe830154e35e60512882aa023fdc443125cf37253e10b85af7f47dddb2",
"recovered-limits.html": "4b24bebe5b4d93bc6b06233d795197bb28ca4116eb29832981bafb33804d1a2d",
"recovered-limits.json": "28611229e027a0d51593ecf71bae32b6f35f7f2767c26680fa2dceb0e7d9ad11",
"recovered-missing.html": "6fa22cb9757a5812d23a1615a43337f20ba1812097d8b4d79c1a3db1a356d8dd",
"recovered-missing.json": "b5aa2c3045d79193518621b4764540775470db97bdbc84ac19804c70baa05324",
"types.txt": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"ui-calculated.png": "3c1070fbb0b9ca66d1b128935ab23e737a11ee2918fc566259a5d70bbae4aa26",
"ui-missing.png": "d0c1c138e9b2404ae8a17c0732d8ab1b7bfbcf89ff431aa4d80e3dfaf7f8d5db",
"ui-proof.json": "108af6bd1557c6a920842102b1a9b54711fc3ab96e32296e1c2c3f77abda177a",
"ui.cjs": "2de9dd0e333edca1a3fd23a6e409cd41271f619cfb2186bbfdf6444855dd35d0",
"ui.txt": "8799b836baa3cf8efefce8a5b0b6951c7963e50fb3e08b0be3d2de3434ff4795",
"vite.config.ts": "2ad3c19a485d8175b33550b017f2a67934f9fbebda5f6f16e69b9fb89809c398"
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,682 @@
{
"status": "installed_L6_short_periods_and_foreign_currency_plans",
"installed": {
"status": "installed",
"commit": "56475acb2f39e58cb51664913f7fb499f58eb7ab",
"release": "/var/www/investmoz-homologacao/releases/56475acb2f39e58cb51664913f7fb499f58eb7ab-694b3932",
"previous_release": "/var/www/investmoz-homologacao/releases/e9fe102259c183a9d9bf7e39f246a8c3860839c6-0e29d858",
"database_migrations": 0,
"content_imports": 0
},
"previous_baseline": "e9fe102259c183a9d9bf7e39f246a8c3860839c6",
"backup": {
"stage": "/var/backups/investmoz-irpc-l6-periods-fx-delivery-20261026/backup",
"created_at": "2026-10-26T08:17:39Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "9ecd9f379351437f88009aa6da072e09ec8616fd782b929919ade05be1493bdc",
"files_sha256": "6da03ab176387b105da1345764f3b292794d8867d0ed4add47197e0a1e5854fa",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l5_restore_20261025",
"port": 55441,
"source_dump_sha256": "9ecd9f379351437f88009aa6da072e09ec8616fd782b929919ade05be1493bdc",
"active_database_writes": 0
},
"preservation": {
"previous_release_preserved": "/var/www/investmoz-homologacao/releases/e9fe102259c183a9d9bf7e39f246a8c3860839c6-0e29d858",
"installed": {
"status": "installed",
"commit": "56475acb2f39e58cb51664913f7fb499f58eb7ab",
"release": "/var/www/investmoz-homologacao/releases/56475acb2f39e58cb51664913f7fb499f58eb7ab-694b3932",
"previous_release": "/var/www/investmoz-homologacao/releases/e9fe102259c183a9d9bf7e39f246a8c3860839c6-0e29d858",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 9,
"preserved_L3_ISPC_FX_runtime_files_verified": 43,
"documentary_files_verified": 31,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 106,
"checksum": "1b8bf615a2fdea986761abc88bfb4419"
},
"after": {
"rows": 106,
"checksum": "a845f75cfcf49b86ebb8a3816f886a63"
}
},
"sessions": {
"before": {
"rows": 9,
"checksum": "635e8bece48c8f7780635c0c79cd6010"
},
"after": {
"rows": 12,
"checksum": "703dbf39af0534461019da7c73354454"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"schema_permissions": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart;requestthrottle;identical home-sector cached value with refreshed expiry(HomeController remember10min);no deletedcache",
"sessions": "anonymous sessions from delivery user-agent or exactUA/time correlated with nginx public request;deleted sessions individually expired beyond configured lifetime,normal database session garbage collection(config/session lottery2/100)",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "dbb99b7e17f5b4b9bb7a8bdf9350d9b2ae368aaa4bc44593a2522d87617d8461",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-{hash}",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true,
"same_value_home_cache_expiry_refresh": false
},
{
"key_sha256": "c1c7bc86ef3255c103a0be6aeb651b824eb07259e993cc5daf3665c1a6afff2d",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-{hash}:timer",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true,
"same_value_home_cache_expiry_refresh": false
},
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false,
"same_value_home_cache_expiry_refresh": false
}
]
},
"sessions": {
"before_rows": 9,
"after_rows": 12,
"changes": [
{
"key_sha256": "6e12944bc8f670195d0c6d2638337e2bf922261a158d130ba09f640a5722f0df",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "11bbe5f81c536cf605ed71f402fbaa6e9ef551d97c0a76e098078521d9f37f71",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
},
{
"key_sha256": "d0a4dbafaf19e2eee3af4ea41ce9aabf52cb42d5a61a598c54b37d8863b533d7",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true,
"expired_before_comparison": false,
"session_lifetime_minutes": 120,
"anonymous_public_request_logged": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"dependency_archiving": {
"status": "dependencies_archived_and_verified",
"versions": 5,
"free_before": 5329760256,
"free_after": 6645653504,
"receipt": "/var/backups/investmoz-build-dependencies-irpc-l6-periods-fx-20261026/receipt.json",
"protected": [
"/var/www/investmoz-homologacao/releases/043dd35d8ee247123b3a32f1fc10fd2ede81e9f4-917b3c47",
"/var/www/investmoz-homologacao/releases/e9fe102259c183a9d9bf7e39f246a8c3860839c6-0e29d858"
],
"active_or_previous_release_modified": false,
"source_data_backups_deleted": 0
},
"public_verification": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "56475acb2f39e58cb51664913f7fb499f58eb7ab",
"branch": "main",
"built_at": "2026-10-26T08:23:47.654431+00:00",
"manifest_sha256": "f6121cade74d12c6de25630b23a1bd73f244a089c2649bf2c3aa76c68491431c"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"IRPC-normal-adjustments/8": [
"assets/project-dossier-BGxws1O_.js"
],
"Preparar período curto ou plano noutra moeda": [
"assets/services-08vnaMl1.js"
],
"Primeiro mês civil do plano": [
"assets/services-08vnaMl1.js"
],
"Pressuposto documentado da conversão mensal para simulação": [
"assets/services-08vnaMl1.js"
],
"Saldo final — âmbito L8": [
"assets/project-dossier-BGxws1O_.js"
],
"Reutilizar selecção cambial": [
"assets/services-08vnaMl1.js"
]
},
"assets": [
{
"file": "assets/services-08vnaMl1.js",
"status": 200,
"sha256": "6cc2b1bfb11744376ae71d1f0429ee776ef6f004edca72a4f22c5a9ef4937688"
},
{
"file": "assets/project-dossier-BGxws1O_.js",
"status": 200,
"sha256": "f2dc461eca8219602099ac2cf17f52f5adedc4553f4b0e48bbeba273041d9bca"
},
{
"file": "assets/project-dossier-document-BYlep2jg.js",
"status": 200,
"sha256": "0ece3300111d8e5c0e094c2c1688604349de11cde057583bd83d8ae3742c8a99"
},
{
"file": "assets/simulation-form-BqVD91Ek.js",
"status": 200,
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-DoIk7pr3.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"runtime_delta": [
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "557714bb3af75080e443ae67b11a66d9feb49d9a4b269065769b128a6d712837"
},
{
"path": "resources/js/components/simulation-irpc-period-fx.tsx",
"sha256_LF": "4b5f718b5ef415ecf5f96dabb0e3806254558c20905de6478e10dacf67569c49"
},
{
"path": "resources/js/components/simulation-irpc-schedules.tsx",
"sha256_LF": "3768c316d5887d337eb3647671863c9464f961d1df4703403e7d57e5641273ed"
},
{
"path": "resources/js/lib/irpc-normal-assessment.ts",
"sha256_LF": "a9b3ced852e37e3e087ce5dab1add4ec0737145ce19f61857a54d5d3d24a6f8c"
},
{
"path": "resources/js/lib/irpc-normal-base.ts",
"sha256_LF": "22019d678f6eb16fead2207dc3d3fa9fd63413c6254633c1ffd4f1c0320344ac"
},
{
"path": "resources/js/lib/irpc-normal-costs.ts",
"sha256_LF": "471457692a2a2f70a1bd1c7abb38d3ce42f07b62a63e5a4ab985ad1bbd068b46"
},
{
"path": "resources/js/lib/irpc-normal-depreciation.ts",
"sha256_LF": "1dad3053157aeac44f6d3bd58885cfc47a73c19d2808284c16931679dfe4291b"
},
{
"path": "resources/js/lib/irpc-normal-period-fx.ts",
"sha256_LF": "a2e7b066623eae17f0d8185d065d0adf5d3a485f780f8b09118a664dc4ba0531"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "e4de2fe0421e489bf555885b9cbb459c00ee77803ea9b6e5af45179bd6bb4f21"
}
],
"protected_runtime": [
{
"path": "resources/js/components/simulation-irpc-depreciation.tsx",
"sha256": "1f9918bfb435bb5b7c0ddd2fafd7bace2a02514c6ece04b93f15975e494a5f53"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256": "909e129a0245e6bf098317485b886a2d19e02c64bbfd9c6f718e98ec6b935b8d"
},
{
"path": "resources/js/lib/irpc-normal-schedules.ts",
"sha256": "edfb6fd338411fa8f87a6bdf9a9d4fd5c6dc2fad9d2eb3d32f2640e2951cbbe9"
},
{
"path": "resources/js/components/simulation-irpc-costs.tsx",
"sha256": "c4156916835daf0f33addf89dfedd40c31b8dc3297112cd98beac33422af274d"
},
{
"path": "resources/js/lib/irpc-normal-forms.ts",
"sha256": "4e986addb9f2d74e7a80345f8f1e4d8e0b2f562c867fa6eee84880d9f72a3649"
},
{
"path": "resources/js/components/simulation-irpc-taxable-base.tsx",
"sha256": "e4fe9f66d35d24aa68fd87de6a5a6a0e901706b270c18962fd0c7ab00f9abd93"
},
{
"path": "resources/js/components/simulation-irpc-assessment.tsx",
"sha256": "7174cc0160005a0c332ea40f02ba8a6d57985081b5ab45177ccd6e721bceea54"
},
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
{
"path": "resources/js/lib/financial-fiscal-bridge.ts",
"sha256": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
}
],
"originals": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"pipeline_checks": [
"OK (1 test, 3106 assertions)",
"built in 31.08s",
"OK (59 tests, 317 assertions)",
"# tests 973",
"# pass 973",
"# fail 0"
],
"accepted_QA_proofs": {
"frontend_tests": 13,
"API_tests": 1,
"API_assertions": 58,
"database": "127.0.0.1:55441/simulator_fiscal_delta_20261021_test;DatabaseTransactions rollback",
"routes_actions": "generated by guarded existing procedure",
"typescript": "passed",
"build": "passed",
"UI": "actual component;dates/FX edit+confirmation;originals/assumptions;save/recovery/export;missingdata",
"accepted_proofs": "reused"
},
"accepted_proofs_reused": true,
"manually_repeated_accepted_suites": false,
"sequence": {
"short_period": "3130→3130→colecta1001.60MZN",
"USD_simulation64": "200320→200320→colecta64102.40MZN;synthetic QA assumption,not real bulletin or fiscal annual confirmation",
"final_payable": null,
"final_recoverable": null,
"final_balance_scope": "L8"
},
"remaining_L6": "Representation/fiscal precision and remaining M20/M22 fields nextQA;partial dates/loss period sequence/short annualcaps/remaining depreciation and costs/annualFX and foreignbalances;conditions preserved in same matrix.",
"L6_complete": false,
"L7_L8_own_scopes": true,
"proof_files": {
"backup.txt": "b1b580ee73bdf6f2a2d3daaecf1b983e2084fea0a5e69e7fa3486d938cf7a87f",
"compact-dependencies.txt": "18375c30afc5fac24e8111779d455808fa363e02c5e38c8a92af6268dcbae7b4",
"installed-protected.txt": "39cd2444e61f5aca2ce41f2eba245defa246aacb908e066d43019e44c2e07e4e",
"installed-public-delta.json": "f35d40c06ff3a428c37e88b63dfa09ab745376c4c15747176382e9b364f80d5b",
"installed-public.txt": "7cd1a559a1c7d327a2d71846abdbe33cda63fdb99c0fdcf1584a75a5ff7c138a",
"integration.txt": "2526b168e5c6ef2515a9351dcdd56f1bbe9a119c073522376715cc815f7e673b",
"manifest-served.json": "f6121cade74d12c6de25630b23a1bd73f244a089c2649bf2c3aa76c68491431c",
"operational-delta.txt": "cadac629ef03871c14e3dd7186ce95379c526927bfefcae4466d6cb88897c1a4",
"preflight.txt": "dbdc76e4c45a45c127ce733def4260601074cee2bcf4cd6182dae06b3e7652a8",
"preparation.json": "dd755c3cad122e3730f57f8a94ee82dda74bfe49925cea95a518199437706e1a",
"progress.txt": "8ea7368149372f43ee10075198a3cc840394f866158a242353bdd7a3fd8e27a2",
"restore.txt": "5a7358ce267845262582c50261f85ab5d035bc16dc9573dd0554083f4457b324",
"schema-permissions-after.txt": "76b5a4d8af11e4898a205062766cfb7ab6ec0783200e77e60a1927aa1ca18597",
"schema-permissions-before.txt": "0ab7c964792acdd8917bce256c472e55e034b103500a58b49f020b5084823ed7",
"status-final.txt": "3b882f9da83f52e66876e3a2456d50e0454d44668e168e9967c290411af9b0e1"
}
}
@@ -0,0 +1,869 @@
{
"status": "short_period_and_foreign_currency_plan_QA_prepared_not_installed",
"installed_baseline": "e9fe102259c183a9d9bf7e39f246a8c3860839c6",
"branch": "codex/irpc-l6-periods-fx-qa-20261026",
"version": "IRPC-normal-adjustments/8",
"cases_recovered": {
"short": {
"accountingProfit": {
"numerator": "3120",
"denominator": "1"
},
"taxableProfit": {
"numerator": "3130",
"denominator": "1"
},
"taxableBase": {
"numerator": "3130",
"denominator": "1"
},
"colecta": {
"numerator": "5008",
"denominator": "5"
},
"period": {
"version": 1,
"kind": "start",
"from": "2026-07-01",
"to": "2026-12-31",
"planStart": "2026-01-01",
"reference": "QA início documentado1Julho;correspondência completa dos meses7–12 ao período do sujeito",
"conversionReference": "",
"mznMapsReference": "QA activo/quotas/juros e demais mapas reconciliados explicitamente emMZN no período",
"months": []
},
"pending": []
},
"fx": {
"accountingProfit": {
"numerator": "199680",
"denominator": "1"
},
"taxableProfit": {
"numerator": "200320",
"denominator": "1"
},
"taxableBase": {
"numerator": "200320",
"denominator": "1"
},
"colecta": {
"numerator": "320512",
"denominator": "5"
},
"period": {
"version": 1,
"kind": "start",
"from": "2026-07-01",
"to": "2026-12-31",
"planStart": "2026-01-01",
"reference": "QA início documentado1Julho;correspondência completa dos meses7–12 ao período do sujeito",
"conversionReference": "QA pressuposto de simulação64MZN/USD aplicado aos meses seleccionados;sem regra fiscal anual confirmada",
"mznMapsReference": "QA activo/quotas/juros e demais mapas reconciliados explicitamente emMZN no período",
"months": [
{
"period": 7,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.920Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
},
{
"period": 8,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.920Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
},
{
"period": 9,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.920Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
},
{
"period": 10,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.920Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
},
{
"period": 11,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.920Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
},
{
"period": 12,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.920Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
}
]
},
"pending": []
},
"missing": {
"accountingProfit": null,
"taxableProfit": null,
"taxableBase": null,
"colecta": null,
"period": {
"version": 1,
"kind": "start",
"from": "2026-07-01",
"to": "2026-12-31",
"planStart": "2026-01-01",
"reference": "QA início documentado1Julho;correspondência completa dos meses7–12 ao período do sujeito",
"conversionReference": "QA pressuposto de simulação64MZN/USD aplicado aos meses seleccionados;sem regra fiscal anual confirmada",
"mznMapsReference": "QA activo/quotas/juros e demais mapas reconciliados explicitamente emMZN no período",
"months": [
{
"period": 7,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.924Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
},
{
"period": 8,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.924Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
},
{
"period": 9,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.924Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
},
{
"period": 10,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.924Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
},
{
"period": 11,
"currency": "USD",
"fxSelection": {
"nature": "commercial",
"submissionDate": "2026-10-26",
"bulletinDate": "2026-10-26",
"bulletinRef": "QA pressuposto sintético64; não boletim real",
"source": "https://www.bancomoc.mz/",
"sourceCurrency": "USD",
"direction": "mzn_per_unit",
"bulletinPerspective": "",
"relation": "",
"buy": "",
"sell": "",
"mean": "64",
"mode": "general",
"exceptionRef": "",
"exceptionScope": "",
"exceptionDate": "",
"exceptionRate": "",
"applied": {
"column": "mean",
"rate": "64",
"date": "2026-10-26",
"source": "QA pressuposto sintético64; não boletim real;https://www.bancomoc.mz/;perspectiva:média de referênciaBM;natureza:commercial;relação:não aplicável à média;Orientação operacional expressa da Tempo,25/10/2026:compra de moeda→taxa de compra;venda→taxa de venda;operações comerciais→taxa média de referência do Banco de Moçambique na data de submissão indicada. Interpretar compra/venda pela perspectiva do boletim. Excepções fiscais específicas conservam disposição,data,taxa e âmbito;sem recálculo automático dos históricos.",
"selectedAt": "2026-10-26T07:51:24.924Z",
"selectionKey": "{\"nature\":\"commercial\",\"submissionDate\":\"2026-10-26\",\"bulletinDate\":\"2026-10-26\",\"bulletinRef\":\"QA pressuposto sintético64; não boletim real\",\"source\":\"https://www.bancomoc.mz/\",\"sourceCurrency\":\"USD\",\"direction\":\"mzn_per_unit\",\"bulletinPerspective\":\"\",\"relation\":\"\",\"buy\":\"\",\"sell\":\"\",\"mean\":\"64\",\"mode\":\"general\",\"exceptionRef\":\"\",\"exceptionScope\":\"\",\"exceptionDate\":\"\",\"exceptionRate\":\"\"}"
}
}
}
]
},
"pending": [
"revenue/mês12: Error: Selecção cambial deste mês/moeda em falta;sem usar taxa de outro mês por defeito.",
"cost_of_sales/mês12: Error: Selecção cambial deste mês/moeda em falta;sem usar taxa de outro mês por defeito.",
"operating_expenses/mês12: Error: Selecção cambial deste mês/moeda em falta;sem usar taxa de outro mês por defeito.",
"personnel/mês12: Error: Selecção cambial deste mês/moeda em falta;sem usar taxa de outro mês por defeito.",
"depreciation/mês12: Error: Selecção cambial deste mês/moeda em falta;sem usar taxa de outro mês por defeito.",
"interest_expense/mês12: Error: Selecção cambial deste mês/moeda em falta;sem usar taxa de outro mês por defeito."
]
},
"loss": {
"accountingProfit": {
"numerator": "3120",
"denominator": "1"
},
"taxableProfit": {
"numerator": "3130",
"denominator": "1"
},
"taxableBase": null,
"colecta": null,
"period": {
"version": 1,
"kind": "start",
"from": "2026-07-01",
"to": "2026-12-31",
"planStart": "2026-01-01",
"reference": "QA início documentado1Julho;correspondência completa dos meses7–12 ao período do sujeito",
"conversionReference": "",
"mznMapsReference": "QA activo/quotas/juros e demais mapas reconciliados explicitamente emMZN no período",
"months": []
},
"pending": []
}
},
"verification": {
"frontend_tests": 13,
"API_tests": 1,
"API_assertions": 58,
"database": "127.0.0.1:55441/simulator_fiscal_delta_20261021_test;DatabaseTransactions rollback",
"routes_actions": "generated by guarded existing procedure",
"typescript": "passed",
"build": "passed",
"UI": "actual component;dates/FX edit+confirmation;originals/assumptions;save/recovery/export;missingdata",
"accepted_proofs": "reused"
},
"runtime_delta": [
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "557714bb3af75080e443ae67b11a66d9feb49d9a4b269065769b128a6d712837"
},
{
"path": "resources/js/components/simulation-irpc-period-fx.tsx",
"sha256_LF": "4b5f718b5ef415ecf5f96dabb0e3806254558c20905de6478e10dacf67569c49"
},
{
"path": "resources/js/components/simulation-irpc-schedules.tsx",
"sha256_LF": "3768c316d5887d337eb3647671863c9464f961d1df4703403e7d57e5641273ed"
},
{
"path": "resources/js/lib/irpc-normal-assessment.ts",
"sha256_LF": "a9b3ced852e37e3e087ce5dab1add4ec0737145ce19f61857a54d5d3d24a6f8c"
},
{
"path": "resources/js/lib/irpc-normal-base.ts",
"sha256_LF": "22019d678f6eb16fead2207dc3d3fa9fd63413c6254633c1ffd4f1c0320344ac"
},
{
"path": "resources/js/lib/irpc-normal-costs.ts",
"sha256_LF": "471457692a2a2f70a1bd1c7abb38d3ce42f07b62a63e5a4ab985ad1bbd068b46"
},
{
"path": "resources/js/lib/irpc-normal-depreciation.ts",
"sha256_LF": "1dad3053157aeac44f6d3bd58885cfc47a73c19d2808284c16931679dfe4291b"
},
{
"path": "resources/js/lib/irpc-normal-period-fx.ts",
"sha256_LF": "a2e7b066623eae17f0d8185d065d0adf5d3a485f780f8b09118a664dc4ba0531"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "e4de2fe0421e489bf555885b9cbb459c00ee77803ea9b6e5af45179bd6bb4f21"
}
],
"protected_runtime": [
{
"path": "resources/js/components/simulation-irpc-depreciation.tsx",
"sha256_LF": "1f9918bfb435bb5b7c0ddd2fafd7bace2a02514c6ece04b93f15975e494a5f53"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256_LF": "909e129a0245e6bf098317485b886a2d19e02c64bbfd9c6f718e98ec6b935b8d"
},
{
"path": "resources/js/lib/irpc-normal-schedules.ts",
"sha256_LF": "edfb6fd338411fa8f87a6bdf9a9d4fd5c6dc2fad9d2eb3d32f2640e2951cbbe9"
},
{
"path": "resources/js/components/simulation-irpc-costs.tsx",
"sha256_LF": "c4156916835daf0f33addf89dfedd40c31b8dc3297112cd98beac33422af274d"
},
{
"path": "resources/js/lib/irpc-normal-forms.ts",
"sha256_LF": "4e986addb9f2d74e7a80345f8f1e4d8e0b2f562c867fa6eee84880d9f72a3649"
},
{
"path": "resources/js/components/simulation-irpc-taxable-base.tsx",
"sha256_LF": "e4fe9f66d35d24aa68fd87de6a5a6a0e901706b270c18962fd0c7ab00f9abd93"
},
{
"path": "resources/js/components/simulation-irpc-assessment.tsx",
"sha256_LF": "7174cc0160005a0c332ea40f02ba8a6d57985081b5ab45177ccd6e721bceea54"
},
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256_LF": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256_LF": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256_LF": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256_LF": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256_LF": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256_LF": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256_LF": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256_LF": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256_LF": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256_LF": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256_LF": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256_LF": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256_LF": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256_LF": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256_LF": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256_LF": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256_LF": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256_LF": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256_LF": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256_LF": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256_LF": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256_LF": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256_LF": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256_LF": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256_LF": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256_LF": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256_LF": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256_LF": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
{
"path": "resources/js/lib/financial-fiscal-bridge.ts",
"sha256_LF": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256_LF": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256_LF": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256_LF": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
}
],
"originals_preserved": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"source_evidence": {
"CIRPC": "Lei34/2007 PDF4 art7(4)/(7),PDF12 art41(5);original preserved",
"decree72_reused_sha256": "922ef67cb0c1111405c3c0a092d8c302a74fba8a34d627b6e9e13223612e0659",
"visual_pages": [
"cirpc-page4.png",
"cirpc-page12.png",
"decreto72-page3.png"
]
},
"installed7_fixture_sha256": "d58beac3cf7db665a632f516a736f754a5874f82585291dfbc5fa6bcda654d0d",
"history_versions1_to7": "unchanged;optional8;source plan not rewritten",
"FX_engine": "Existing selectFx/convertIrpcAmount/convertCents/direction/evidence/link unchanged;monthly assumptions explicit;no fiscal annual rule asserted",
"FX_rate64": "synthetic QA assumption,not real BM bulletin",
"schema_API_config_permissions_dependencies_changed": false,
"active_data_changed": false,
"L6_complete": false,
"L7_L8_own_scopes": true,
"remaining_reference": "Same matrix section26/10 períodos curtos e planos noutra moeda;concrete conditions per case",
"proof_sha256": {
"api.txt": "e2c50de5a45a76cdd596d4093974b88c449d23ba8011edf5f8a6325d2cf01d07",
"build-exit.txt": "13bf7b3039c63bf5a50491fa3cfd8eb4e699d1ba1436315aef9cbe5711530354",
"build.txt": "9b167ca7bcd724a65f6a4030a46ce9e81accaad5a2e80160b623ca3807400bc7",
"cirpc-page12.png": "12bb97ef4964b69816c30894bca201cedf2dcbadb29b3be9e867f2325e575abd",
"cirpc-page4.png": "3f6fdfd75d4fef4d07f461969675118f5f000c33ab593fcb6e0ee0fc93f56737",
"cirpc.txt": "c3ba3b845fcb12c25bc28b08485f3e5d70034895ece4ff60cf640fd0be796f9a",
"decreto-72-2013.pdf": "922ef67cb0c1111405c3c0a092d8c302a74fba8a34d627b6e9e13223612e0659",
"decreto72-page3.png": "4a150dd00dc7c7d4602c231bb42ebea5d7505917f1e21781c2d967cf5da8e327",
"dossier-fx.json": "5d1e429a48e8fd6c53a9116b3176641146e2aa6b68c888558ac6c4ff0950138c",
"dossier-loss.json": "862ee41f5b38546255335ab569039e52388d64f7bf30f38c3033f6f583e04d7c",
"dossier-missing.json": "514c2386e8e1cd687545c880fd5e66a0099c851433c0c8f337439a69e56db5b1",
"dossier-short.json": "cdab2ed8019f46f132f600c6b301d99ad44e8027926117abf3e57eb6c6000071",
"dossier.mjs": "cd967cfdba196bf0b7c691fe418f38dd39232030c6e601c22f8e25bd27e93d46",
"download.html": "95f59ff469af21bc2a41225358769bf99f25cf056479ff9a9c3d1dad4cb5f521",
"frontend.txt": "d9c7e51b63e020bf35d2a4a3aa22f29ca71d003e4bcf22b111e90173e442745b",
"fx.html": "5bae85164ca7cec78d76fc4c72c3c33cdaca70c63c42929c8e037ab7e91ba93f",
"fx.json": "e92ed4b718eef390aef573728a459679fdd3130bdf923db4cfd8f7a560958fbf",
"index.html": "09941968500d2910121bdcb0029e326fc6d44bb025b01766654289a28caa62fa",
"loss.html": "b672fd43361efcc81c4da4f83b7eba12dd9bd7799de0b463f248928065a4de97",
"loss.json": "07e56fb88034d377ca9bc2b098b9a4a266058a46aeb7b127a99b3c539bceec1b",
"missing.html": "ed41bf1b5ffab532a59b8e07d8a3700bd62576bc15c9256750c84a371a2cbc8a",
"missing.json": "5022f8eddd7f09b9a10a837f0e407e7db3619e27302e19f367923a956ebe47a6",
"qa.tsx": "c7c06f793e4a5aa3df70f36ec6681a6399b6016f27168d18917be2f22dffdbaf",
"recovered-fx.html": "5bae85164ca7cec78d76fc4c72c3c33cdaca70c63c42929c8e037ab7e91ba93f",
"recovered-fx.json": "2c7d1e8858af254930bff8a420f3369475ebd335ca4251b4ddc691558ed1c9aa",
"recovered-loss.html": "b672fd43361efcc81c4da4f83b7eba12dd9bd7799de0b463f248928065a4de97",
"recovered-loss.json": "2618a36d92005ebf791c938687662789086d351606f95f62f4eb1133f4b029e2",
"recovered-missing.html": "ed41bf1b5ffab532a59b8e07d8a3700bd62576bc15c9256750c84a371a2cbc8a",
"recovered-missing.json": "094b1ee4822bdcee6ac8ce5dc9ea5cfc178bf555b15f31a6cd2a1c6becd759ae",
"recovered-short.html": "955f182b29c160774bacc8997477c2da44cd1fcc401d1ed1955fa62f9f94d743",
"recovered-short.json": "e4399308561d5f412c9bb803c83fd6e045d89d24986a4d6a8279c2977044bb96",
"short.html": "955f182b29c160774bacc8997477c2da44cd1fcc401d1ed1955fa62f9f94d743",
"short.json": "a6b0e4ea322353f84c0ba6ff09d6cf89ee270dbefb850f225c4f8fe4485f68fb",
"types.txt": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"ui-fx.png": "deaede13c0c4eb6cc74ce0a55fc9b7bc2948f52fe7863ffc53ab83ca42456587",
"ui-proof.json": "56b6005ea84dfd370ac55167a5f47d19bffcee8408982c2046cb1ad27ecc9f20",
"ui-short.png": "b716d583fc3ca286c2e19cbeefca018ec08e8b75e0e95499ff7d27ab06a843d6",
"ui.cjs": "1f5506f7865cdbfcfa8aea853be241bab849807e6d641f3c5596534727cb5938",
"ui.txt": "85e77d9f361edf72d68990272040cc9b6edab3cc0873f921b1d5e561dc0553af",
"vite.config.ts": "0351ec239d5a6ba429ee17b9aa68757e31f59902f8f88a522afdd56bd3b44879"
}
}
@@ -0,0 +1,599 @@
{
"status": "installed_joint_L6_through_scoped_simulated_taxable_profit",
"installed": {
"status": "installed",
"commit": "5e02c23af863485f6881e409c8704ec7e7573cc9",
"release": "/var/www/investmoz-homologacao/releases/5e02c23af863485f6881e409c8704ec7e7573cc9-e83fcca2",
"previous_release": "/var/www/investmoz-homologacao/releases/7a11c4ef8f06ef149eb0488be3cd0749dc609bd0-68c76bdc",
"database_migrations": 0,
"content_imports": 0
},
"previous_baseline": "7a11c4ef8f06ef149eb0488be3cd0749dc609bd0",
"backup": {
"stage": "/var/backups/investmoz-irpc-l6-profit-delivery-20261025/backup",
"created_at": "2026-10-25T19:38:10Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "5dfb2cd96d7c440e12ec860080660ee1e88f8704075f9814e3225421ab007c71",
"files_sha256": "117c6e457320c08b63cd69599f63c676f48ad8b90cac5d6091e9d748c8b8850c",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l5_restore_20261025",
"port": 55441,
"source_dump_sha256": "5dfb2cd96d7c440e12ec860080660ee1e88f8704075f9814e3225421ab007c71",
"active_database_writes": 0
},
"preservation": {
"previous_release_preserved": "/var/www/investmoz-homologacao/releases/7a11c4ef8f06ef149eb0488be3cd0749dc609bd0-68c76bdc",
"installed": {
"status": "installed",
"commit": "5e02c23af863485f6881e409c8704ec7e7573cc9",
"release": "/var/www/investmoz-homologacao/releases/5e02c23af863485f6881e409c8704ec7e7573cc9-e83fcca2",
"previous_release": "/var/www/investmoz-homologacao/releases/7a11c4ef8f06ef149eb0488be3cd0749dc609bd0-68c76bdc",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 6,
"preserved_L3_ISPC_FX_runtime_files_verified": 33,
"documentary_files_verified": 31,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 106,
"checksum": "ed89c778b68dc12d870c1e1883be7e90"
},
"after": {
"rows": 106,
"checksum": "767a064eedb1c472eee28f9a0a59c907"
}
},
"sessions": {
"before": {
"rows": 25,
"checksum": "2821ae7c8c768e6f77acf2820265e3db"
},
"after": {
"rows": 26,
"checksum": "179f6c6d10853b16bb62ee44f1b7ca41"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"schema_permissions": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart value/expiry and request-throttle counter/timer pair;no deleted cache rows",
"sessions": "anonymous sessions created by exact delivery verification user-agent",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "8d6ea77eb4b34d86d207362d583cfa8bf2880b907becd9b00398964482c6b4bd",
"kind": "updated",
"fields": [
"expiration"
],
"key_pattern": "investemoz-cache-{hash}",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "2f251473865d14b953236ab95b1521764754d76abd79b58ca7d38c96dfe2fab1",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-{hash}:timer",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false
}
]
},
"sessions": {
"before_rows": 25,
"after_rows": 28,
"changes": [
{
"key_sha256": "7ed81a892bf75b5fda7e5071799a98d547242fcc64a5a29c0f169994073eb2ba",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "f72c5658d3a886e194bf35fa62f9c2c94c793790736bf253f9520936c75844f9",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "c28bc1e32e3d9c0eca1c9e1ad610e6b238ea101b609bff46a41a1f7a416bf83b",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"public_verification": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "5e02c23af863485f6881e409c8704ec7e7573cc9",
"branch": "main",
"built_at": "2026-10-25T19:41:48.731555+00:00",
"manifest_sha256": "316ad1f339fe14d64c8dce10ddf9c2ecc2080ce400fc9e87f9700de6e7333a59"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"Iniciar conferência até ao lucro tributável": [
"assets/services-cKAPGaXt.js"
],
"Suporte da completude do sujeito passivo no exercício": [
"assets/services-cKAPGaXt.js"
],
"Valor conhecido zero com suporte;distinto de ausência declarada.": [
"assets/project-dossier-B6lVijAe.js"
],
"Ausência declarada contradiz o montante conhecido da origem.": [
"assets/project-dossier-B6lVijAe.js"
],
"lucro tributável simulado:": [
"assets/project-dossier-B6lVijAe.js"
],
"Simulação pelos pressupostos introduzidos, sem confirmação fiscal dos juros.": [
"assets/services-cKAPGaXt.js"
],
"Códigos provisórios ou de simulação não são correspondências oficiais.": [
"assets/project-dossier-B6lVijAe.js"
],
"Calcular e guardar apuramento trimestral ISPC": [
"assets/services-cKAPGaXt.js"
],
"Calcular e guardar restituição E": [
"assets/services-cKAPGaXt.js"
],
"Reutilizar selecção cambial": [
"assets/services-cKAPGaXt.js"
]
},
"assets": [
{
"file": "assets/project-dossier-B6lVijAe.js",
"status": 200,
"sha256": "2882700d6723356a13be75f2287d9b71da3ba601ae95dee0e7c4b2cd9d31d690"
},
{
"file": "assets/simulation-form-BqVD91Ek.js",
"status": 200,
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
},
{
"file": "assets/services-cKAPGaXt.js",
"status": 200,
"sha256": "a62d8c8859d285db2fcddb89e93b358f6e8ceb2ee076d93c7ff1ea2934c5a8e1"
},
{
"file": "assets/project-dossier-document-bIxweCUO.js",
"status": 200,
"sha256": "88d93dd8177ed4b651b6f0b01ab494df38572bf136869a857581c8ab9b473dab"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-Q-Wi-bGe.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"runtime_delta": [
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "387292520216d3d37870e4080880e5ec026702977a2f4c556be6c82dd34a7fce"
},
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "d15a42d6bc295a4794b8427c668780335305d6091363002b570109aa0ac1aef9"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256_LF": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256_LF": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256_LF": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256_LF": "35dc586d9ab6c77405f3a46ed2ce3d9db74c54f338314d5e3c4959f0b6a55860"
}
],
"protected_runtime": [
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
{
"path": "resources/js/lib/financial-fiscal-bridge.ts",
"sha256": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33"
}
],
"originals": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"pipeline_checks": [
"OK (1 test, 3106 assertions)",
"built in 30.45s",
"OK (59 tests, 317 assertions)",
"# tests 888",
"# pass 888",
"# fail 0"
],
"accepted_proofs_reused": true,
"manually_repeated_accepted_functional_suites": false,
"limitations": "6480+220=6700MZN simulated taxable profit in demonstrated ordinary annual case;not taxable base or tax payable. Known amounts,declared absence and missing information distinct. L6partial. L5questions only limit dependent cases.",
"L6_complete": false,
"next": "QA taxable-base determination:documented ordinary own losses and delineated deductions;no unrestricted subtraction of benefit amounts",
"proof_files": {
"backup.txt": "fa06ec92a10c5918b4273d1f8714d5be4fddf9e18ddfe739e9154b2eb0fb96cf",
"compact-dependencies.txt": "afa3afafaf78314fff511b52a1fbc4a2f25a28fa549f9100400f2bc9a01e3579",
"installed-protected.txt": "8417903e69430856d316dbbc0874e355bbbb8cd8b6a55ab1f5f184c9b872829c",
"installed-public-delta.json": "633c50e0befc472d4504bf714f6bb9f6cd8b133c191040c360a06f30e1710648",
"installed-public.txt": "cec9d549fa288f970b85f7feeb131363b163884a5871dc3274a7e6b954f5fddd",
"integration.txt": "55ad35300fee092fff8bd9ab78e446342dd7735533fd534a5d4cf6bc771193bc",
"manifest-served.json": "316ad1f339fe14d64c8dce10ddf9c2ecc2080ce400fc9e87f9700de6e7333a59",
"operational-delta.txt": "28e02f58f87bb099ca2fddee7be182d736b4b85e9c1140e9a51482813929457d",
"preflight.txt": "484186b67968f20f506127460ebd6d0805a5077d7943f48e4b8cd7c9d2a257f5",
"preparation.json": "88c48f4a53fb1a59c47552b79dbb0c4c5db37cfde3b214f6eced213074d1bdf5",
"restore.txt": "f89d146854467f33fc5fa8643ad2b6155fd5e143c85daa856fdd6f0c7ec7bd72",
"schema-permissions-after.txt": "76b5a4d8af11e4898a205062766cfb7ab6ec0783200e77e60a1927aa1ca18597",
"schema-permissions-before.txt": "0ab7c964792acdd8917bce256c472e55e034b103500a58b49f020b5084823ed7",
"status1.txt": "eeddc365cc723cf3ad4783203517ef713eafcf4db6a70a78bec9960d3084d0eb",
"status2.txt": "da80cda2b3fead23b76868de2f1538dbb30abf5f72487aa12361e744ba7609c8",
"status3.txt": "bba01cbcdacefa72b7c6e8065158a488e8476de911d707cf5a2c1f50a842f2ba"
}
}
@@ -0,0 +1,687 @@
{
"status": "installed_L6_compatible_sets",
"installed": {
"status": "installed",
"commit": "a2de725901c308fb2ac2bc3d72181ab50ef46b7a",
"release": "/var/www/investmoz-homologacao/releases/a2de725901c308fb2ac2bc3d72181ab50ef46b7a-145e8f25",
"previous_release": "/var/www/investmoz-homologacao/releases/2f684e59846187f3fb8a338d9d6f6a08cadb4d0d-b46cd351",
"database_migrations": 0,
"content_imports": 0
},
"previous_baseline": "2f684e59846187f3fb8a338d9d6f6a08cadb4d0d",
"backup": {
"stage": "/var/backups/investmoz-irpc-l6-sets-delivery-20261025/backup",
"created_at": "2026-10-25T20:34:03Z",
"target": {
"database": "teste_investidor",
"port": 5432
},
"tables": 174,
"files_verified": 369,
"dump_sha256": "c30f1bb3558988a3e761d04465d0ed594280f10e36b866101b790cdeae60eacd",
"files_sha256": "e2a26a462dc115233aa8d1dd12aacc1511db0035de475f703074f28dc7da948a",
"restore_verified": false
},
"restore": {
"restore_verified": true,
"tables_verified": 174,
"container_network": "none",
"database": "irpc_l5_restore_20261025",
"port": 55441,
"source_dump_sha256": "c30f1bb3558988a3e761d04465d0ed594280f10e36b866101b790cdeae60eacd",
"active_database_writes": 0
},
"preservation": {
"previous_release_preserved": "/var/www/investmoz-homologacao/releases/2f684e59846187f3fb8a338d9d6f6a08cadb4d0d-b46cd351",
"installed": {
"status": "installed",
"commit": "a2de725901c308fb2ac2bc3d72181ab50ef46b7a",
"release": "/var/www/investmoz-homologacao/releases/a2de725901c308fb2ac2bc3d72181ab50ef46b7a-145e8f25",
"previous_release": "/var/www/investmoz-homologacao/releases/2f684e59846187f3fb8a338d9d6f6a08cadb4d0d-b46cd351",
"database_migrations": 0,
"content_imports": 0
},
"runtime_files_verified": 8,
"preserved_L3_ISPC_FX_runtime_files_verified": 38,
"documentary_files_verified": 31,
"persistent_files_and_env_verified": 369,
"tables_compared": 174,
"changed_tables": {
"cache": {
"before": {
"rows": 106,
"checksum": "edf84d90ae30f0a6a080a6c4929a4601"
},
"after": {
"rows": 106,
"checksum": "5226f818ead8e964983de752574a1647"
}
},
"sessions": {
"before": {
"rows": 31,
"checksum": "4bf9b80b2351e8896afacca734410295"
},
"after": {
"rows": 34,
"checksum": "79156a787aed15907ef066919ae90801"
}
}
},
"preserved_counts": {
"published_fiches": 29,
"relations": 28,
"geometries": 408
},
"migration_count": 0,
"content_imports": 0,
"comparison_role": "postgres_before_and_after;sameexportedsnapshotbaseline;noapplicationRLSvisibilityinference",
"writes_by_verification": 0
},
"schema_permissions": {
"schema_sha256": "5045b3e51d2185377aa3d9ac7fa07a44fad3ec620cdfa83ffe31c8884ee1601d",
"roles_grants_sha256": "1530c33cb016e67bfdc64891ddfce7f185b13b56b2cd87c012871a685e118109",
"filesystem_permissions": {
".env": {
"mode": 416,
"uid": 1001,
"gid": 33
},
"storage": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"storage/app": {
"mode": 1533,
"uid": 1001,
"gid": 33
},
"bootstrap/cache": {
"mode": 1528,
"uid": 1001,
"gid": 33
}
},
"comparison_identity": "postgres;catalogue read only;no passwords collected",
"unchanged": true
},
"operational_delta": {
"status": "operational_delta_reconciled",
"comparison_identity": "postgres before/after;isolated restored baseline;no RLS visibility inference",
"cache": "queue:restart value/expiry and request-throttle counter/timer pair;no deleted cache rows",
"sessions": "anonymous sessions created by exact delivery verification user-agent",
"delta": {
"cache": {
"before_rows": 106,
"after_rows": 106,
"changes": [
{
"key_sha256": "dbb99b7e17f5b4b9bb7a8bdf9350d9b2ae368aaa4bc44593a2522d87617d8461",
"kind": "updated",
"fields": [
"expiration"
],
"key_pattern": "investemoz-cache-{hash}",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "c1c7bc86ef3255c103a0be6aeb651b824eb07259e993cc5daf3665c1a6afff2d",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-{hash}:timer",
"is_queue_restart_key": false,
"expiration_unchanged": false,
"throttle_timer_pair": true
},
{
"key_sha256": "7f7dd83f47f5bf404d55e6e9f1367948721579970b195680645e356031a070ff",
"kind": "updated",
"fields": [
"value",
"expiration"
],
"key_pattern": "investemoz-cache-illuminate:queue:restart",
"is_queue_restart_key": true,
"expiration_unchanged": false,
"throttle_timer_pair": false
}
]
},
"sessions": {
"before_rows": 31,
"after_rows": 34,
"changes": [
{
"key_sha256": "8692330c25efe0f42e8cb66da1379be3235a7e91d340a89d49ace9679b19050d",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "5b2c1cf1904c5f25c8058da6406ffb0fcc80f0976903d312f0a1c76206073c73",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
},
{
"key_sha256": "cb0d56ccd4c384f2996530ddd041efda5890973ea90b6946fc383e2a72fcc4cd",
"kind": "added",
"fields": [
"id",
"ip_address",
"user_agent",
"payload",
"last_activity"
],
"anonymous_user": true,
"delivery_user_agent": true
}
]
}
},
"business_tables_to_confirm_separately": 172,
"active_data_writes_by_comparison": 0,
"restore_network": "none"
},
"public_verification": {
"status": "installed_delta_verified",
"served_revision": {
"commit": "a2de725901c308fb2ac2bc3d72181ab50ef46b7a",
"branch": "main",
"built_at": "2026-10-25T20:38:12.482895+00:00",
"manifest_sha256": "a450ea3ad0d3d13aa3942c90475c6a97eb081079e4de91d1a46cfee8cf28fa32"
},
"manifest_hash_matches": true,
"compiled_delta_markers": {
"Iniciar mapas complementares L6": [
"assets/services-Bav6HNRP.js"
],
"Acrescentar regra complementar": [
"assets/services-Bav6HNRP.js"
],
"Juros financeiros ordinários — artigo22c": [
"assets/services-Bav6HNRP.js"
],
"Amortizações fiscais — quotas constantes anuais": [
"assets/services-Bav6HNRP.js"
],
"Período anual e correspondência dos meses": [
"assets/services-Bav6HNRP.js"
],
"M20 — correspondência": [
"assets/project-dossier-CDrS2OdS.js"
],
"Saldo final — âmbito L8": [
"assets/project-dossier-CDrS2OdS.js"
],
"Calcular e guardar apuramento trimestral ISPC": [
"assets/services-Bav6HNRP.js"
],
"Calcular e guardar restituição E": [
"assets/services-Bav6HNRP.js"
],
"Reutilizar selecção cambial": [
"assets/services-Bav6HNRP.js"
]
},
"assets": [
{
"file": "assets/project-dossier-CDrS2OdS.js",
"status": 200,
"sha256": "995b6b17abf7a068faaf05f2eccb3a7ef882dff5758520b029251070165e167f"
},
{
"file": "assets/services-Bav6HNRP.js",
"status": 200,
"sha256": "9371a96868c7b2ef0af2332a3774dadb5ff45ad55ca2feb6833f9552605c2f01"
},
{
"file": "assets/project-dossier-document-B3HEGNVE.js",
"status": 200,
"sha256": "3331347876436578071dbb87033c060c0c8fe7eeeac9a0661240c6e6d2f87e71"
},
{
"file": "assets/simulation-form-BqVD91Ek.js",
"status": 200,
"sha256": "85cbd533c5bc92af5a448db71da006d4346d2d0adb09dde825db0aa19ad5048c"
}
],
"simulator_status": 200,
"simulator_entry": "assets/app-BNz3HFDA.js",
"existing_fiscal_availability": {
"data": {
"enabled": true,
"coverage_start": "2026-01-01",
"coverage_end": "2026-12-31",
"message": "IVA geral sobre base líquida disponível; enquadramento declarado."
}
},
"synthetic_private_writes": 0,
"method": "Read-only installedrevision/manifest/newcompiledcatalogueandreaders/simulatorentry;acceptedQAproofsreused"
},
"runtime_delta": [
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "e33b3839aac53a1b7ca2a76eda0ec4c54015a6d1c75e386aaeb5d342943f5965"
},
{
"path": "resources/js/components/simulation-irpc-schedules.tsx",
"sha256_LF": "eebd6d9e4100920a5ebf91b800537ffe301fd6a994b86a3b080d673f4a9c9a42"
},
{
"path": "resources/js/lib/irpc-normal-assessment.ts",
"sha256_LF": "1dc6adc0835af033ef296d12cdc1e9ef354b2f54cd36e2349b2df66e369c1ee3"
},
{
"path": "resources/js/lib/irpc-normal-base.ts",
"sha256_LF": "85fa1eb78ce2b8a144a9f0dcda93b542083a7ff119cbc43f4334c87284bfd312"
},
{
"path": "resources/js/lib/irpc-normal-forms.ts",
"sha256_LF": "4e986addb9f2d74e7a80345f8f1e4d8e0b2f562c867fa6eee84880d9f72a3649"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256_LF": "d5a2b52f7deb4cf35651188e04f103fcba950a007e3aa4de5ba7017e686614df"
},
{
"path": "resources/js/lib/irpc-normal-schedules.ts",
"sha256_LF": "b0045fd2c072998ebb290c2a8332c26d05a1f5f746b3beb1805508147497cac8"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "62d20bbcebb523f77fde950f623933a13f03283238665cf22fec9390f7ba9333"
}
],
"protected_runtime": [
{
"path": "resources/js/components/simulation-irpc-taxable-base.tsx",
"sha256": "e4fe9f66d35d24aa68fd87de6a5a6a0e901706b270c18962fd0c7ab00f9abd93"
},
{
"path": "resources/js/components/simulation-irpc-assessment.tsx",
"sha256": "7174cc0160005a0c332ea40f02ba8a6d57985081b5ab45177ccd6e721bceea54"
},
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
{
"path": "resources/js/lib/financial-fiscal-bridge.ts",
"sha256": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
}
],
"originals": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"pipeline_checks": [
"OK (1 test, 3106 assertions)",
"built in 31.41s",
"OK (59 tests, 317 assertions)",
"# tests 920",
"# pass 920",
"# fail 0"
],
"accepted_QA_proofs": {
"frontend_tests": 14,
"private_API_tests": 1,
"private_API_assertions": 78,
"database": "127.0.0.1:55441/simulator_fiscal_delta_20261021_test;DatabaseTransactions rollback",
"routes_actions_generated": true,
"typescript": "passed",
"build": "passed",
"actual_UI": "field editing;unsupported asset rate;missing interest;save/recovery;download;current loss",
"dossier": "from API-recovered calculated/missing/loss/EP JSON"
},
"accepted_proofs_reused": true,
"manually_repeated_accepted_suites": false,
"sequence": {
"taxable_profit": "6980MZN simulated",
"taxable_base": "4680MZN simulated",
"normal_colecta": "1497.60MZN simulated,32%",
"final_payable": null,
"final_recoverable": null,
"final_balance_scope": "L8"
},
"remaining_L6": [
{
"pending_case_or_mapping": "Custos com limites36(1)e/f/h/i/n, provisões28/29, obras plurianuais19 e componentes de exercícios anteriores18(2).",
"resolution_condition": "Implementar a regra de cada categoria a partir do diploma aplicável: parcela contabilizada, limite/base próprios, documentação e exercício de imputação; demonstrar o efeito com sinal nos totais. Nos exercícios anteriores, distinguir o que era imprevisível/manifestamente desconhecido no encerramento.",
"blocking_scope": "Só a categoria ou parcela ainda sem regra; os acréscimos36a/b/c/g, juros ordinários e periodização corrente/seguinte demonstrados permanecem utilizáveis. Eventual tributação autónoma pertence aL7."
},
{
"pending_case_or_mapping": "Amortizações além dos itensII/3/9 e9.1: restantes tabelas, quotas inferiores, duodécimos, quotas decrescentes, bens usados/reavaliados/intangíveis e recuperação de quotas anteriormente tributadas.",
"resolution_condition": "Corresponder categoria/tabela prevalecente, método, entrada em uso, vida útil, base depreciável e quotas contabilizadas/fiscais acumuladas; implementar o cálculo e a reconciliação que impeçam dupla dedução.",
"blocking_scope": "Só os activos/métodos afectados. Computadores25% e servidores20% no recorte anual constante e a perda corrente já demonstrada não são reabertos."
},
{
"pending_case_or_mapping": "Períodos curtos, transição/liquidação e reconciliação fiscal anual de plano noutra moeda.",
"resolution_condition": "Ligar os meses e factos de início/cessação/transição ao período fiscal; implementar os efeitos sobre quotas e contagem das perdas. Para outra moeda, identificar os eventos/datas e a regra de conversão anual aplicável, reutilizando o motor cambial aceite.",
"blocking_scope": "Só o período ou origem cambial sem reconciliação. Os períodos anuais emMZN e oEP com imputação documentada conservam o cálculo demonstrado."
},
{
"pending_case_or_mapping": "Representação fiscal de fracções de unidade/cêntimo.",
"resolution_condition": "Identificar a instrução de representação/arredondamento da edição/campo aplicável ou obter esclarecimento específico daAT; então implementar essa regra conservando o valor racional original. O exemplarM20A.1 pede meticais sem centavos, mas isso não determina sozinho como arredondar uma fracção.",
"blocking_scope": "Só a transcrição do valor não exactamente representável. Os cálculos racionais e os valores exactamente representáveis permanecem disponíveis; não é necessária nova validação genérica das fontes."
},
{
"pending_case_or_mapping": "M20A.1: discriminação de vendas/serviços, fornecimentos/outros gastos, imposto sobre o rendimento e resultado líquido; M22: campo200 e detalhe dos restantes ajustamentos.",
"resolution_condition": "Reutilizar a origem financeira, recolhendo apenas a classificação em falta e o imposto contabilizado; reconciliar resultado antes/depois de imposto e cada ajustamento com a edição aplicável. Não usar a colecta simulada como imposto contabilizado. Completar as correspondências por campo e demonstrar a recuperação/exportação.",
"blocking_scope": "Só os campos sem correspondência. M20A.1/Q4 contas6.1.1/6.2/6.5/6.9 e M22 campos259/260,269/270,276/277/278 e300 conservam a preparação parcial demonstrada."
},
{
"pending_case_or_mapping": "Transporte de resultado entre ediçõesM20/M22: XLSXM20A.1 remete para201/quadro8; PDFM22 inventariado usa200/quadro10.",
"resolution_condition": "Identificar a edição do formulário de destino e corresponder explicitamente o resultado líquido a essa edição; registar a remissão corrigida sem substituir os exemplares ou reutilizar fórmulas antigas por aproximação.",
"blocking_scope": "Só esse transporte entre edições; não bloqueia os cálculos independentes nem os outros campos já correspondidos."
}
],
"matrix_row": "AUD-SIM-INT02",
"L6_complete": false,
"L7_L8_own_scopes": true,
"documentary_divergence": "Only result transfer M20A.1 field201/Q8 versus PDFM22 field200/Q10;independent calculations and mapped fields remain available",
"L5_ten_questions": "unchanged;only dependent cases blocked;no new research",
"documentation_runtime_changed": false,
"proof_files": {
"backup.txt": "a591b64eafc2bfbf4c2581cbf7e622645434cd329ef76350cb93db7cab9a4924",
"compact-dependencies.txt": "d1c1681ce26172f3d54d4f800f928b0bca4fee69b436ed230208f03334194283",
"installed-protected.txt": "9fda494d5f02097704a534a9fad88246d3c2b9d1b195984b622a09fa0b18015c",
"installed-public-delta.json": "060517951fa315913d5848da634b5dd9c9cf4ea41e02c46f6d79cb5226c5e834",
"installed-public.txt": "b165c03e6f5745be112de5ed6e3f09de9bbdd66eee1b110ee6e0271e5a250a8d",
"integration.txt": "1f3bb46c6b39cc527fea30b81a80d815b81e73a776a512516add1c19be01276a",
"manifest-served.json": "a450ea3ad0d3d13aa3942c90475c6a97eb081079e4de91d1a46cfee8cf28fa32",
"operational-delta.txt": "02c8a942e58e243cfc131e08e8237c6e0495c0151330977f6aa738f903b60cc3",
"preflight.txt": "ffb60ef455b33ca6a2167b2c5f792fea591a6d22b37f46b7964c3fe0e20c371b",
"preparation.json": "61facd82de423031b21808a507fb1904fb8dc5f512314a02ea3563f864285d6d",
"progress.txt": "9347cbbd7a9373c97f6f1a53b8228ba4b7fdd6d270de35745ff7faf0861e5c7e",
"progress2.txt": "c3360e6f080fcf40778d997b7382e29f8b5f24013e89ba34c7b5a55fa821e315",
"remaining-section.md": "aceaf87dc9f82c0dbf6792d6d6918c188129369d29e8e9a52c729ce75534c74a",
"restore.txt": "e5cc45d4d6fd35d0424f3febe8c74ef089e88256fa6eb49de224a8e6a167b2fe",
"schema-permissions-after.txt": "76b5a4d8af11e4898a205062766cfb7ab6ec0783200e77e60a1927aa1ca18597",
"schema-permissions-before.txt": "0ab7c964792acdd8917bce256c472e55e034b103500a58b49f020b5084823ed7",
"status-final.txt": "7af3227a73d3d8eac0a8a5f116c48ca91c90d986f21ec96ecd192c7430667f9f",
"status1.txt": "4bd015e1aacfc764253af72a1cfa8e3f3f31614a92daac2c3d94779eb51dddf8",
"status2.txt": "52f274c01858b8570237f434ff86727720cfc7db0baf3a7d0c792abc19f853bd",
"status3.txt": "0c71c139c20da160dd49929a237e38887481a6ce6c24ea921df78023566cc85e",
"status4.txt": "0c71c139c20da160dd49929a237e38887481a6ce6c24ea921df78023566cc85e",
"status5.txt": "7af3227a73d3d8eac0a8a5f116c48ca91c90d986f21ec96ecd192c7430667f9f"
}
}
@@ -0,0 +1,385 @@
{
"status": "scoped_taxable_base_losses_deductions_QA_not_installed",
"installed_baseline": "5e02c23af863485f6881e409c8704ec7e7573cc9",
"branch": "codex/irpc-l6-taxable-base-qa-20261025",
"QA_workspace": "C:\\laragon\\www\\portal-investidor-irpc-l6-base-qa-20261025",
"scope": "2026 resident general regime,declarative method,ordinary annual own fiscal losses,same taxpayer,complete corrected balances. Explicit proposed utilisation within balance/profit;no FIFO or percentage cap assumed. No positive-benefit rule,transferred losses,special/short periods or negative current-result base implemented.",
"implemented": [
"Reuse calculated taxable profit,no re-entry of6700;optional reuse of existing same-opportunity MRFTA NUIT preserves deliberate edits",
"Loss ledger by origin year,NUIT,assessed/corrected fiscal amount,previous use and explicit proposed current use;source/reference and ordinary-period/general-activity/balance facts",
"Five subsequent ordinary fiscal years41(1),activity/object restriction41(7),specific indirect/partial-exempt/transparency/correction/short-period dependencies identified",
"Expired or changed-object exclusions visible;positive request against excluded loss is not silently ignored",
"Cap by available balance and total profit;no implicit allocation order;negative base prevented through explicit reconciliation",
"Known benefits zero,declared absence and missing information kept separate;positive benefit amount recorded but no arbitrary subtraction15(4)",
"No official loss balance consumption on calculation/save/repeat;source uses unchanged",
"Optional calculationversion3 preserves currentversion2 and histories1/2;changed input makes onlynewresult stale",
"PrivateAPI create/update/recovery,UI and HTML/dossier from recovered known/missing payloads"
],
"examples": {
"profit": "6700 MZN simulated taxable profit,not tax",
"loss2021": "assessed1000-prior200=available800;proposed800,lastordinaryyear2026,remaining0",
"loss2024": "assessed3000-prior500=available2500;proposed1500,lastordinaryyear2029,remaining1000",
"base": "6700-2300=4400 MZN simulated taxable base;tax payable indeterminate",
"supported_absence": "Losses and benefits absent with support -> base6700,not assumed before evidence",
"missing_benefit": "profit6700 and proposed eligible losses2300 retained;base/deductions indeterminate",
"known_positive_benefit": "known200 preserved,not subtracted without implemented rule",
"expired2020": "lastordinaryyear2025;explicitzero request -> no deduction2026",
"negative_current_profit": "kept signed;base indeterminate,no automatic zero or current-loss carryforward"
},
"verification": {
"frontend_new_tests": 10,
"private_API": "1test/42assertions,create/update If-Match/recovery,DatabaseTransactions rollback,isolated127.0.0.1:55441/simulator_fiscal_delta_20261021_test",
"typescript": "passed",
"Wayfinder": "existing guarded routes/actions procedure",
"QA_build": "passed exit0",
"UI": {
"profitReused": true,
"baseCalculated": true,
"taxPayableIndeterminate": true,
"localSaveRecovery": true,
"explicitLossAllocation": true,
"sourceBalancesNotConsumed": true,
"overuseRejected": true,
"download": true,
"missingBenefitIndeterminate": true,
"positiveBenefitPreservedNotSubtracted": true,
"privateApi": "IrpcNormalBaseDraftTest separate",
"errors": []
},
"dossier": "known and missing outputs from actual API recovery",
"accepted_proofs": "reused,no manual accepted suite repeats;version2 snapshot only read/roundtripped",
"legacy_fixture_sha256": "105857393035cb5e7c569dc9e6c7b91f51c335b9799fc148b1bfee57057f3138",
"protected_runtime": 37,
"originals": 31
},
"runtime_delta": [
{
"path": "resources/js/lib/irpc-normal-base.ts",
"sha256_LF": "ab7f7389bac23abd990d0d3a8d4c52b81f7b11066586d74b4254c6cc2c15392f"
},
{
"path": "resources/js/components/simulation-irpc-taxable-base.tsx",
"sha256_LF": "e4fe9f66d35d24aa68fd87de6a5a6a0e901706b270c18962fd0c7ab00f9abd93"
},
{
"path": "resources/js/lib/irpc-normal.ts",
"sha256_LF": "df3ac3ba0bd60a9687cc64bfa2d5766cc975d044b51901d96a815cc426255b5c"
},
{
"path": "resources/js/components/simulation-irpc-normal.tsx",
"sha256_LF": "0f9fe320814db4a5329688cedaf9a2e1388812c80bb49ade21601392abce1a28"
}
],
"protected_runtime": [
{
"path": "resources/js/components/acquisition-beverage-restitution.tsx",
"sha256_LF": "6f44897b8b12569314551df0022c26da57a165634087942a724293e66837558d"
},
{
"path": "resources/js/components/fiscal-calculation-gaps.tsx",
"sha256_LF": "1dab6ceb73756d4e023096b3b2ba767aaa843ff6cc69046ea630ab449a00b0dd"
},
{
"path": "resources/js/components/fiscal-l3-preparation.tsx",
"sha256_LF": "e84a7b1ccadaa1b5bd78d778a3287f96ccaf530855eef404786cd7aa3d321b73"
},
{
"path": "resources/js/components/simulation-acquisitions.tsx",
"sha256_LF": "c206d4cfe575d6ba007aa2b425b5f898efa97e4162b8710e358b6ecfd9458542"
},
{
"path": "resources/js/components/simulation-operations.tsx",
"sha256_LF": "a7e55972fa790063dcf11945055de2af46a77db9e509900af22ede7ec47bb4cf"
},
{
"path": "resources/js/lib/iva-acquisition-bc.ts",
"sha256_LF": "b0ef55e0917bdb79f14b53ba9e95d73c08153befeb7d4ce73f81e6fb13992225"
},
{
"path": "resources/js/lib/iva-beverage-allocation.ts",
"sha256_LF": "32968d198c7fe0c53ca89641c22d5749be6636be2c79127b867e4e3afd0dd40d"
},
{
"path": "resources/js/lib/iva-beverage-restitution.ts",
"sha256_LF": "5c650cbd9469d5f99001f56fc4ff99ac973eb368036d4e96c6d171f1b220bd9e"
},
{
"path": "resources/js/lib/iva-calculation-gaps.ts",
"sha256_LF": "2e7d84a0c196bd5b56fd67cc1a389d43d5041894184e675680a4de3cd10b31a2"
},
{
"path": "resources/js/lib/iva-operations.ts",
"sha256_LF": "ec37b949f1233c5f5c14a87450c421ed29fabf1ed5b73fb32564564a2bc31f54"
},
{
"path": "resources/js/lib/l3-form-preparation.ts",
"sha256_LF": "fc47f5fa5ec1420fbd847d0d081f00d99ebbb524164eef785b20877e0562f704"
},
{
"path": "resources/js/lib/ispc-residuals.ts",
"sha256_LF": "40d5751c06c7c155ab4b7a17ee2d1653da2fbbf075807fbb8561cdbe19820955"
},
{
"path": "resources/js/components/simulation-ispc-residuals.tsx",
"sha256_LF": "a9219d6f41ccbd0ce45659d4f6aa0fa1c169a685840f5cb1e18daeca377d5e18"
},
{
"path": "resources/js/lib/ispc-eligibility.ts",
"sha256_LF": "44675c5efacdc1ae19505667611ba3b522d3043cebacc8754597c3a68ca89d25"
},
{
"path": "resources/js/components/simulation-ispc-quarter.tsx",
"sha256_LF": "2c2555309b32d4261f14e7164f39314c9188129c2990357fc54090a2468dd2b4"
},
{
"path": "resources/js/components/simulation-ispc-withholding.tsx",
"sha256_LF": "e0445d015b72859e48726959aa52686f79b1cf5c2ade29751efa83257068b878"
},
{
"path": "resources/js/lib/ispc-quarter.ts",
"sha256_LF": "f66bd52e9cdfe1ddaa6b00a931465862b3d890b9be216b7a056740f027f24129"
},
{
"path": "resources/js/lib/ispc-withholding.ts",
"sha256_LF": "6c31b240299edd3262efa28f7f3d5aee21123f94e30ef4ab90e26c35777cb6e4"
},
{
"path": "resources/js/components/simulation-ispc-eligibility.tsx",
"sha256_LF": "f48dd4a8f87a994eda0447f81a463589905e5873b2e1044debac9d10825a880c"
},
{
"path": "resources/js/lib/iva-acquisitions.ts",
"sha256_LF": "cce283b1d0a07fb383fcb527225f4dd5bec829010a662cbaae1d60e595221977"
},
{
"path": "resources/js/lib/iva-modelo-a.ts",
"sha256_LF": "c641619a05613c1620385baad0e9ffbf810dd970aafb30e12b3a7f9a3bf11846"
},
{
"path": "resources/js/lib/iva-fx-selection.ts",
"sha256_LF": "9aa07ad443bc777b80510a3b5bd6aff9ddb9814d2450f3c690e531e74d71d998"
},
{
"path": "resources/js/components/simulation-fx-selection.tsx",
"sha256_LF": "39bb6d87d404745b0b66349bc11626545a3672ae27321ce9b4658416592059bf"
},
{
"path": "resources/js/lib/business-financial-plan.ts",
"sha256_LF": "c20274722d1ffcd0360f041a6cacb5d868fe0621cb27a1aca6e06826612c3ebb"
},
{
"path": "resources/js/lib/iva-currency-events.ts",
"sha256_LF": "cc9f2045d302d7987310da4006cc250fc5c99a27397918d166d649bfc32fab08"
},
{
"path": "resources/js/lib/irpc-fx.ts",
"sha256_LF": "5c4a7a477429f8d775acf6db3e117008468f5554e5731dec81f60fbb75e948fb"
},
{
"path": "resources/js/lib/irpc-withholdings.ts",
"sha256_LF": "8e5f3c035ce5e4d6c3fc82f933439ab580fa5519492f9c4d32cfb71b77b54803"
},
{
"path": "resources/js/components/simulation-irpc-withholdings.tsx",
"sha256_LF": "751af4fab346659bc5ccb08b8a2169769af7521ea0035050af32b41ea7f5aa76"
},
{
"path": "resources/js/lib/irpc-interest.ts",
"sha256_LF": "f8e6390b3b2c58c296f7e3fd14576e06ae248bc0cabce1a666b7094611f2a7dd"
},
{
"path": "resources/js/lib/irpc-mrfta.ts",
"sha256_LF": "76dcce8954f68b081d500be61de9c5b146a452a3eb578a0b78776ba9e1f8051c"
},
{
"path": "resources/js/lib/irpc-mrfta-cases.ts",
"sha256_LF": "4266746076ab3f70312fd042351e24dd2f136c4f3e8a277b57dd97849a9f1862"
},
{
"path": "resources/js/components/simulation-irpc-mrfta.tsx",
"sha256_LF": "913d1bb4ac0fc59763cf5d27bc637f6a713b2050c4463748db554af4be451538"
},
{
"path": "resources/js/lib/financial-fiscal-bridge.ts",
"sha256_LF": "5a30c501653b16b5fedcb12631ce81fcce4fe473aa542e94374986b3c50f2d33"
},
{
"path": "resources/js/components/simulation-form.tsx",
"sha256_LF": "85b024a7f45ceb52efd6ff1f21d0eab1fd8fcf1ab59e4b5302c08685235c472a"
},
{
"path": "resources/js/lib/project-dossier.ts",
"sha256_LF": "a0909bbfcdf7e8542b010faa104fcb918e86ae38ddf096082d4d5be98d31b2b9"
},
{
"path": "resources/js/lib/project-dossier-report.ts",
"sha256_LF": "5207a2ffeb208cd5ace6713038cee85208020ee618194dca7114e94fc3200b6c"
},
{
"path": "resources/js/lib/irpc-normal-profit.ts",
"sha256_LF": "35dc586d9ab6c77405f3a46ed2ce3d9db74c54f338314d5e3c4959f0b6a55860"
}
],
"originals_preserved": [
{
"path": "docs/investmoz/simulations/source-archive/AT-Comunicado-9-2026-ISPC.pdf",
"sha256": "106f8a9ce9255c03549c70bf07fe999d32e6e55302d009b509862aa74ccb4973"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-30-ISPC.pdf",
"sha256": "6802edd06b6ff638a0b851a3ec7ecf69af8f07840faa47446becad67d35d445c"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-Modelo-B-Geral.pdf",
"sha256": "bd977c7c59d4d98befd92e2c566b1bf168cb1343bb519f51b41a3807f431fc57"
},
{
"path": "docs/investmoz/simulations/source-archive/AT-MRFTA-19-39.pdf",
"sha256": "8ea62c53066b482f87078a7a7b1ecf15ca98a12a122e8d7abca63acfc993186b"
},
{
"path": "docs/investmoz/simulations/source-archive/BM-Mercado-Monetario-MAIBOR-20261025.html",
"sha256": "00e8a7e0d3a1db4ca3beb56d5361b2084a0f1684f3d40fc1c203702a2190e063"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-16-I-Serie-2008-04-16.pdf",
"sha256": "fc373ff5637edf75ec6a9595dec8763a8503d4ee786e3b7d8f1c742eae9d80ee"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-248-I-Suplemento-1-2025.pdf",
"sha256": "ccf2a8deeca820f2dd076b4b2141b1efe3f6a806568c3a587ca59a8e92f4c251"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-89-I-Serie-2017-06-08.pdf",
"sha256": "11f0cab15eb6e51010952203ffa24fdc533a24fd642e19525fe4f46b17a1f5e5"
},
{
"path": "docs/investmoz/simulations/source-archive/BR-95-I-Suplemento-2025-05-21.pdf",
"sha256": "e0e682e2c027c3cd9c1d46a73a3f48bc5f6bdbf05667fd97314d7a3f6a456358"
},
{
"path": "docs/investmoz/simulations/source-archive/BR252-I-Serie-2022-Lei20-PESOE.pdf",
"sha256": "1159fd3ce1ba5581671796d083534da48bd3c5578298819e896f1c2a8026318d"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-22-2021-BR70.pdf",
"sha256": "a8fac38dcfe08f9c7a8e46254cff10e1ec82fc4f7a8d88ad6e4fe7d91ffc21a5"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-27-2026-BR123.pdf",
"sha256": "26249c3fa58f149c81de36e99d1aac2819a4771379d9e8833159660dabf539bb"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-29-1998-BR22-5-suplemento.pdf",
"sha256": "6242cbe675faadf085f43f95ec8c7e8868aafe67c3b2ab2bb010992288f954f8"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-3-2011-BR-11-I-mineiros.pdf",
"sha256": "5bca1133666ba9c69870b89823420175b7b5b8d0eccb667ecdf5c29716f3b6be"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-37-2023-BR124.pdf",
"sha256": "7e680b191481faa0e2e9057fa5053587eb2a29d1d8c819e0eb9f02814255a04c"
},
{
"path": "docs/investmoz/simulations/source-archive/Decreto-9-2008-BR16.pdf",
"sha256": "96fccdecbfdc11c9eafb90fbc6c7bc259f88bbd4c7507d1ac3af1fa03f960697"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-13-2016-CIVA-BR-156-10-suplemento.pdf",
"sha256": "b90dc7c14ecea2e378c4a62e8e5a47d54a5644c457baeb8b8053b92fd2a5710b"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-14-1992-BR42.pdf",
"sha256": "089fff7423e99a70a230a73ca379e4ea3a91d124703f91016e57ff82794b9e56"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-BR251-exemplar-MCNet5.pdf",
"sha256": "14eb34f0af91a8f5cb1770c7b52d6ff839c6818302d1ed96d79afbfb9fe999d4"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-17-2022-IPP-BR250-Parlamento.pdf",
"sha256": "978cd22403ffd336a631704ecd7a5bbd814a427c815b9acdaca5515591dd9e2a"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2013-BR76.pdf",
"sha256": "bba96d645cc935ffc3d1a79b9f0f73ac1c693d6459c2ad41f56cd2841accae76"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-19-2017-IRPS-BR-OCAM.pdf",
"sha256": "c3a0186cb9ad090d7a9533006295dc9bb6a62ad0d6150173cbd49dba4ee4b52d"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-2-2011-BR-1-4-suplemento-MCNet.pdf",
"sha256": "a7543a68cc3287a46a83c39a04821b40f649dd06c4e9b5dc51ff0b47fba08899"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-20-2009-BR36-AT-exemplar19.pdf",
"sha256": "fc1c8144db42960cbf73e717e095896f511ece0f907f58f78819b27d6917a7ee"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-22-2022-IVA-republicada-BR-250-2-suplemento.pdf",
"sha256": "ea1b0dc6f5cf6e595f6d9a19e7042f398999e0087caef1785f6e8fac571b5f53"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-34-2007-BR52.pdf",
"sha256": "cdbef875ad7ccc1517b12faf5de0e893a70ed2ed81e33913cd6dc4a674474e6e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-1994-BR37-3-suplemento.pdf",
"sha256": "210df9db8980d0a5690cd187a6eeec7e37a900d743e39062c16f4e0d12215c7e"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-4-2012-BR3.pdf",
"sha256": "b8845cef41dcbd9ba50c43dbfa743a56030dd3d348242a107e1ae30279eec121"
},
{
"path": "docs/investmoz/simulations/source-archive/Lei-7-1991-Partidos-IFES.pdf",
"sha256": "6b783a0bb3330688ef10660a58060d9724aa2da6a873d234fe902f0eaaeda42d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-CDT-1992.pdf",
"sha256": "d504e1024b28aee5c6acf4592acb96ec9c915a8414f67a61ab6984d6acf9df9d"
},
{
"path": "docs/investmoz/simulations/source-archive/PT-MZ-Protocolo-2009.pdf",
"sha256": "f353773dcf41f09f4daa6cf5ba5a5f7994f3e02615867c2dcffc61c3d901bf9b"
}
],
"new_sources": 0,
"source_review": "Accepted CIRPC Lei34/2007PDF5/p768(59):15(1)a/15(2-4),PDF12/p768(66):41(1-7),visually read. Accepted amendment lists reused:Lei20/2009 adds41-A(transfer,not applied),4/2012,19/2013,20/2022,12/2025 do not change15/41 within this scope. No new L5 research. No indirect method,partial-exempt ringfencing,transparency,transfer41-A,short periods or positive benefit rule inferred.",
"proof_sha256": {
"api.txt": "7e78ac0a8460d463505b54ed510287b70030ddf65c115deeec8ab322de53d37b",
"build-exit.txt": "5feceb66ffc86f38d952786c6d696c79c2dbc239dd4e91b46729d73a27fb57e9",
"build.txt": "b0ed7b4b3220a4dd33918c1297c0bda4ee219f205a63758ddd2c03d2e5753c00",
"calculated.json": "ee1b1b49e0686bed3f8171beaacf9f57327850bcd36c96e1cc2ba5f1064ff585",
"CIRPC-page12.png": "ac413f5d39bf353fcaa4adb5bc630f328f34c3cd9ebeef47e73bd08d99d28bb9",
"CIRPC-page5.png": "af1209cfc8c5820ec7d46652bc9a1d30ca30e21e6e7c7e3bf49e52cfb46812a7",
"dossier-calculated.json": "a0f4223464e40e85810ddbd868fd9ff7fc8d5c0b2071380389805ed6b80f5bc3",
"dossier-missing.json": "551a9231f7ab48405ff45117f4667b0ee8431726b5136a96d4bb77e2095a99ee",
"download.html": "db4b0f82ad31825c016d1f3cf70f8b8da3484d26408d0ae043b2b2049949472c",
"frontend.txt": "3be8a5ea29b874a5c3b768c328035ad9c793fdec3d6e51337715ad88f82318bb",
"index.html": "9af7b69c19ca2fb213988ace8eb927008cb0bea73e267f16dee363fcdbcb0f12",
"missing.json": "3607986c3ec80b800effe2a48bd623c94cf2039b84a645007236e5528286290c",
"preparation.html": "1f970ab58e6f71a3ee80e93331496104745a19c570b4273eff5978e7a312f7ac",
"recovered-calculated.html": "1f970ab58e6f71a3ee80e93331496104745a19c570b4273eff5978e7a312f7ac",
"recovered-calculated.json": "9bdd82a0a1b1a8b0a3fd18c0a54ef2ffa7233cf10f012d16c830e795b85129ea",
"recovered-missing.html": "29a11c4e9af4f35f36d032244fbcfaa843cc0d90f1051cd80fdda0b0e4ac7311",
"recovered-missing.json": "994f44a62032acf7c1b2805c312b90f0665176d3438b0cf10da9af06229cd809",
"types.txt": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"ui-base.png": "d53f7e096abedf6dc1361aa9be303c7c2afb5604ab02e9d704d8ffe52f6f3e3d",
"ui-pending.png": "d900c53f829675b5f4ab500ed36c85dd9a71605e6e4f727d5abc9193511d2039",
"ui-proof.json": "85d4bbade8f97b676b7ecade5b283df853b93c74eef4314cb27d39b1f9fad651",
"ui.txt": "13c8982f58552f00e26ef4eda1d83a20489d57ba51dcf368455a74500241e660"
},
"not_claimed": [
"tax collection,tax payable,annual withholding credits,M20/M22/submission",
"Official consumption of loss ledger or complete fiscal regime",
"Positive benefits automatically deductible from typed amount/reference",
"Full L6 completion or resolution of L5 ten questions"
],
"active_changes": false,
"schema_API_config_permissions_dependencies_delta": false,
"L6_complete": false,
"L5_questions": "Only actually dependent cases limited;existing ten questions unchanged"
}

Some files were not shown because too many files have changed in this diff Show More